In the beginning, there was anarchy. Building a project which consumed a different, external project typically involved hand coding build directives based on assumptions where the external would be located.

Along came pkg-config. This was an improvement, but it was designed for UNIX-like platforms and isn’t entirely portable. Also, while pkg-config does an adequate job describing the necessary compile and link flags to consume a package, this information is not always sufficient.

Some time later, CMake entered the scene, eventually gaining its own mechanism to describe a package. While this system solved many earlier problems, it relies on the CMake language and is therefore tightly coupled to that build system.

CPS attempts to solve these issues by taking the lessons learned by CMake and providing compatible information in a format that is not tied to the language of a particular build system.

What’s wrong with pkg-config?

pkg-config was created way back in the bad old days of autotools, when everyone was using the same compiler and linker. It handles everything by direct specification of compile flags, which breaks down when multiple compilers with incompatible front-ends come into play and/or in the face of “superseded” features. (For instance, given a project consuming packages “A” and “B”, requiring C++14 and C++11, respectively, pkg-config requires the build tool to translate compile flags back into features in order to know that the consumer should not be build with -std=c++14 ... -std=c++11.)

Specification of link libraries via a combination of -L and -l flags is a problem, as it fails to ensure that consumers find the intended libraries. Not providing a full path to the library also places more work on the build tool (which must attempt to deduce full paths from the link flags) to compute appropriate dependencies in order to re-link targets when their link libraries have changed.

Last, pkg-config is not an ideal solution for large projects consisting of multiple components, as each component needs its own .pc file.

What’s wrong with CMake exported targets?

CMake exported targets provide a richly featured mechanism for describing packages as a set of individual components, along with the necessary details for consuming each individual component. This generally works well… for CMake. The biggest problem with this system is not any internal flaw in the system, but the fact that it relies on the CMake language. Consumers have to parse not only CMake syntax, but in some cases need to cope with CMake generator expressions. Moreover, packages have access to the entire CMake language, which is Turing complete and capable of executing external processes. It would be exceptionally difficult for non-CMake tools to consume CMake package specifications without effectively reimplementing most or all of CMake itself. Clearly, this is not practical.

Even so, certain tasks that should be easy, such as handling transitive dependencies or specifying version compatibility, are difficult and may require hand-writing code. While there is plenty of room for improvement without leaving the CMake ecosystem, CPS offers similar room for growth while also opening up package distribution to a wider audience of consumers.