Cmake Include_Directories()

How to properly add include directories with CMake

Two things must be done.

First add the directory to be included:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

In case you are stuck with a very old CMake version (2.8.10 or older) without support for target_include_directories, you can also use the legacy include_directories instead:

include_directories(${YOUR_DIRECTORY})

Then you also must add the header files to the list of your source files for the current target, for instance:

set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})

This way, the header files will appear as dependencies in the Makefile, and also for example in the generated Visual Studio project, if you generate one.

How to use those header files for several targets:

set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)

add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})

cmake - When to include include_directories in a CMakeLists.txt file

How to know whether a library should be included using include_directories or target_link_libraries?

Unless a library is a header-only library, call to target_link_libraries is required for use it.

If Find* script (called by find_package() call) sets variable with include directories (this information can be obtained from the script's documentation), it assumes that these directories will be included (via include_directories or target_include_directories).

Propagating include directories through the target_link_libraries occurred in case of IMPORTED target, usually named as <namespace>::<name>.


In your specific case include_directories have no effect only because given directory is searched by a compiler by default, this is usual when library is installed through package manager. But find_package is intended to work even with non-system installations.

Cmake include_directories()

Quoting the documentation for include_directories:

The include directories are added to the directory property
INCLUDE_DIRECTORIES for the current CMakeLists file. They are also
added to the target property INCLUDE_DIRECTORIES for each target in
the current CMakeLists file. The target property values are the ones
used by the generators.

The INCLUDE_DIRECTORIES directory property is inherited to all subdirectories and all targets in the directory.

  • Specifying ${CMAKE_CURRENT_SOURCE_DIR} for include_directories is redundant as relative paths are interpreted as relative to this directory by default. You should throw it out to increase readability.
  • Specifying an include directory in both a subdirectory and its parent is redundant. You should avoid this and settle on one location.
  • Use get_property and message to double-check that all directories and targets end up with the correct entries in their INCLUDE_DIRECTORIES property.
  • If you are free to require CMake 2.8.11 as a minimum requirement, consider abandoning include_directories completely and use target_include_directories instead. This has the advantage that include dependencies get resolved on a per-target basis exclusively which is usually the more desirable behavior.

include_directory inheritance within CMake?

Yes, that is the standard behavior for CMake's include_directories command. If you want properties to propagate to dependents, use the target_include_directories command that became standard with version 3. Specifically, locations with headers that are needed by client code should be in the PUBLIC or INTERFACE section. If SubL also needs to include headers there, use PUBLIC. Look at the whole family of target_* commands for property propagation to dependents.

CMake include_directories does not help to find header files

'include_directories' affects the include directories of targets in that CMakeLists.txt, and its descendants. I think the issue is that the executable is added (targeted) in CMakeLists.txt 1; src.cpp isn't actually in CMakeLists 2's target/build scope, so it isn't affected by 'include_directories' calls in CMakeLists 2.

Why is CMake removing some include directories from INCLUDE_DIRECTORIES() calls?

After a few days I couldn't find a better answer so I'll post this answer-to-self since it works.

During the compiler detection, CMake will extract a series of implicit include paths which usually are always available and, if added to include paths, might break the compilation process (Thanks to @Tsyvarev for the caveat). However, if this path gets incorrectly added to the excluded paths, the only way I could find to override this is removing the exclusion list alltogether using:

unset(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES)
unset(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES)

As described on https://gitlab.kitware.com/cmake/cmake/issues/17966 but this solution is using CMake internals so it may do or break depending on your compiler or environment. In this particular case the fix worked.

On a similar situation, again with a proprietary + ancient gcc toolchain, simply updating to the latest CMake version worked, apparently due to better compiler detection.

How to set include_directories from a CMakeLists.txt file?

include_directories() populates a directory property called INCLUDE_DIRECTORIES:

http://www.cmake.org/cmake/help/v2.8.12/cmake.html#prop_dir:INCLUDE_DIRECTORIES

Note that CMake 2.8.11 learned the target_include_directories command, which populates the INCLUDE_DIRECTORIES target property.
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#command:target_include_directories

Note also that you can encode the fact that 'to compile against the headers of the lib target, the include directory lib/inc is needed' into the lib target itself by using target_include_directories with the PUBLIC keyword.

add_library(lib STATIC ${lib_hdrs} ${lib_srcs}) # Why do you list the headers?
target_include_directories(lib PUBLIC "${ROOT_SOURCE_DIR}/lib/inc")

Note also I am assuming you don't install the lib library for others to use. In that case you would need to specify different header directories for the build location and for the installed location.

target_include_directories(lib
PUBLIC
# Headers used from source/build location:
"$<BUILD_INTERFACE:${ROOT_SOURCE_DIR}/lib/inc>"
# Headers used from installed location:
"$<INSTALL_INTERFACE:include>"
)

Anyway, that's only important if you are installing lib for others to use.

After the target_include_directories(lib ...) above you don't need the other include_directories() call. The lib target 'tells' proj1 the include directories it needs to use.

See also target_compile_defintions() and target_compile_options().



Related Topics



Leave a reply



Submit