Handling Header Files Dependencies with Cmake

How CMake automatically detects header dependencies

When I run cmake . -B build it creates the following make target in ./build/CMakeFiles/main.dir/build.make

CMakeFiles/main.dir/main.cpp.o: CMakeFiles/main.dir/compiler_depend.ts
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/nikolay/Cpp/Train/Cppref/build/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object CMakeFiles/main.dir/main.cpp.o"
/usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -MD -MT CMakeFiles/main.dir/main.cpp.o -MF CMakeFiles/main.dir/main.cpp.o.d -o CMakeFiles/main.dir/main.cpp.o -c /home/nikolay/Cpp/Train/Cppref/main.cpp

Pay attention to the -MD compiler option, as
it is used to dump dependencies visible to the preprocessor.

So after the first build it will create ./build/CMakeFiles/main.dir/main.cpp.o.d with the following content

CMakeFiles/main.dir/main.cpp.o: /home/nikolay/Cpp/Train/Cppref/main.cpp \
/home/nikolay/Cpp/Train/Cppref/header.h

So whenever you change header.h, the target main.o will be rebuilt.

CMake get dependent header files like gcc -M

Check the build folder for your CMake project. For each target, CMake should generate a file called C.includecache. This file contains the include dependency information.

If, for example, you have a main.c file which is including the stdio.h and math.h headers. The C.includecache file will contain an entry like:

/path/to/main.c
stdio.h
-
math.h
-

CMake - dependencies (headers) between apps/libraries in same project

Here's one possible solution:

Root CMakeLists.txt:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(${PROJECT_NAME})
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)



lib1/CMakeLists.txt:

project(Lib1)
add_library(lib1 lib1.cpp lib1.h)



lib2/CMakeLists.txt:

project(Lib2)
add_library(lib2 lib2.cpp lib2.h)

# Add /lib1 to #include search path
include_directories(${Lib1_SOURCE_DIR})
# Specify lib2's dependency on lib1
target_link_libraries(lib2 lib1)



app/CMakeLists.txt:

project(App)
add_executable(app main.cpp some_header.h)

# Add /lib1 and /lib2 to #include search path
include_directories(${Lib1_SOURCE_DIR} ${Lib2_SOURCE_DIR})
# Specify app's dependency on lib2.
# lib2's dependency on lib1 is automatically added.
target_link_libraries(app lib2)



There are plenty of different ways to achieve the same end result here. For a relatively small project, I'd probably just use a single CMakeLists.txt:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)

add_library(lib1 lib1/lib1.cpp lib1/lib1.h)
add_library(lib2 lib2/lib2.cpp lib2/lib2.h)
add_executable(app app/main.cpp app/some_header.h)

include_directories(${CMAKE_SOURCE_DIR}/lib1 ${CMAKE_SOURCE_DIR}/lib2)

target_link_libraries(lib2 lib1)
target_link_libraries(app lib2)



For further info on the relevant commands and their rationale, run:

cmake --help-command add_subdirectory
cmake --help-command include_directories
cmake --help-command target_link_libraries

CMake cannot figure out header dependencies if build is out-of-source?

If your build directory is a subdirectory of the source directory, then it's not really out-of-source, but a sort of hybrid. The recommended CMake approach is to do proper out-of-source builds where the source and binary directory are totally unrelated. This means they can be siblings or further removed, but neither is a descendant of the other.

CMAKE auto header file dependency

As mentioned in my comment, I have tried out your example and things were working fine: if main.h was modified then main.c would be recompiled.

My installation of CMake (version 2.8.0) told me to add

cmake_minimum_required(VERSION 2.8)

to the CMakeLists.txt file, but that is all of the adjustments I needed.

CMake and issues with header files in subfolders

As the name implies, target_include_directories only affects one target. So when you set target_include_directories(${PROJECT_NAME} PUBLIC Lib/headers/), this adds to the include path for the executable target named ${PROJECT_NAME} but not to the include path for the library name_of_lib.

To fix this, you can add the include path for your library in the lower level CMakeLists.txt:

target_include_directories(name_of_lib PUBLIC headers)

As a bonus, because it's PUBLIC, this path is also automatically added to any target that depends on name_of_lib. So in the top-level CMakeLists.txt, you can remove this line:

target_include_directories(${PROJECT_NAME} PUBLIC Lib/headers/)

Aside, this line looks useless and can probably be removed as well:

target_link_directories(${PROJECT_NAME} PRIVATE Lib/headers/)

Link libraries are not usually placed in headers directories.

Importing header files and linking .a file in CMake

In your primary CMakeLists.txt file you would simply add the following:

target_link_libraries(project skia)

If CMake cannot find the library, you can either do:

target_link_libraries(project /full/path/to/libskia.a)

or:

link_directories(/path/to/libraries)
target_link_libraries(project skia)


Related Topics



Leave a reply



Submit