In the CMakeLists.txt
of the root-level, I use add_subdirectory
to add two directories that have two CMakeLists
correspondingly responsible for building different stuff. How can I use the first project into the second one, passing the cmake configuration (i.e. what is to be included for that project) instead of manually copying cmake commands from one CMakeLists.txt
to the other?
$ tree
├── libs
│ └── dependency
│ ├── CMakeLists.txt
│ ├── include
│ ├── other_include
│ └── src
│
├── project
│ ├── CMakeLists.txt
│ ├── include
│ └── src
│
└── CMakeLists.txt
...
...
add_subdirectory(libs/dependency)
add_subdirectory(project)
...
...
Pasting the vital content from the one file to another works. But in my case, this content is about a few paths to the header files, some to the implementation files and the linking to the library. However, I am very curious to learn what's the best practice in such circumstances, especially when it comes to more complicated projects. So I am keeping the question as simple and generic as possible, hoping it s not something obvious that I miss.
In the CMakeLists.txt
of the root-level, I use add_subdirectory
to add two directories that have two CMakeLists
correspondingly responsible for building different stuff. How can I use the first project into the second one, passing the cmake configuration (i.e. what is to be included for that project) instead of manually copying cmake commands from one CMakeLists.txt
to the other?
$ tree
├── libs
│ └── dependency
│ ├── CMakeLists.txt
│ ├── include
│ ├── other_include
│ └── src
│
├── project
│ ├── CMakeLists.txt
│ ├── include
│ └── src
│
└── CMakeLists.txt
...
...
add_subdirectory(libs/dependency)
add_subdirectory(project)
...
...
Pasting the vital content from the one file to another works. But in my case, this content is about a few paths to the header files, some to the implementation files and the linking to the library. However, I am very curious to learn what's the best practice in such circumstances, especially when it comes to more complicated projects. So I am keeping the question as simple and generic as possible, hoping it s not something obvious that I miss.
Share Improve this question asked Mar 28 at 13:34 cestpasmoicestpasmoi 6758 silver badges19 bronze badges 7 | Show 2 more comments1 Answer
Reset to default 1Assuming dependency
is a library that is linked by project
, you would create a library target using add_library(dependency src/dependency.cpp)
and then use target_include_directories(dependency INTERFACE $CMAKE_CURRENT_LIST_DIR/../include)
to let whomever uses dependency
that -I $CMAKE_CURRENT_LIST_DIR/../include
needs to be added to the include path to allow for it to be included by the source files trying to use it.
The order of the creation of targets is irrelevant, as CMake will defer resolving that until later.
FWIW, when I'm putting together a build system I have a convention that directory structure is set up so that the include is to be specified like: #include "mylibrary/mylibrary.h"
so that only -I <root>/libraries/
ends up being added to the compile flags (reduces the compilation time because it doesn't need to search so many directories).
So something like:
/
+ libraries/
| + CMakeLists.txt
| + lib1/
| | + CMakeLists.txt
| | + lib1.h
| | + src/
| | + lib1.cpp
| + lib2/
| + CMakeLists.txt
| + lib2.h
| + src/
| + lib2.cpp
+ projects/
+ project1/
+ CMakeLists.txt
+ src/
+ project1.cpp
So in this case, both lib1 and lib2 will add libraries/
to their interface includes, so when you have target_link_libraries(project1 lib1 lib2)
then lib1 will add ./libraries/
to the include path and so will lib2
, and it'll collapse to a single -I ./libraries/
and #include "lib1/lib1.h"
and #include "lib2/lib2.h"
will resolve properly when project1.cpp
is being built.
For more info on this, look for "modern cmake" documentation. The idea is "properties" of targets are transitive and you attach whatever property is required to build a target to the target, so when something uses that target the properties will be applied to the user of the target.
The key to controlling this 'transitive' stuff that PUBLIC
means add to both the target and the user of the target. PRIVATE
means just added to the target when it's being compiled, and INTERFACE
properties are only to the user of the target when it is compiling.
project
? If not, all targets created inlibs/dependency
are visible in the root CMake file and the one inproject
. No need for copy-pasting. – Botje Commented Mar 28 at 13:37target_include_directories(some_dependency PUBLIC ...)
to annotate thesome_dependency
target with an include directory and usetarget_link_libraries(some_project PUBLIC some_dependency)
to link the two. CMake is all about targets and their (transitive or inherited) properties... – Botje Commented Mar 28 at 14:10