5

My project is organized in subdirectories (a dozen), there are some includes between subdirectories. Some of these subdirectories contains only header files (dir1 for example).

Here is a look at the organization of the project:

project
 |
 |----- src -- dir1  <-- header-only library
 |       |      |--- dir1.h
 |       |      |--- CMakeLists.txt
 |       |
 |       |
 |       | --- dir2
 |       |      |--- dir2.cpp
 |       |      |--- dir2.h
 |       |      |--- CMakeLists.txt
 |       |
 |       | --- file.h
 |       | --- CMakeLists.txt 
 |
 |
 |----- test -- dir1 -- test.cpp
 |       | ---- dir2 -- test.cpp
 |       | ---- includeFile.h
 |
 |
 |----- CMakeLists.txt

I want to have a library containing all the code from src directory and an executable to run unit tests. After some research on stackOverFlow and Cmake examples, I arrived to these CMake files. There is one makefile per src subdirectories, one for grouping all the library and one global.

dir1 CMakeLists

add_library(dir1 INTERFACE)
target_sources(dir1 INTERFACE dir1.h)
target_include_directories(dir1 INTERFACE
  "${PROJECT_SOURCE_DIR}/src/dir1"
)

dir2 CMakeLists

set(dir2_src
  dir2.cpp dir2.h
)

add_library(dir2 ${dir2_src})

src CMakeLists

add_subdirectory(dir1)
add_subdirectory(dir2)


add_library(TheProject INTERFACE)
target_sources(TheProject INTERFACE file.h)
target_include_directories(TheProject INTERFACE
  "${PROJECT_SOURCE_DIR}/src/"
)
target_link_libraries(TheProject INTERFACE dir1
                                dir2
                                ${Boost_LIBRARIES})

main CMakeLists.txt

project(TheProject)

# gtest
# boost
# compilation flags ...

####### include paths
include_directories("./src/")
include_directories(${Boost_INCLUDE_DIRS})

####### library to compile
add_subdirectory(src)


####### executable
file(GLOB SRCS utest/*/*.cpp)
add_executable(utest ${SRCS} test/includeFile.h)

target_link_libraries(utest gtest_main TheProject)

I almost used the same organization on a smaller project without header only libraries and INTERFACE and it worked. Here, I have an error with the different interface libraries:

CMake Error at CMakeLists.txt:88 (add_executable):
  Cannot find source file:

    file.h

  Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
  .hxx .in .txx

I think I have not well understood the use of INTERFACE. I have done some research but nothing solve my problem.

And I have also a few questions:

  • There is some dependancies between directories, (e.g. code in dir1 has an include of some dir2 files), should I specify these dependance in their cmake file (with target_link_libraries(dir2 dir1)) ?
  • In the code, include are specified with relative paths in src and utest, is it not better to use paths like "dir1/dir1.h"?
1
  • is it not better to use paths like "dir1/dir1.h"? - It is fully up to you. While different "public" files has different names (from #include directive), everything is OK. There is some dependancies between directories ..., should I specify these dependance in their cmake file? - Most likely, you needn't to care about these dependencies. There is no such thing in CMake like "dependencies between directories": CMake only tracks files. Also, if some header file will change, the executable which uses it will be rebuilt on next make invocation. Commented Apr 24, 2018 at 9:24

2 Answers 2

13

Before CMake 3.13 relative paths, passed to target_sources, are interpreted relative to further invocations of add_executable (or add_library).

Because you call add_executable() from the top directory, CMake searches test.h relative to the top directory, not relative to the src/ one.

Use absolute paths for target_sources calls:

target_sources(TheProject INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/file.h)

Since CMake 3.13 relative paths passed to target_sources are resolved immediately, relative to the current source directory. See @markhc's answer.

Sign up to request clarification or add additional context in comments.

1 Comment

This behavior was changed on CMake 3.13, see my answer below.
6

As an addon to Tsyvarev answer to anyone that comes across this from google, the behavior for target_sources was changed on CMake 3.13.

You can now use relative paths in target_sources calls.

https://cmake.org/cmake/help/v3.13/command/target_sources.html

Relative source file paths are interpreted as being relative to the current source directory

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.