CmDaB is a lightweight helper for resolving dependencies at CMake configure time using find_package.
It removes the need to manually integrate FetchContent while preserving the native CMake workflow and semantics.
CmDaB augments CMake’s dependency resolution process:
- find_package remains the only API surface
- system packages are preferred when available
- missing packages are fetched and built automatically
- no runtime logic – everything happens during configure
- CmDaB does not attempt to abstract or normalize upstream libraries beyond basic target normalization.
CmDaB extends the standard find_package() workflow by transparently resolving
dependencies from the system or building them from source when necessary.
Unlike traditional package managers, CmDaB does not introduce a separate dependency graph or workflow. Dependencies become part of the normal CMake target graph.
This has a key consequence:
- Dependencies and project code can be built in parallel
- No "build dependencies first" phase is required
- Incremental builds naturally include dependencies
Example:
find_package(Foo)With CmDaB, this will:
- Use a system installation if available (and wanted)
- Otherwise build the package from source using FetchContent
No changes to the caller are required.
| Tool | Integration Model | Workflow Required | Build Model | Parallelization | Uses System Libraries | Builds from Source | Transparent Fallback | External Build Tools |
|---|---|---|---|---|---|---|---|---|
| CmDaB | find_package extension |
no | integrated build graph | high | yes | yes | yes | minimal |
| CMake | explicit find_package |
no | project only | limited | yes | no | no | minimal |
| Meson | built-in dependency API | yes | integrated build graph | high | yes | yes (fallback) | no (explicit) | sometimes |
| vcpkg | toolchain-based | yes | dependencies first | limited | optional | yes | n/a | often |
| Conan | external manager | yes | dependencies first | limited | optional | yes | n/a | often |
Many package managers introduce additional build-time dependencies for building libraries (e.g. Python, Perl, custom scripts).
CmDaB operates purely within the CMake ecosystem:
- Dependencies are expected to be CMake-based
- Build requirements become part of the same CMake build graph
- No separate build toolchain is required
This avoids the need to install additional tools just to build dependencies.
CmDaB integrates dependency resolution directly into the existing
CMake find_package() workflow.
Unlike Meson, which requires explicit fallback definitions, CmDaB applies this behavior transparently without any changes to the caller.
Unlike traditional package managers (vcpkg, Conan), dependencies are not built in a separate phase, but are part of the normal CMake build graph. This allows full parallelization
CmDaB can be integrated in two ways:
Copy CmDaB.cmake into your project, for example:
include(cmake/CmDaB.cmake)Alternatively, include the repository directly:
add_subdirectory(externals/CmDaB)
include(externals/CmDaB/CmDaB.cmake)After inclusion, dependencies are used normally:
find_package(GTest COMPONENTS gmock)
find_package(ZLIB)CmDaB only affects find_package calls that occur after it is included.
Calls made before including CmDaB are not modified and use default CMake behavior.
CmDaB loads package definitions from its packages/ directory
Each package is declared via:
CmDaB_Declare(...)For each package, CmDaB generates:
- a Config.cmake wrapper
- a Find<Package>.cmake wrapper
These are added to the CMake search paths:
- CMAKE_PREFIX_PATH
- CMAKE_MODULE_PATH
When find_package is called:
- CmDaB’s wrapper intercepts the call
- Resolution proceeds via CmDaB_Resolve
Resolution follows a strict order:
- Try system / toolchain packages (find_package)
- Validate required targets
- If insufficient, download and build via FetchContent
- Normalize targets via declared aliases
- System packages may provide more targets than requested, but must provide at least the required ones.
Packages are declared in individual .cmake files:
CmDaB_declare(GTest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG main
OPTIONS
INSTALL_GTEST OFF
TEST_OPTIONS
gtest_build_tests
gmock_build_tests
ALIASES
GTest::gtest gtest
GTest::gmock gmock
)Additional package definitions can be provided via:
set(CmDaB_PACKAGE_DIR "<path>")- packages in this directory are processed before built-in ones
- the first definition wins
- allows clean overrides of existing packages
- bypasses system packages
- always uses FetchContent
- controls all TEST_OPTIONS defaults.Applies only if options are not explicitly set
- Path to an additional directory containing local packages or overrides
Packages can define custom resolution logic:
function(GTest_Handle_Find)
...
endfunction()Use this for:
- component-aware builds
- special build flags
- non-standard upstream behavior
CmDaB intentionally keeps a narrow scope:
- no abstraction of dependency semantics
- no attempt to fix all upstream inconsistencies
- no version or feature management layer
It provides:
- deterministic dependency availability
- consistent integration with find_package
- minimal developer overhead
- Only targets actually provided by upstream are exposed
- Static/shared variants cannot be synthesized
- Some packages require custom handlers
See the LICENSE file for details.
CmDaB can optionally cache built dependencies locally.
After an initial build from source, dependencies can be reused in subsequent builds, combining the benefits of source-based builds with binary reuse.
This enables:
- Reproducible builds without a central registry
- Fast rebuilds after initial setup
- No additional package manager workflow