Як правильно додати включити каталоги з CMake


243

Близько року тому я запитав про залежності заголовка в CMake .

Нещодавно я зрозумів, що проблема, здавалося, полягає в тому, що CMake вважає ці заголовкові файли зовнішніми для проекту. Принаймні, при створенні проекту Code :: Blocks заголовні файли не відображаються в проекті (це роблять вихідні файли). Тому мені здається, що CMake вважає ці заголовки зовнішніми до проекту, і не відстежує їх у залежності.

Швидкий пошук у підручнику CMake лише вказав на те, include_directoriesщо, здається, не робить те, що я хочу ...

Який правильний спосіб повідомити CMake, що певний каталог містить заголовки, які слід включити, і що ці заголовки повинні відслідковуватися створеним Makefile?


Внесення змін до цього питання робить його заплутаним. Оригінальне запитання та відповіді полягали у тому, як відстежувати файли заголовків у IDE. Це сильно відрізняється від створених залежностей файлу заголовка Makefile відсутній та способів вирішення цієї проблеми.
fdk1342

@Fred: Я поняття не маю, про що ти говориш. Як видно з редакції редакції, останнє речення завжди було там. З цього питання було внесено лише косметичні зміни, і жодне слово не було введено (або видалено).
Матьє М.

Тоді це моє непорозуміння. Мені це виглядало сподобалось, додано цілий абзац. stackoverflow.com/questions/13703647/… говорить, що загальним розумінням було те, як перелічити файл заголовка в IDE. Це стосується .cbpфайлу проекту. Тепер, якщо сканер залежності cmake не зможе правильно визначити файл заголовка як залежність для Makefile, існують способи виправити це, але в деяких випадках він помилиться, оскільки не містить повного препроцесора.
fdk1342

Відповіді:


267

Дві речі треба зробити.

Спочатку додайте каталог, який потрібно включити:

target_include_directories(test PRIVATE ${YOUR_DIRECTORY})

Якщо у вас залишилася дуже стара версія CMake (2.8.10 або пізніша версія) без підтримки target_include_directories, ви також можете використовувати спадщину include_directoriesзамість цього:

include_directories(${YOUR_DIRECTORY})

Потім ви також повинні додати файли заголовків до списку вихідних файлів для поточної цілі, наприклад:

set(SOURCES file.cpp file2.cpp ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)
add_executable(test ${SOURCES})

Таким чином, файли заголовків будуть відображатися як залежності в Makefile, а також, наприклад, в створеному проекті Visual Studio, якщо ви генеруєте такий.

Як використовувати ці файли заголовків для кількох цілей:

set(HEADER_FILES ${YOUR_DIRECTORY}/file1.h ${YOUR_DIRECTORY}/file2.h)

add_library(mylib libsrc.cpp ${HEADER_FILES})
target_include_directories(mylib PRIVATE ${YOUR_DIRECTORY})
add_executable(myexec execfile.cpp ${HEADER_FILES})
target_include_directories(myexec PRIVATE ${YOUR_DIRECTORY})

Ах! Я знав, що це повинно бути щось дурне. Дійсно, я не перераховував заголовки ... Чи потрібно мені перераховувати заголовки саме цієї бібліотеки, а також усі заголовки, від яких це може залежати (на додаток до оголошення залежності від бібліотеки)? Це зростаючий проект, і я дуже боявся ідеї додавання заголовка до всіх залежностей, коли я додаю його в кореневу бібліотеку.
Матьє М.

Для кращого відстеження залежностей (наприклад, щоб переконатися, що зміна файлу заголовка запускає компіляцію для всіх уражених цілей), так. Однак ви можете використовувати cmake змінні для переліку файлів заголовків лише один раз і використовувати їх у кількох місцях, див. Мою редагування.
SirDarius

1
Моє запитання було більше в тому сенсі, що у мене є кілька бібліотек, які залежать одна від одної: libroot, liba залежить від libroot, libb залежить від libroot. Чи можу я використовувати LIBROOT_HEADER_FILESзмінну в, liba/CMakefileа libb/CMakefileпотім?
Матьє М.

2
Це неправильно, ви ніколи не повинні використовувати include_directoriesбільше target_include_directories. Перший встановлює його рекурсивно для всіх цілей у цьому каталозі; тоді як останній встановлює це як мета. Виконання попереднього розбиває поняття цільового графа в CMake, а натомість покладається на побічні ефекти для вашої ієрархії файлів.
Енді

1
Я відредагував відповідь, щоб відобразити поточне поняття про перевагу target_include_directoriesсучасного коду CMake. Не соромтесь запросити мене до чату, якщо ви не погоджуєтесь із змінами.
ComicSansMS

74

По-перше, ви використовуєте include_directories()для того, щоб сказати CMake, щоб додати каталог як -Iдо командного рядка компіляції. По-друге, ви перераховуєте заголовки у своєму add_executable()або add_library()зателефонуйте.

Наприклад, якщо джерела вашого проекту є src, і вам потрібні заголовки include, ви можете зробити це так:

include_directories(include)

add_executable(MyExec
  src/main.c
  src/other_source.c
  include/header1.h
  include/header2.h
)

19
Вам справді потрібно додати заголовки add_executable? Я подумав, що CMake зрозумів, що включати залежності файлів автоматично.
Колін Д Беннетт

57
@ColinDBennett Вам не доведеться їх перераховувати з причин залежності - CMake розраховує, що будувати залежності просто добре, якщо цього не потрібно. Але якщо ви перерахуєте їх, вони вважатимуться частиною проекту, і вони будуть такими, як такі, в IDE (що було темою питання).
Ендже вже не пишається SO

Принаймні для QtCreator не потрібно додавати class.h у випадку, якщо існує class.cpp. До джерела потрібно додати лише lonely.h. Дивіться підручник на веб-
Th. Тілеманн

19

CMake більше схожий на мову скрипта, якщо порівнювати його з іншими способами створення Makefile (наприклад, make або qmake). Це не дуже круто, як Python, але все ж.

Не існує такого поняття, як " правильний спосіб ", якщо в різних проектах з відкритими джерелами дивитися, як люди включають каталоги. Але це можна зробити двома способами.

  1. Неочищені include_directories додадуть каталог до поточного проекту та всіх інших нащадків, які ви додасте за допомогою ряду команд add_subdirectory . Іноді люди кажуть, що такий підхід є спадщиною.

  2. Більш елегантний спосіб - за допомогою target_include_directories . Це дозволяє додавати каталог для конкретного проекту / цілі без (можливо) зайвого успадкування або зіткнення різних каталогів, що включають. Дозвольте також виконати навіть тонку конфігурацію і додати один із наступних маркерів для цієї команди.

PRIVATE - використовувати лише для цієї заданої цілі збірки

PUBLIC - використовуйте її для визначеної цілі та для цілей, які пов'язують цей проект

ІНТЕРФЕЙС - використовуйте його лише для цілей, які пов'язані з поточним проектом

PS:

  1. Обидві команди дозволяють позначати каталог як СИСТЕМА, щоб натякнути, що вказані каталоги будуть містити попередження не у вашому бізнесі.

  2. Аналогічна відповідь - з іншими парами команд target_compile_definitions / add_definitions , target_compile_options / CMAKE_C_FLAGS


13

Додайте include_directories("/your/path/here").

Це буде схоже на дзвінки gccз -I/your/path/here/опцією.

Обов’язково поставте подвійні лапки навколо шляху. Інші люди не згадували про це, і це змусило мене застрягти 2 дні. Тож ця відповідь призначена для людей, які є новинкою CMake і дуже розгублені.


7

У мене була така ж проблема.

Мій каталог проекту був такий:

    --project
    ---Classes
    ----Application
    -----.h and .c files
    ----OtherFolders
    --main.cpp

І що я використовував для включення файлів у всі ці папки:

    file(GLOB source_files
            "*.h"
            "*.cpp"
            "Classes/*/*.cpp"
            "Classes/*/*.h"
    )

    add_executable(Server ${source_files})

І це повністю спрацювало.


Пам'ятаючи, що cmake - це "генератор системи побудови", а не "система побудови", використовуючи файловий глобус, не є хорошою ідеєю в сучасному cmake (CMake з версіями 3.0 і вище), тому що кульові файли оцінюються під час "побудови", а не "побудови" час генерації системи. Дивіться посилання: gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1
ggulgulia
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.