21

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?

3
  • Can't you just list your headers in add_executable and remove all add_library? Commented Oct 6, 2016 at 6:38
  • One thing that seems odd in your source code and could explain the problem: target_include_directories() is only for directories that contain header files. So it should be target_include_directories(lib2 INTERFACE ../lib1). Commented Oct 6, 2016 at 6:59
  • Thanks for all the comments! Commented Oct 6, 2016 at 18:26

3 Answers 3

29

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>
)
Sign up to request clarification or add additional context in comments.

3 Comments

target_sources shouldn't be needed since target is of type "INTERFACE", and isn't compiled by itself. Passing sources directly to add_library even gives the following error: add_library INTERFACE library requires no source arguments.
BTW target_sources is also needed for sources to be visible in Projects pane of QtCreator IDE easily.
I'm using cmake 3.5.1 and for the line target_link_libraries(lib2 lib1) I get this error INTERFACE library can only be used with the INTERFACE keyword of target_link_libraries I guess it means lib2 by the interface library here. I can get past this error if I add the INTERFACE keyword in the target_link_libraries command before lib1. target_link_libraries(lib2 INTERFACE lib1)
5

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.

1 Comment

I still can't understand how do other solutions work and would prefer empty cpp again
3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.