Заставить CMake использовать абсолютный путь включения

У меня есть проект, макет каталога которого выглядит так:

- src/ #Contains main source code
- ext/ #Contains external libraries and headers from GitHub
- CMakeLists.txt

Проблема в том, что независимо от того, что я делаю, CMake всегда передает ext/ компилятору как относительный путь, например:

/usr/bin/c++ -I../ext mysrc.cpp

Я пробовал делать оба:

include_directories("${PROJECT_SOURCE_DIR}/ext")
include_directories("/home/user/project/ext")

Но это не имеет значения. Каталог всегда передается -I как ../ext.

Почему это важно? В конце моей сборки я вызываю gcov -r <source file>, который сообщает gcov генерировать отчеты о покрытии из моего исходного файла и любых относительных путей, найденных внутри. В результате gcov заходит в ext/ и генерирует отчеты для кучи вещей, которые меня не волнуют, и это занимает много времени. Если бы вместо этого CMake передал -I/home/user/project/ext, то gcov -r проигнорировал бы все в ext/.

Насколько я могу судить по: https://cmake.org/cmake/help/v3.13/command/include_directories.html ... это невозможно, но, может быть, я просто что-то упускаю?

Изменить: похоже, это проблема именно с генератором ninja. При использовании генератора Unix Makefiles все передается по абсолютным путям.

https://gitlab.kitware.com/cmake/cmake/issues/18666

Редактировать2:

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

person Gillespie    schedule 01.12.2018    source источник
comment
Хорошо, если это ошибка в генераторе ниндзя CMake, которая преобразует абсолютные пути в относительные пути, думали ли вы об использовании вместо этого генератора Makefile в качестве временного обходного пути. Возможно, вы захотите сообщить, что ошибка все еще остается проблемой в используемой вами версии cmake.   -  person fdk1342    schedule 02.12.2018
comment
На самом деле я не могу воспроизвести эту проблему, используя cmake 3.13. build.ninja всегда использует абсолютный путь для директивы -I.   -  person fdk1342    schedule 02.12.2018
comment
Я еще не пробовал 3.13, но если это так, у меня будет обратная проблема! В основном я хочу, чтобы пути в src/ были относительными, но пути в ext были абсолютными, чтобы gcov игнорировал внешние исходные файлы и вычислял покрытие только для моих относительных исходных файлов.   -  person Gillespie    schedule 02.12.2018
comment
Обычно cmake делает все пути абсолютными при создании файлов проекта. Вот почему вы не можете перемещать вещи после создания проекта. Например, если build и source оба являются подкаталогами ~/example, и вы переименовываете example в actual, вы больше не сможете использовать проекты в build.   -  person fdk1342    schedule 02.12.2018
comment
Я не смог воспроизвести с помощью 3.13. Какая у тебя версия ниндзя?   -  person Gillespie    schedule 02.12.2018
comment
Я не считаю, что это так. В последних версиях ninja и cmake все пути включения являются относительными в Ubuntu 18.   -  person Gillespie    schedule 02.12.2018
comment
Ubuntu 14.04/cmake 3.13/ниндзя 1.3.4. Запуск ninja -v показывает абсолютные пути для исходных файлов и для каталогов включения, как я и ожидал, основываясь на содержимом файла build.ninja, созданного cmake.   -  person fdk1342    schedule 02.12.2018
comment
Я предполагаю, что вы должны вызывать cmake либо из исходного каталога, либо из одного из его подкаталогов. Это, как вы знаете, прослушивается (ссылка теперь отсутствует в вашем сообщении) и использует относительные пути вместо абсолютных путей. Попробуйте построить в другом месте (я всегда слышал, что это рекомендуемый метод). По крайней мере, для меня это использование абсолютных путей.   -  person fdk1342    schedule 02.12.2018
comment
Нет, я делаю сборки вне исходников, как вы описываете. Можешь обновить ниндзя до 1.8 и попробовать еще раз?   -  person Gillespie    schedule 02.12.2018
comment
Если содержимое build.ninja неверно и имеет относительные пути, это проблема cmake. Вам нужно будет опубликовать минимальный пример, который воспроизводит проблему. Также опубликуйте, если возможно, что происходит, когда вы запускаете ninja -v, чтобы продемонстрировать, что относительные пути используются в командной строке. Если ninja преобразует полные пути в относительные, это проблема ninja.   -  person fdk1342    schedule 02.12.2018
comment
Давайте продолжим обсуждение в чате.   -  person Gillespie    schedule 02.12.2018


Ответы (1)


В примере показано, что можно считать сборкой из исходного кода. Это когда каталог сборки тот же или подкаталог папки src (не то, чтобы было жесткое определение или что-то еще, но это вызывает проблему ниндзя с использованием относительных путей в командной строке). Попробуйте mkdir ~/cmake_build && cd ~/cmake_build && cmake ~/cmake_test, тогда он должен использовать абсолютные пути для всего.

В любом случае, на самом деле нет конкретного способа заставить одно или другое. Как правило, генераторы cmake будут использовать абсолютные пути для всего, что в конечном итоге используется в командной строке. Похоже, что в Ninja есть проблемы, из-за которых генератор не может использовать абсолютные пути для сборок в исходном коде (https://github.com/ninja-build/ninja/issues/1251).

person fdk1342    schedule 03.12.2018
comment
Я не считаю это сборкой из исходного кода, но я считаю ваше предложение сборкой вне проекта, так что, возможно, в этом и заключается разница. В любом случае я не хочу абсолютные пути включения для всего — мне нужны абсолютные пути включения для кода, который я не хочу анализировать на предмет охвата, и относительные пути для всего остального. Похоже на ограничение CMake, поэтому я поднял вопрос. Спасибо за ваш вклад - person Gillespie; 03.12.2018
comment
В случае с Ninja, я думаю, они говорят об исходном дереве. Что касается cmake, здесь есть соответствующая ссылка о том, почему это работает именно так. gitlab.kitware.com/cmake/community/wikis/ - person fdk1342; 03.12.2018
comment
Однако это не исходный код, потому что мои исходные каталоги не содержат никаких артефактов сборки после завершения сборки. Сборка в исходном коде означает, что ваши исходные каталоги будут содержать .o файлов, например, после запуска сборки afaik. - person Gillespie; 03.12.2018
comment
Каждый раз, когда я слышу фразу «сборки в исходном коде и вне исходного кода», это относится к дереву каталогов. Таким образом, любая папка сборки, которая является подкаталогом корня исходного кода, будет частью дерева исходных каталогов. Но это всего лишь общая концепция. Проблема Ninja была связана с папкой сборки, которая находится в структуре подкаталогов исходного корня. Что мы можем видеть на этом конкретном примере. В любом случае cmake не работает так, как вы хотите. Почему бы вам не попробовать использовать gcov -s и просто начать исключать все, что вам не нужно? - person fdk1342; 03.12.2018
comment
Можете ли вы привести пример оператора gcov -s, который исключает заголовки ext/ и /usr/include? Похоже, что -s нельзя использовать так, как вы описываете. -s просто для того, чтобы имена файлов выглядели красивее, обрезав /some/long/path/leading/up/to/source.h -> source.h. Насколько я знаю, -r - это единственный способ для gcov выполнить упреждающую фильтрацию файлов для обработки. - person Gillespie; 03.12.2018
comment
Я не читал руководство таким образом об опции -s. Но я попробовал, и вы правы. Вместо этого можно попробовать gcovr и попробовать параметры исключения (вместе с параметром задания). Может быть, он будет работать быстрее, чем gcov. - person fdk1342; 04.12.2018
comment
К сожалению, gcovr - это просто оболочка для gcov, поэтому он может быть только медленнее (помимо распараллеливания - но я уже запускаю несколько процессов gcov). Я ценю ваши предложения, хотя. Похоже, cmake или gcov потребуется улучшение функций, чтобы получить ускорение, которое я ищу. - person Gillespie; 04.12.2018