CMake allows us to organize our project in a better way than a flat structure.
Imagine a project with the following structure:
├── CMakeLists.txt
├── main.cpp
├── print
│ ├── print.cpp
│ └── print.hpp
└── sort
├── sort.cpp
└── sort.hpp
And a CMakeLists.txt that looks like this:
cmake_minimum_required(VERSION 3.0)
project(sortdemo)
add_library(my_sort_lib sort.cpp)
add_library(my_print_lib print.cpp)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME}
PRIVATE
my_sort_lib
my_print_lib
)
This is going to fail to build because it can’t fint either sort.cpp or print.cpp. The solution is sub-directories. Add the following to the file after the project line:
add_subdirectory(print)
add_subdirectory(sort)
And create a CMakeLists.txt in each of the sub-directories print and sort. Add the following to them and remove the add_library lines from the parent CMakeLists:
print/CMakeLists.txt
project(print)
add_library(my_print_lib print.cpp)
sort/CMakeLists.txt
project(sort)
add_library(my_sort_lib sort.cpp
We will need to add the path to the header files includes in the cpp files.
Creating a sub-directory creates a new variable scope. We will still have access to the parent’s variables but they will be copies, like passing parameters in C++, changes made in sub-directory will not be reflected in the parent. To set the variable so it changes in the parent use the PARENT_SCOPE keyword. This will not change the variable in the child scope:
set(some_var "Changed in child" PARENT_SCOPE)
Normally, in a project we organize it with separate include and src directories, so after moving the files around, our project looks like:
├── CMakeLists.txt
├── include
│ ├── print
│ │ └── print.hpp
│ └── sort
│ └── sort.hpp
├── main.cpp
└── src
├── print
│ └── CMakeLists.txt
│ └── print.cpp
└── sort
└── CMakeLists.txt
└── sort.cpp
To make this work, simply add a new CMakeLists.txt to the source folder and add:
add_subdirectory(print)
add_subdirectory(sort)
And change the parent CmakeLists to remove the current add_subdirectory lines and add
add_subdirectory(src)
Modify the src/print/CMakeLists.txt and add:
target_include_directories(my_print_lib PUBLIC ${CMAKE_SOURCE_DIR}/include/print)
And do the same to the sort directory with the appropriate changes. Then in the cpp and header files change the includes to use angle brackets. The PUBLIC in the target_include_directories means that all links to the library inherit the includes.