Skip to content
autoantwort edited this page May 23, 2024 · 13 revisions

Welcome to the CPS wiki!

Hi! Thanks for your interest into the Common Package Specification (CPS). These documents are intended to supplement the specification itself with community-editable tutorials, guides, and other explanations.

FAQ

What is CPS?

CPS is a schema for JSON files. Those files describe libraries as built and installed on a filesystem. Currently CPS is targeting C, C++, and Fortran projects, but the project will be extensible to support other languages. The main purpose of CPS is to provide interoperability mechanisms across various tools, with interoperation across build systems as an initial target.

What is a library?

One of the challenges in modern development for natively compiled libraries is that there is no standard or de facto definition for what a library is, exactly. To CPS, a library has a definition -- an entry in a CPS file. All of the following are describable with CPS JSON files:

  • static libraries
  • shared libraries
  • header-only libraries
  • deployed object files
  • collections of flags modeled as a library

What tools use CPS?

No tools currently use CPS, though there is active research to add CPS support to the CMake build system. There is also interest and collaboration with maintainers of popular C++ ecosystems. Also, an open source project called cps-config has been launched to assist in interacting with installed CPS files from the command line and potentially build systems. Contributors welcome!

How does CPS relate to the ISO C++ Standard?

It is premature to standardize CPS right now, but it is a goal of the project to propose an addition to a to-be-created ISO C++ Ecosystem Standard as soon as there is sufficient adoption experience to justify that step.

How would I use CPS?

Generally, it is not expected that end users would interact with CPS files directly. Instead, it will be a way for various tools to communicate with one another about what a library is and how to use it.

End user exposure to CPS files would probably be limited to troubleshooting workflows when tools are not interoperating as expected. For instance, looking for inaccurate fields or sharing contents of CPS files in bug reports.

How-To Guides

Specific steps to solve specific problems!

Cookbook

How do I write a CPS file for a given type of project?

Single Static Library

In a file called fmt.cps:

{
  "cps_version": "0.11.0",
  "name": "fmt",
  "description": "An open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
  "license": "MIT",
  "version": "10.2.1",
  "default_components": [ "fmt" ],
  "components": {
    "fmt": {
      "type": "archive",
      "definitions": {"*": {"FMT_HEADER_ONLY": "0"}},
      "requires": [],
      "includes": ["@prefix@/include"],
      "location": "@prefix@/lib64/libfmt.a"
    }
  }
}

Note:

  • The library would be of the archive type.
  • The location is the location of the library binary file.
  • The "header-only" preprocessor definition is explicitly disabled.

Single Shared Library

In a file called fmt.cps:

{
  "cps_version": "0.11.0",
  "name": "fmt",
  "description": "An open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
  "license": "MIT",
  "version": "10.2.1",
  "default_components": [ "fmt" ],
  "components": {
    "fmt": {
      "type": "dylib",
      "definitions": {"*": {"FMT_HEADER_ONLY": "0"}},
      "requires": [],
      "includes": ["@prefix@/include"],
      "location": "@prefix@/lib64/libfmt.so"
    }
  }
}

Note:

  • The library would be of the dylib type.
  • The location is the location of the library to be linked in downstream projects.
  • The "header-only" preprocessor definition is explicitly disabled.
  • TODO: What about RUNPATH?

Single Header-Only Library

In a file called fmt.cps:

{
  "cps_version": "0.11.0",
  "name": "fmt",
  "description": "An open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
  "license": "MIT",
  "version": "10.2.1",
  "default_components": [ "fmt" ],
  "components": {
    "fmt": {
      "type": "interface",
      "definitions": {"*": {"FMT_HEADER_ONLY": "1"}},
      "requires": [],
      "includes": ["@prefix@/include"],
    }
  }
}

Note:

  • The library would be of the interface type.
  • For this library, a different preprocessor definition for FMT_HEADER_ONLY is needed.
  • There is no location field provided.

Library Providing Both Shared and Static Options

In a file called fmt.cps:

{
  "cps_version": "0.11.0",
  "name": "fmt",
  "description": "An open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams.",
  "license": "MIT",
  "version": "10.2.1",
  "default_components": [ ":shared" ],
  "components": {
    "shared": {
      "type": "dylib",
      "definitions": {"*": {"FMT_HEADER_ONLY": "0"}},
      "requires": [],
      "includes": "@prefix@/include",
      "location": "@prefix@/lib64/libfmt.so"
    },
    "static": {
      "type": "archive",
      "definitions": {"*": {"FMT_HEADER_ONLY": "0"}},
      "requires": [],
      "includes": "@prefix@/include",
      "location": "@prefix@/lib64/libfmt.a"
    }
  }
}

Note:

  • There are two "components", one for the static version of the library and one for the shared version.
  • The shared version of the library is the default version in this arrangement, but it's possible to specify otherwise.
  • See the simple static and shared examples for notes on specific fields.
  • TODO: What about RUNPATH?
  • TODO: Do the static and shared versions conflict?

Explanations

Concepts, context, and other ways to grow understanding.

Motivation

Why is CPS being developed?

See the CppCon 2023 talk called Libraries: A First Step Toward Standard C++ Dependency Management by Bill Hoffman and Bret Brown to understand the motivation and goals for CPS.

In short, CPS attempts to be a metadata file format to allow better interoperability across the build systems of different projects. It's important to have specific interfaces and protocols for how projects cooperate because natively compiled languages do have nuanced requirements regarding how they are linked together. Certain decisions, as detailed as specific flags used to compile specific files, need to be communicated and followed consistently for correct and productive software development in natively compiled languages. Implications of these difficulties have been far-reaching and have held back innovation and progress in tooling, dependency management, and even a development of a robust library ecosystem.

Historically, dependency management for natively compiled languages has been painstaking and bug-prone, but CPS hopes to provide a path forward.

Authoring CPS

What do I need to know about writing CPS files?

For Project Maintainers

Mostly, you won't write CPS files. It is expected that build systems will be able to be much more precise, consistent, and efficient about providing this metadata. It is recommended that projects work with the maintainers of their build systems to provide seamless CPS support.

When CPS is fully adopted, it should mostly be use to allow various tools talk about dependency graphs with one another, especially different build environments and build systems. This will be analogous to how debug information is used to allow compilers and debuggers to share information about compiled binaries. Most users do not need to understand how this debug information is encoded, though it is helpful to know it exists and how to ensure it is provided as appropriate.

That being said, there will be situations where project maintainers may need to author a CPS file, so further documentation is available here to help people learn about constructing CPS files in more detail.

For Packagers and Build System Maintainers

If you're ensuring your packages have good CPS files or implementing CPS support in a build system, you will need to understand CPS files in more detail.

Most CPS files will be simple. The first examples in the CPS Cookbook should be the most common examples, especially as the CPS ecosystem develops.

The primary purpose of a CPS file is to provide a defined schema for describing intention of the original authors and packagers of a library. The files should objectively describe the library as deployed. This will primarily consist of describing built files on disk, how they were built, what headers they provide, and what dependencies that library exposes to consumers.

While there are worse and better ways to build and package libraries, CPS exists partly to describe even mistakes accurately. For instance, it is possible to construct a cyclic dependency graph with CPS. It is wise to avoid cyclic library dependencies, but the CPS project values adaptability of its metadata over perfection. It is expected that tools will develop to help clearly identify problems such as cycles in dependency graphs because CPS data will exist to make that activity possible.


Reference Documentation

Facts, specifics, and other information

Reference documentation for CPS is maintained in the CPS specification. Since precision and review are important to maintaining a specification, those documents are maintained using a more structured pull request workflow. Please use PRs and issues on the CPS repo itself to contribute to the CPS specification.


Contributors' Guide

It can be challenging to write documentation that serves all purposes for all readers. The documentation for CPS is instead structured into the documentation system described by Divio. It's expected that approach will be more approachable both for readers and for contributors to the documentation. If you have ideas, questions, or concerns, please open an issue on this repo describing what you expected and what happened instead.