CMake is a de facto standard build tool forC++. There are those who love it, and there are those who hate it. Thetool had a few problems in the past, butModernCMake solved most of them and continued to evolve and add more andmore features.
Watch Effective CMaketalk by Daniel Pfeifer andUsing Modern CMakePatterns to Enforce a Good Modular Design by Mathieu Ropert to get anidea and hints on modern CMake.
Use the industry standard build system, with its wide feature set, large ecosystem to build Qt applications. Support for Catch2 test framework.
- How to launch conan install from cmake¶ It is possible to launch conan install from cmake, which can be convenient for end users, package consumers, that are not.
- From Catch2's example, I tried to run this example with cmake where structure of my project is like this: /factorial +- CMakeLists.txt +- /bin +- /include +- catch.hpp.
![Catch2 cmakelists Catch2 cmakelists](/uploads/1/3/7/2/137291065/507393372.jpg)
In this blog post, I describe the approach I use to manage externaldependencies in C++ projects.
The dependencies have to have a validCMake configuration, i.e. they have to export their targets asdescribed in Daniel Pfeifer’s 'Effective CMake' starting at37:34, Henry Schreiner’sModernCMake: Exporting and Installing, andIt’sTime To Do CMake Right by Pablo Arias.
Typical project layout
Let’s review the layout of one of my C++ projects:
There are a few items in the root directory of the project:
Directory | Purpose |
---|---|
. | Project root with the root CMakeLists.txt |
build | That’s where you do cd build && cmake .. && make to build the project |
cmake | Consists of custom CMake modules |
conker | A subproject for a library |
extern | External dependencies |
outpost | A subproject for a main application |
test | A subproject for unit-tests |
Describing dependencies
![Catch2 Catch2](/uploads/1/3/7/2/137291065/880307889.png)
The
extern/CMakeLists.txt
file is a central repository for thedependencies. Make it available from the root CMakeLists.txt
:Let’s take a closer look at the dependencies file:
The script uses CMake’sFetchContentmodule which enables populating content at configure time. That’s how youdescribe a dependency:
In other words, you declare where and how to get the dependency firstand then check if it is already available. If it is not avialable yet,then you fetch it and include into the build using the
add_subdirectory
command.Catch2 Cmake Include
Importing dependencies in subprojects
FetchContent
makes exported targets available to the build so that you can usethem in target_link_libraries
:Here, I added the
glfw
as a public dependency to the outpost
target.Hierarchical dependency management
There are few ways to organise dependency management.
Keep all dependencies in the same file
It’s good enough for simple projects that live in the same repository,and there are no plans to move subprojects outside of it. That’s whatI described in the previous sections.
Each subproject describes its dependencies
In this case, you make subprojects independent by adding their own
external/CMakeLists.txt
. Then you can extract any of them from thesource tree and build it without any further configuration if needed.Catch Unit Test
Combination of the previous methods
You declare dependencies for each subproject in their own
external/CMakeLists.txt
. Then you declare (i.e. duplicate)dependencies on one level higher than the subprojects. This is how youoverride population of content specified anywhere lower in the projecthierarchy.