I have a project whose directory layout looks like:
- src/ #Contains main source code
- ext/ #Contains external libraries and headers from GitHub
- CMakeLists.txt
The problem is that no matter what I do, CMake always seems to pass ext/
to the compiler as a relative path, like this:
/usr/bin/c++ -I../ext mysrc.cpp
I've tried doing both:
include_directories("${PROJECT_SOURCE_DIR}/ext")
include_directories("/home/user/project/ext")
But it doesn't seem to matter. The directory is always passed to -I
as ../ext
.
Why does this matter? At the end of my build I invoke gcov -r <source file>
which tells gcov to generate coverage reports from my source file and any relative paths found within. As a result, gcov is going into ext/
and generating reports for tons of stuff I don't care about and it's taking up a lot of time. If CMake would instead pass in -I/home/user/project/ext
then gcov -r
would ignore everything in ext/
.
As far as I can tell from: https://cmake.org/cmake/help/v3.13/command/include_directories.html ... this isn't possible, but maybe I'm just missing something?
Edit: This appears to be a problem with specifically the ninja
generator. When using the Unix Makefiles
generator, everything is passed via absolute paths.
https://gitlab.kitware.com/cmake/cmake/issues/18666
Edit2:
user@antimony:~/cmake_test$ ls
CMakeLists.txt ext src
user@antimony:~/cmake_test$ cat CMakeLists.txt
project(Hello)
add_subdirectory(src)
user@antimony:~/cmake_test$ cat src/CMakeLists.txt
include_directories(
.
${PROJECT_SOURCE_DIR}/ext
)
add_executable(hello_world hello.cpp)
user@antimony:~/cmake_test$ cat src/hello.cpp
#include <useless.h>
int main()
{
hello h;
return 0;
}
user@antimony:~/cmake_test$ cat ext/useless.h
struct hello {
int x;
};
user@antimony:~/cmake_test$ ~/Downloads/cmake-3.13.1-Linux-x86_64/bin/cmake --version
cmake version 3.13.1
CMake suite maintained and supported by Kitware (kitware.com/cmake).
user@antimony:~/cmake_test$ mkdir build && cd build
user@antimony:~/cmake_test/build$ ~/Downloads/cmake-3.13.1-Linux-x86_64/bin/cmake .. -G Ninja
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
...
-- Build files have been written to: /home/user/cmake_test/build
user@antimony:~/cmake_test/build$ ninja -v
[1/2] /usr/bin/c++ -I../src/. -I../ext -MD -MT src/CMakeFiles/hello_world.dir/hello.o -MF src/CMakeFiles/hello_world.dir/hello.o.d -o src/CMakeFiles/hello_world.dir/hello.o -c ../src/hello.cpp
[2/2] : && /usr/bin/c++ -rdynamic src/CMakeFiles/hello_world.dir/hello.o -o src/hello_world && :
user@antimony:~/cmake_test/build$ cat build.ninja
# CMAKE generated file: DO NOT EDIT!
# Generated by "Ninja" Generator, CMake Version 3.13
# This file contains all the build statements describing the
# compilation DAG.
...
#############################################
# Order-only phony target for hello_world
build cmake_object_order_depends_target_hello_world: phony || src/CMakeFiles/hello_world.dir
build src/CMakeFiles/hello_world.dir/hello.o: CXX_COMPILER__hello_world ../src/hello.cpp || cmake_object_order_depends_target_hello_world
DEP_FILE = src/CMakeFiles/hello_world.dir/hello.o.d
INCLUDES = -I../src/. -I../ext
OBJECT_DIR = src/CMakeFiles/hello_world.dir
OBJECT_FILE_DIR = src/CMakeFiles/hello_world.dir
TARGET_COMPILE_PDB = src/CMakeFiles/hello_world.dir/
TARGET_PDB = src/hello_world.pdb
# =============================================================================
# Link build statements for EXECUTABLE target hello_world
The example shows what may be considered an in-source build. That is when the build directory is the same or a sub-directory of the src folder (not that there is a hard definition or anything, but this does trigger the ninja issue of using relative paths on the command line). Try mkdir ~/cmake_build && cd ~/cmake_build && cmake ~/cmake_test
then it should use absolute paths for everything.
Either way there really isn't a specific way to force one or the other. In general cmake generators will use absolute paths for everything that ends up used on the command line. There seems to be issues with Ninja that prevent the generator from using absolute paths for in-source builds (https://github.com/ninja-build/ninja/issues/1251).