CMake: target_include_directories() печатает ошибку, когда я пытаюсь добавить исходный каталог сам или один из его подкаталогов

Я пишу библиотеку С++ (только для заголовка) и использую CMake для создания моего проекта (Visual Studio) и файлов решений. Я также пишу тестовый набор, который является частью одного и того же проекта CMake.

Моя проблема возникает, когда я вызываю target_include_directories() в целевой объект, который представляет мою библиотеку только для заголовка, так что пользователи моей библиотеки могут найти свои файлы заголовков. Я получаю следующее сообщение об ошибке (даже если генерация не отменена).

CMake Error in CMakeLists.txt:
  Target "Fonts" INTERFACE_INCLUDE_DIRECTORIES property contains path:

    "D:/Projects/GPC/fonts/include"

  which is prefixed in the source directory.

(D:/Projects/GPC/Fonts - это каталог верхнего уровня моего проекта библиотеки. Btw проблема остается, если я перемещаю файлы заголовков в верхний каталог.)

Строка оскорбления в моем CMakeLists.txt - это (адаптировано для простоты):

target_include_directories(Fonts INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")

Я не понимаю, что я делаю неправильно. Без target_include_directories() код потребительских проектов просто не может включать мои файлы заголовков (если только в установленной форме, но я еще не дошел до этого, и в любом случае я хочу иметь возможность использовать мою библиотеку из дерева сборки, без установки.)

Я чувствую, что мне не хватает чего-то основного здесь; но я искал часы, не найдя решения или объяснения.

Ответ 1

Происхождение проблемы - это не сама команда target_include_directories, а попытка install целевой, которая имеет общий или интерфейс, включать в себя каталог, префикс в путь источника.

В то время как совершенно бесплатно и желательно использовать абсолютные пути при создании библиотеки с нуля, сторонняя библиотека, которая втягивает в предварительно созданную версию этой библиотеки, вероятно, захочет использовать другой путь include. В конце концов, вы не хотите, чтобы все ваши пользователи зеркалировали структуру каталогов вашей машины сборки, чтобы закончить путь справа.

Механизм упаковки CMake обеспечивает поддержку обоих этих вариантов использования: вы можете вытащить библиотеку непосредственно из дерева сборки (то есть проверить источник, построить его и точку find_package() в каталог) или из установочного каталога (запустите make INSTALL, чтобы скопировать встроенные файлы в каталог установки и указать find_package() в этот каталог). Последний подход должен быть перемещаемым (т.е. Я строю и устанавливаю на свою машину, отправляю вам результирующий каталог, и вы сможете использовать его на своем компьютере из другой структуры каталогов), в то время как первая не является.

Это очень аккуратная функция, но вы должны учитывать ее при настройке каталогов include. Указание руководства для target_include_directories:

Включение требований к использованию каталогов обычно различается между build-tree и установочное дерево. BUILD_INTERFACE и INSTALL_INTERFACE выражения генератора могут использоваться для описания отдельные требования к использованию, основанные на местоположении использования. Относительный пути допускаются в выражении INSTALL_INTERFACE и интерпретируется относительно префикса установки. Например:

target_include_directories(mylib PUBLIC  
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>  
    $<INSTALL_INTERFACE:include/mylib>  # <prefix>/include/mylib
)

BUILD_INTERFACE и INSTALL_INTERFACE выражения генератора делают все волшебство:

$<INSTALL_INTERFACE:...>

Содержимое ..., когда свойство экспортируется с помощью install(EXPORT), и пустым в противном случае.

$<BUILD_INTERFACE:...>

Содержимое ..., когда свойство экспортируется с помощью export(), или когда цель используется другой целью в одной и той же сборке. Расширяется до пустой строки в противном случае.