CMake: Can we specify include directories for a specific set of files not forming an executable or lib?

Viewed 2649

If I have this source tree:

C:\app:
    src:
        CMakeLists.txt
        main.cpp --> #include "acme/header_only_lib/api.h"

D:\3rdparty\acme\header_only_lib:
    api.h --> #include "detail.h"
    detail.h 

Without using symlink tricks, and without adding files to the 3rdparty folders, if I must retain #include "acme/header_only_lib/api.h" in main.cpp, how should I specify the include directories in CMake such that api.h can see detail.h, without adding global include directory of D:\3rdparty\acme\header_only_lib? The header-only-lib is not an executable nor library target, and its code is not modifiable by me. I also don't want to pollute my global include directories by adding D:\3rdparty\acme\header_only_lib because the filenames inside there are too common and will easily clash with other libraries/future code.

Is there a CMake mechanism where I can say: Only for D:\3rdparty\acme\header_only_lib\api.h, add D:\3rdparty\acme\header_only_lib as the include directory?

2 Answers

Use include_directories or target_include_directories:

include_directories("D:\3rdparty")

OR with target_include_directories if you want to make this change only for the main target:

add_executable(main main.cpp)
target_include_directories(main PUBLIC "D:\3rdparty")

Then you can just #include "acme/header_only_lib/api.h" or #include <acme/header_only_lib/api.h>

Header only lib

If you want to do this for header-only-lib only, you need to do this in it's CMake file. First add the library as INTERFACE with no source files:

add_library(header-only INTERFACE) 

Then include directories for it:

target_include_directories(header-only INTERFACE include-dir-for-header-only) 

Then link it to the main target

find_library(HeaderOnly
    NAMES header-only
    HINTS "D:\3rdparty\path-to-lib"
)
target_link_libraries(main header-only)

To add a directory to the global list of include directories, you use e.g.

include_directories( ${CMAKE_SOURCE_DIR}/3rdparty )

Note that you should not hardcode absolute paths (like D:\) into your CMakeLists.txt as that makes it impossible to build your project in any other location. CMake offers variables like ${CMAKE_SOURCE_DIR} and ${CMAKE_BINARY_DIR} for just that purpose.

If you want to add a directory to the list of include directories for a specific part of your build only, you use e.g.

target_include_directories( app PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty )

This adds the directory only for the target (executable / library) app.

Note that, if your acme/header_only_lib is supposed to be installed alongside with the app binaries, this approach won't work, as your acme headers would need to "see" each other on the client's machine, which is unlikely if they reside in the acme/header_only_lib subdirectory but address each other without subdirs. That would require your client (who isn't using your CMakeLists.txt for his builds) to add acme/header_only_lib to the include paths for your header lib to work -- you should not do that.

Related