简体   繁体   中英

How to create a cmake header-only library that depends on external header files?

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?

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>
)

I've used an empty _only_for_compiling_the_lib.cpp file as the simplest and fastest workaround, but clearly the above solution is strongly advised.

I simply wasn't aware of INTERFACE keyword.

This problem was due to full path issue of INTERFACE library files, which got fixed in cmake version 3.13.

For more info: https://gitlab.kitware.com/cmake/cmake/issues/17556

This page also contains an example for better understanding.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM