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?

rocambille
  • 15,398
  • 12
  • 50
  • 68
X. Liu
  • 213
  • 1
  • 2
  • 5
  • Can't you just list your headers in `add_executable` and remove all `add_library`? – arrowd Oct 06 '16 at 06: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)`. – Florian Oct 06 '16 at 06:59
  • Thanks for all the comments! – X. Liu Oct 06 '16 at 18:26

3 Answers3

28

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>
)
starball
  • 20,030
  • 7
  • 43
  • 238
rocambille
  • 15,398
  • 12
  • 50
  • 68
  • 2
    `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.` – helmesjo Jun 13 '17 at 18:39
  • BTW `target_sources` is also needed for sources to be visible in *Projects* pane of *QtCreator* IDE easily. – Tomilov Anatoliy May 18 '18 at 11:15
  • 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)` – Mohammed Safwat Jul 16 '18 at 08:52
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.

  • I still can't understand how do other solutions work and would prefer empty cpp again – IC_ Apr 08 '20 at 13:44
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.

Pankaj Misra
  • 143
  • 1
  • 13