I have a project with the following file structure:
project
|
|-------> lib1
| |----> lib1.h
|
|-------> lib2
| |----> lib2.h
|
|-------> main.cc
The two libs lib1
and lib2
only contain header files while lib2.h
includes lib1.h
, and main.cc
includes lib2.h
.
How do I write the cmake file for this project now? I tried to create an interface library for lib2
, but the compiler can't find lib1.h
. Here are the contents of my cmake files:
CMakeLists.txt for lib2:
add_library(lib2 INTERFACE)
target_sources(lib2 INTERFACE lib2.h)
target_include_directories(lib2 INTERFACE ../lib1/lib1.h)
CMakeLists.txt for the whole project:
add_executable(project main.cc)
target_link_libraries(project lib2)
What's the problem in the cmake files?
Creating a Header-Only CMake Target By specifying INTERFACE as the second parameter to add_library , we are no longer allowed to provide source files since the library is not meant to generate any build output.
In the context of the C or C++ programming languages, a library is called header-only if the full definitions of all macros, functions and classes comprising the library are visible to the compiler in a header file form.
To include headers in CMake targets, use the command target_include_directories(...) . Depending on the purpose of the included directories, you will need to define the scope specifier – either PUBLIC , PRIVATE or INTERFACE .
Interface Libraries add_library(<name> INTERFACE) Creates an Interface Library. An INTERFACE library target does not compile sources and does not produce a library artifact on disk. However, it may have properties set on it and it may be installed and exported.
As stated in the comments, target_include_directories
should be given a path to a directory, not to a file.
Moreover, if you want to create a dependency for lib2
on lib1
, you should do it through target_link_libraries
: a dependency is not only about include directories, but also about compile options, definitions, target properties...
target_sources
doesn't work with interface libraries. From this answer, You can use a custom target without commands to associate the sources to a target without impacting the build process (for msvc, QtCreator and other GUI-based tools, this makes the sources accessible through the IDE; AFAIK it's useless for other build tools).
Your cmake may look like this:
add_library(lib1 INTERFACE)
target_sources(lib1 INTERFACE lib1.h)
target_include_directories(lib1 INTERFACE
"${PROJECT_SOURCE_DIR}/lib1"
)
add_library(lib2 INTERFACE)
if(MSVC)
add_custom_target(lib2.headers SOURCES lib2.h)
endif()
target_include_directories(lib2 INTERFACE
"${PROJECT_SOURCE_DIR}/lib2"
)
target_link_libraries(lib2 INTERFACE lib1)
add_executable(project main.cc)
target_link_libraries(project lib2)
Advanced tip: you can specify a different directory in target_include_directories
for the build tree and the install tree (see documentation):
target_include_directories(lib1 INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/lib1>
$<INSTALL_INTERFACE:${YOUR_INSTALL_DIR}/lib1>
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With