Basic Concepts¶
This pages describes the general ideas behind the CMakeProjectFramework. It introduces some terms that are used throughout the documentation of this project.
Concepts¶
The CPF follows the following key concepts.
Provide a multi repository approach that allows the distribution of the code base over multiple repositories.
Define the build infrastructure completely in text-files that can be held in a repository. This allows to quickly set up the infrastructure from a small amount of data. The repository also provides the change history for the system.
Hide all CMake features behind a smaller declarative interface. While cmake offers the functionality to solve all problems that occur when setting up a C++ code-base, it is still quite some work to implement a solution. The CPF wants to take that burden from its users, while trying not to loose too much of the generality that a custom implementation would offer.
Keep files of three different live expectancies in three different directories. Sources, Configurations and generated files. Keeping the generated files out of the source-tree has become the norm when using CMake. This allows deleting the build-tree in order to guarantee a fresh system. However, in the standard CMake workflow, the generated files also contain the manually defined project configuration within the
CMakeCache.txt
file. For complex projects, defining a configuration may take some time and deleting it together with the generated files is undesirable. The CPF therefore puts the configuration information in a directory that is parallel to the build- and source-tree. It also allows defining multiple configurations at the same time.Let the build system handle parallelism and up-to-date checks. The CPF takes advantage of CMake’s custom target mechanism. This way the advanced tasks like test-runs, code-analysis or documentation generation may be run in parallel and are only re-run when they are outdated.
Separate the CI-code from the production code by putting it into the CI-project repository. Read more in CI Project vs. Package Projects.
CI Project vs. Package Projects¶
In a CPF project, the code that implements the CI-job is separated from the payload code. The payload code can be split up into multiple packages.
To achieve this, a CPF project has two CMake project levels. The CI project is created in the root CMakeLists.txt
file. It provides
the interface for the CI-job and the developers to build a set of packages and defines which configurations are build by the CI-system.
The project repository can also contain some higher level documentation that does not really belong to a single
package, but rather the group of packages that is owned by the CI project.
In the Sources subdirectory we have the package directories that contain the CMakeLists.txt
files that define the package
projects. Each package creates one main binary that is supposed to be used by consumers. This can be a library or an executable.
The package can also contain other arbitrary files like test-code, image resources, documentation and everything else that
belongs to that piece of functionality.
Multi Repository Approach¶
For small code bases it is practical to keep all files in a single repository.
This avoids version conflicts and keeps the project nice and simple.
This means however, that a change in a a lower lever library must always be
pulled through for all components that use the library. A change in one .cpp
file
will always trigger the build-job for the whole world. One can imagine that this
does not scale for a growing code-base.
The CPF therefore supports splitting up the code-base into multiple repositories and multiple build-jobs. A CPF project can be started with the simple single repository and single build-job approach and later be split up in multiple repositories and multiple build-jobs. One should be aware though, that this introduces a noticeable increase in complexity. The git work will increase and and version conflicts become possible.
Each CI-project repository defines a CI-build-job for multiple packages, and each package can have its own repository which is recommended for packages that are consumed by multiple CI-projects.
Todo
Add a nice diagram of a monolithic project vs. a distributed one.
Package Ownership¶
A package can be owned by a CI project or be an external package. If a package is owned by a CI project it means, that this CI project is responsible for running the automated tests of the package and defining the officially supported build configurations of that the package. When using the CPFMachines CI-job, it will also be the entity that marks successful builds of owned packages with version tags. An owned package can either be included in the CI projects git repository, or it can be a git submodule with its own repository. If it uses a git submodule it is called a loose owned package. In this case it’s version number can advance independently of the CI-repository. Packages that are intended to be used in other projects, should be loose packages with their own repository to allow other projects to include the package as a git submodule. Loose packages lead to more and more complex git work, meaning that more git operations will be necessary in the day to day work. If packages are executables or not used in other projects, it is therefore recommended to make them fixed packages and check them directly into the CI repository.
External packages are always git submodules. The CI project’s build-pipeline will not run the tests for these packages and exclude them when generating the documentation. An external project should have another CI project that owns that package.