![]() |
Scanframe DevOps Trial App 0.1.0
|
The cmake/lib Git submodule provides a complete C++ project boilerplate that enables cross-platform development, building, testing, and packaging from a single codebase. It is designed to work from a freshly installed operating system — Linux or Windows — without requiring manual toolchain setup.
The submodule delivers:
In a typical project, the cmake/lib submodule is added as a Git submodule. The project then creates its own CMakeLists.txt, CMakePresets.json, and build.ini files — either by copying from the submodule's tpl/root/ templates or by creating them from scratch. The submodule's CMake packages are discovered via CMAKE_PREFIX_PATH and loaded with find_package().
The submodule provides several CMake packages, each discovered via find_package() in the top-level CMakeLists.txt. The CMAKE_PREFIX_PATH is set to include both cmake/ and cmake/lib/ so that project-specific and submodule packages are both found.
The foundational package that provides core functions and macros used throughout the build system:
Configures the compiler toolchain based on the SF_COMPILER cache variable and the host system. It determines the correct compiler paths, architecture settings, and platform-specific flags.
Provides reusable CMake macros and functions for common tasks, such as setting target options, parsing arguments, and managing file operations.
Ensures that the current build directory is not within the source.
Handles Qt library discovery and automatic download. When SF_BUILD_QT is enabled, it reads the Qt version from build.ini and locates or downloads the required Qt libraries.
Integrates the Catch2 testing framework.
Integrates the GoogleTest testing framework.
When SF_BUILD_TESTING is enabled in the project, unittests become available in the project. Tests can be executed from the CLion IDE or via the command line.
Configures Doxygen documentation generation with PlantUML support. With the flag doc passed to Sf_AddTarget() when creating a target, documentation is generated for the target. See Documentation for conventions.
The build system uses CMake Presets (version 6) defined in two files:
Contains the base presets provided by the submodule. Key preset categories include:
Allows project-specific overrides and additional presets without modifying the submodule's file. Follows the same structure and can extend or override base presets. The inheritance tree for each preset type is illustrated in the diagrams below.
Presets include vendor: {"jetbrains.com/clion": {"toolchain": "..."}} entries that enable CLion to automatically detect and configure the correct toolchain. This allows developers to switch between compilers (GNU, MinGW, MSVC) directly within the IDE without manual CMake configuration.
The complete build workflow follows a linear pipeline orchestrated by build.py:
For detailed build.py usage, see Python Build Script.
When Sf_AddTarget() is called with the VERSION flag, the function Sf_AddVersionResource() embeds version information into the compiled binary. The approach differs between platforms:
For Windows targets, Sf_AddVersionResource() processes the version.rc template via configure_file(), substituting @RC_*@ variables with project metadata (version, company name, description, compiler info, build timestamp). The generated .rc file is added to the target sources and compiled into the PE resource section. The resulting .exe or .dll contains VS_VERSION_INFO with:
For Linux targets, Sf_AddVersionResource() processes the version.cpp template, which declares const char arrays placed in custom ELF sections (.meta.CompanyName, .meta.FileVersion, etc.) using __attribute__((section(".meta.name"))). These sections are embedded in the compiled binary and can be read by exiftool.py.
When Sf_AddTarget() is called with the EXIF flag, a custom exif-<target> target is created that runs exiftool.py after the build. The script:
The top-level exif custom target aggregates all exif-<target> targets, providing a single build target that reports metadata for all binaries.
The submodule provides several shell scripts in cmake/lib/bin/ that support the build workflow. These scripts are primarily used during Linux development.
Invoked by the Git pre-commit hook to verify code formatting before commits. This script works on Windows as well when Git is configured to run the hook, making it cross-platform despite being a shell script. The pre-commit hook is installed at .git/hooks/pre-commit and symlinks to cmake/lib/tpl/root/git-pre-commit-hook.sh.
Testing is enabled when SF_BUILD_TESTING is set to ON. The submodule integrates two testing frameworks:
Integrated via SfCatch2Config.cmake. Catch2 tests are defined in the src/tests/catch/ directory and can use the single-header framework for lightweight testing.
Integrated via SfGoogleTestConfig.cmake. GoogleTest tests are defined in src/tests/google/ and provide a more comprehensive testing framework with fixtures and parameterized tests.
Coverage analysis is available when building with the GNU compiler and the Coverage build type.
When CMAKE_BUILD_TYPE is set to Coverage, the build enables gcov instrumentation. After running tests, Sf_AddTestCoverageReport() generates:
The coverage report test is added as the last test to ensure all instrumented targets have been built.
In the GitLab CI/CD pipeline, coverage HTML reports are uploaded to the Nexus exchange repository. This approach solves a key limitation: child pipelines cannot report coverage percentages back to the parent pipeline. By uploading the report to a shared Nexus repository, the main pipeline can access and display the coverage results.
Example URL pattern:
When the build type is not Coverage, CPack configuration is applied via SF_CPACK_PREPARE_FILE, which points to cmake/lib/tpl/cpack/prepare.cmake. The packaging system supports multiple generators:
Package configuration files are located in cmake/lib/tpl/cpack/ and include platform-specific settings for icons, licenses, installation directories, and component grouping.
Documentation is generated by the document CMake target, which is added when the doc/ directory exists and SfDoxygen is found. The documentation system:
For documentation conventions, see Documentation.
To build documentation:
The submodule provides GitLab CI/CD configuration in cmake/lib/tpl/root/gitlab-ci/ with two approaches:
A single-job pipeline that performs configure, build, test, and package in one continuous job. This approach avoids the CMake absolute path issue and is the recommended configuration.
Splits the workflow into multiple jobs. This approach has a known limitation: CMake uses absolute paths in its cache, and GitLab runners may not provide the same filesystem paths between jobs. To work around this, the project directory must be bound to /tmp consistently across jobs. Additionally, artifacts (including coverage reports) must be stored in the Nexus exchange repository because child pipelines cannot pass data back to the parent pipeline.
The main pipeline triggers child pipelines for each toolchain (GNU, MinGW/GW, MSVC, GNU Coverage). This enables parallel builds across different compilers and platforms.
Pipeline jobs run in Docker containers with pre-configured toolchains, eliminating the need for manual compiler installation. The same Docker images are used for local Docker builds via build.py.
The build system supports building for multiple platforms and architectures from a single codebase:
Developers can work entirely on Linux:
The function Sf_GetGitTagVersion() extracts the project version from Git tags. It analyzes the current repository state and returns:
The version is set as the CMake PROJECT_VERSION and flows through to:
For semantic versioning and conventional commit details, see Semantic Versioning.