|
StormByte - Build Master
|
Build Master is a small DSL extension for CMake that makes it simple and reliable to build, install and consume external CMake and Meson projects from a parent CMake tree. It was created to work around a common limitation of ExternalProject_Add: external projects are typically configured at build time, which prevents the parent CMake from observing and reacting to configure-time results.
Build Master generates configure / compile / install stages during CMake configure time, allowing the parent project to inspect artifacts, create import targets, and adjust environment variables deterministically.
When a CMake project needs to build external dependencies as part of its own build, the usual tool — ExternalProject_Add — has several structural limitations:
POST_BUILD commands to a clean <component>_build or <component>_install target because those targets simply do not exist.Additionally, unlike FetchContent, Build Master does not merely download sources — it orchestrates full configure/build/install stages with environment propagation and explicit targets.
Build Master solves these issues by generating deterministic stages during configure time, exposing targets such as:
This makes it trivial to attach post-build actions, inspect installed artifacts, and integrate external projects as if they were native parts of the parent build.
Managing external dependencies in CMake has traditionally required a patchwork of ad‑hoc scripts, late‑executed logic, and build‑time orchestration that prevents the parent project from making informed decisions during the configuration phase. Tools like FetchContent and ExternalProject_Add each solve part of the problem, but neither provides a complete, deterministic, configure‑time model for building and integrating external components.
FetchContent focuses on retrieving sources, but delegates all configuration to the external project. ExternalProject_Add performs configuration and build steps only at build time, when it is already too late for the parent project to inspect results, generate import targets, or adjust its own configuration based on the external dependency’s capabilities.
This leaves a structural gap:
How can a CMake project reason about external dependencies during configure time, before the build begins, and without reinventing orchestration logic for each component?
Build Master exists to close that gap.
By generating configure/build/install stages during CMake’s configure phase, Build Master allows the parent project to:
The result is a dependency model that is deterministic, inspectable, and reproducible — turning external integration from a fragile afterthought into a first‑class, declarative part of the build system.
Build Master does not replace CMake’s existing tools. Instead, it extends them by providing deterministic configure‑time orchestration where CMake traditionally defers work to the build phase.
| Capability | FetchContent | ExternalProject_Add | Build Master |
|---|---|---|---|
| Retrieve sources | ✔️ | ✔️ | ✔️ (via Git helpers) |
| Configure external projects | ❌ | ✔️ (build time) | ✔️ configure time |
| Inspect artifacts before build | ❌ | ❌ | ✔️ |
| Deterministic imported targets | ❌ | Partial | ✔️ |
| Meson integration | ❌ | Manual | ✔️ native |
| Environment propagation | ❌ | Manual | ✔️ coherent |
| Recursive usage without conflicts | ❌ | Fragile | ✔️ designed for it |
| Reproducibility | Medium | Low | High |
| Feature | FetchContent | ExternalProject_Add | Build Master |
|---|---|---|---|
| When configuration happens | N/A | Build time | Configure time |
Explicit <component>_build / <component>_install targets | ❌ | ❌ | ✔️ |
| Ability to attach post‑build steps to external components | ❌ | ❌ | ✔️ |
| Unified installation layout | ❌ | Partial | ✔️ |
| Multi‑build‑system support (CMake + Meson) | ❌ | Manual | ✔️ |
| Versioned, generated scripts | ❌ | ❌ | ✔️ |
| CI determinism | Medium | Low | High |
| Inspect configuration results | ❌ | ❌ | ✔️ |
| Stability in deep dependency trees | Low | Fragile | ✔️ robust |
PKG_CONFIG_PATH, PATH, LIB, INCLUDE, etc.).Using Build Master in a project is intentionally simple — three steps:
What these lines do:
BUILDMASTER_INITIALIZE_EXTRA_TOOLS: optional list of extra tools that are not initialized by default.add_subdirectory(buildmaster): configures and initializes Build Master.include(buildmaster/helpers.cmake): imports helper functions such as create_component(), create_cmake_component(), create_meson_component() and other utilities.After this you can declare components:
Notes:
OUT_FILE) receives the generated fragment path.include(${OUT_FILE}), the imported targets and stage targets (<component>_build, <component>_install) become available.By default Build Master produces minimal, concise output: a single brief line for each stage — configure, build and install — so that CMake output remains compact when managing many components. To enable full, verbose output for the configure and build stages set the environment variable BUILDMASTER_DEBUG to 1. When BUILDMASTER_DEBUG is 1 Build Master will show the underlying configure and build tool output (stdout/stderr) to help diagnose configure-time or build-time problems.
Build Master is designed to support recursive usage: an external CMake project may itself use Build Master to orchestrate its dependencies, and those dependencies may also use Build Master, recursively. This is possible because Build Master is initialized only once (for example by add_subdirectory(buildmaster)) and all recursive instances share the same installation location (the unified BUILDMASTER_INSTALL_DIR). Nested projects therefore reuse the same initialization state and installation layout, avoiding duplicate initializations and conflicting install paths while ensuring deterministic behavior across parent and subproject boundaries.
create_component() or the wrappers create_cmake_component() / create_meson_component().create_cmake_stages() or create_meson_stages() directly.POST_BUILD steps.OUTPUT, so other targets can depend on them.create_component(_out_var _component _component_title _srcdir _builddir _options _library_mode _build_system _subcomponents _dependency)create_cmake_stages(_file_configure _file_compile _file_install _component _component_title _srcdir _builddir _options _library_mode _output_libraries)create_meson_stages(...)library_import_hint()library_import_static_hint()library_dll_hint()sanitize_for_filename()list_join()prepare_command()These helpers are used internally by templates but can also be used by the user.
CMake templates:
tools/cmake/configure.cmake.intools/cmake/build.cmake.intools/cmake/install.cmake.inMeson templates:
tools/meson/setup.cmake.intools/meson/compile.cmake.intools/meson/install.cmake.inTemplates are versioned and can be customized if needed.
Build Master includes helpers that generate Git-related scripts under the generated scripts tree.
Examples:
Scripts are generated under BUILDMASTER_SCRIPTS_GIT_DIR.
component/helpers.cmaketools/cmake/helpers.cmaketools/meson/helpers.cmaketools/gitBuild Master is distributed under the MIT License.
See the LICENSE file for full details.