Issue
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"?
Solution
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.
Answered By - Tsyvarev