Генераторами называются компоненты инструмента CMake, отвечающие за создание проектов для конечных систем построения. Для каждой поддерживаемой системы (make, Microsoft Visual Studio определенной версии и т.д.) существует свой генератор. Выбор конкретного генератора задаётся в командной строке CMake при помощи ключа "-G".
$ cmake -G "Visual Studio 14 2015" ..\project_src
Полный список имён поддерживаемых генератором для данной версии можно узнать при помощи команды:
$ cmake --help
Ключ "-A" позволяет указать целевую платформу (ARM, x64, и т.д.)
Входными файлами для программы CMake являются файлы CMakeLists.txt, лежащие в корне каталога проекта (с файлами исходных кодов). Путь к каталогу проекта предаётся инструменту CMake в качестве последнего аргумента командной строки. Крупные проекты могут также содержать подкаталоги с проектами нижнего уровня, каждый из которых будет иметь в корне свой файл CMakeLists.txt Кроме файлов CMakeLists.txt также могут использоваться файлы с расширением ".cmake". Эти файлы могут подключаться из программы на языке CMake при помощи директивы include(...), вызываться при исполнении команды find_package(...) (модули поиска или конфигурационные файлы) или передаваться инструменту CMake для исполнения при помощи ключа "-P"
# - Однострочный комментарий.
#[[ ]] - Блочный комментарий.
Команда cmake_minimum_required(...) определяет минимальную версию инструмента CMake, при помощи которого можно обрабатывать текущий входной файл проекта. Аргумент {версия} может содержать до 4 чисел, разделенных точками. Команду cmake_minimum_required(...) рекомендуется указывать самой первой в файле CMakeLists.txt верхнего уровня.
cmake_minimum_required(VERSION {версия} [FATAL_ERROR])
Команда project(...) устанавливает имя для иерархии проектов. Например, для генераторов Microsoft Visual Studio это имя определяет имя создаваемого решения.
project({имя_проекта} [VERSION {версия}] [LANGUAGES {язык1} ... {языкN}])
- После аргумента VERSION можно указать версию проекта - строку, содержащую до 4 чисел, разделенных точками. Установка версии проекта доступна в CMake начиная с версии 3.0.
- После необязательного аргумента LANGUAGES указываются языки программирования, для которых обеспечивается поддержка в проекте.
Команда include(...) загружает из внешнего файла и исполняет заданный модуль CMake. Модуль может задаваться при помощи пути к файлу, либо только именем модуля (без пути и расширения). В последнем случае файл с именем {модуль}.cmake ищется в каталогах, список которых задан переменной CMAKE_MODULE_PATH (по умолчанию пустая), и затем в каталоге стандартных модулей, поставляемых вместе с CMake.
include({файл} | {модуль} [OPTIONAL] [RESULT_VARIABLE {имя_переменной}])
Команда message(...) предназначена для вывода сообщения различными утилитами, интерпретирующими входной файл.
message([{режим}] {строка1} ... {строка2})
{режим} = STATUS | WARNING | AUTHOR_WARNING | SEND_ERROR | FATAL_ERROR | DEPRECATION
Команда add_executable(...) добавляет к проекту цель с заданным логическим именем, построение которой из указанных исходных модулей должно привести к созданию исполняемого файла.
add_executable({логическое_имя_цели} [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] {исходный_модуль1} ... {исходный_модульN})
Изменить имя можно при помощи установки свойства OUTPUT_NAME цели.
set_property(TARGET {имя_цели} PROPERTY OUTPUT_NAME {имя_выходного_файла})
CMAKE_RUNTIME_OUTPUT_DIRECTORY содержит имя подкатолога построения. Использование аргумента WIN32 приведёт к отключению консоли при построении на платформе Windows. Для остальных платформ этот аргумент игнорируется. Передача аргумента EXCLUDE_FROM_ALL приведет к тому, что генерируемая цель будет исключена из цели "all".
Первая форма команды add_library(...) аналогична команде add_executable(...), но создаёт цель для построения библиотеки.
add_library({логическое_имя_цели} [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] {исходный_модуль1} ... {исходный_модульN})
add_library({логическое_имя_цели} {тип_библиотеки = SHARED | STATIC | MODULE | UNKNOWN} IMPORTED)
Тип библиотеки можно задать при помощи необязательного аргумента:
- STATIC: статическая;
- SHARED: динамическая (разделяемая);
- MODULE: разделяемая, предназначенная исключительно для загрузки при помощи функций API (POSIX dlopen() и т.п.). Такой тип библиотеки используется для реализации загружаемых модулей (plugins).
Изменить расположение библиотеки можно при помощи соответствующих свойств цели, которые инициализируются значениями специальных переменных:
Имя свойства | Тип библиотеки |
---|---|
CMAKE_ARCHIVE_OUTPUT_DIRECTORY | статические(+импорта) |
CMAKE_RUNTIME_OUTPUT_DIRECTORY | DLL |
CMAKE_LIBRARY_OUTPUT_DIRECTORY | модули, разделяемые |
Размещение библиотек в разных ОС стр. 85
Вторая форма команды add_library(...) предназначена для добавления к проекту внешней заранее собранной библиотеки (как правило, сторонней). Как и для предыдущей формы команды, создаётся цель с заданным логическим именем, которая по умолчанию имеет область видимости текущего каталога построения и ниже и которую можно использовать, как и остальные цели библиотек, для связывания с другими целями проекта при помощи команды target_link_libraries(...). Однако в этом случае не создаётся никаких правил построения библиотеки.
Чтобы указать местоположение файла библиотеки для создаваемой цели, необходимо записать его в свойство цели IMPORTED_LOCATION, а также в свойства IMPORTED_LOCATION_DEBUG и т.д. для каждой используемой конфигурации. Для получения пути к исполняемому файлу библиотеки можно использовать команду find_library(...).
Команда add_subdirectory(...) добавляет к построению подпроект, расположенный заданном подкаталоге. В нём должен находиться файл CMakeLists.txt с описанием подпроекта.
add_subdirectory({подкаталог_проекта} [{подкаталог_построения}] [EXCLUDE_FROM_ALL])
Имеет смысл указывать относительный путь к каталогу.
- При помощи необязательного аргумента {подкаталог_построения} можно указать подкаталог для выходных и промежуточных файлов проекта.
Команда include_directories(...) добавляет указанные каталоги к списку каталогов в которых компилятор должен искать заголовочные файлы, подключаемые директивами #include. Эти каталоги добавляются к соответствующему свойству всех целей, определенных в текущем файле CMakeLists.txt. Относительные пути интерпретируются по отношению к текущему каталогу исходных файлов проекта.
include_directories([AFTER | BEFORE] [SYSTEM] {каталог1} ... {каталогN})
- При помощи необязательного аргумента BEFORE или AFTER можно сообщить команде, что заданные в ней каталоги должны добавляться в начало или конец списка каталогов для поиска
- При помощи аргумента SYSTEM можно сообщить, что указанные каталоги являются системными (относящимися к компилятору).
Результат исполнения команды target_include_directories(...) аналогичен вызову команды include_directories(...), основные же отличия состоят в следующем:
- В аргументе команды указывается имя цели к которой она относится. Команда влияет на соответствующие свойства этой цели, в то время как команда include_directories(...)_ влияет на свойство каталога проекта (т.е. действует на все цели, определяемые в текущем подпроекте).
- Есть возможность указать, будут ли использованы указанные в аргументах команды каталоги для компиляции самой цели или для зависимых от неё целей.
target_include_directories({имя_цели} [SYSTEM] [BEFORE] INTERFACE | PUBLIC | PRIVATE [{каталог1,1} ... {каталог1,M}]
[
INTERFACE | PUBLIC | PRIVATE [{каталог2,1} ... {каталог2, n})
...
])
Перед путями к каталогам укзывается один из следующих аргументов:
- PRIVATE: каталоги будут использованы для поиска заголовочных файлов при компиляции файлов текущей цели (аналогично команде include_directories(...)).
- INTERFACE: каталоги будут использованы при компиляции файлов зависимых целей от текущей.
- PUBLIC: каталоги будут использованы при компиляции файлов как текущей цели, так и зависимых от неё целей (как будто они описаны одновременно как PRIVATE и INTERFACE) Таким образом, команда позволяет упростить подключение библиотек к исполяемым файлам.
Команда add_definitions(...) добавляет заданные определения символов препроцессора к свойствам текущего каталога и подчиненных (подключаемых при помощи команды add_subdirectory(...)). Определения символов должны быть в формате "-D{имя_символа}" или "/D{имя_символа}". Система CMake автоматически преобразует такие определния к аргументам командной строки, поддерживаемым используемым компилятором.
add_definitions({определение1} ... {определениеN})
# Пример
add_definitions(-DDEBUG -DEXTRA_TESTS)
При использовании в построении компилятора gcc ему будут переданы аргументы "-DDEBUG -DEXTRA_TESTS", а при использовании Microsoft Visual C++ - "/DDEBUG /DEXTRA_TESTS". После этого в компилируемых файлах препроцессором будут положительно обрабатываться директивы вида:
#ifdef EXTRA_TESTS
do_extra_tests();
#endif
Команда add_compile_options(...) позволяет передавать аргументы компилятору в неизменном виде.
add_compile_options({аргумент1} ... {аргументN})
Замечание: при передаче компилятору аргументов командной строки, отвечающих за некоторые часто используемые функции, вместо команды add_compile_options(...) предпочтительнее использовать другие команды, которые способны передавать компилятору аргументы в поддерживаемом формате:
- Для определения символов препроцессора с пустыми значениями предназначена команда add_definitions(...).
- Для передачи компилятору дополнительных путей поиска заголовочных файлов предназначена команда include_directories(...), которая оказывает влияние на свойства текущего каталога построения, а также команда _target_include_directories(...), которая определяет свойства отдельной цели.
- Для передачи компоновщику дополнительных библиотек используется команда target_link_libraries(...).
- Для передачи компилятору аргументов, делающих доступными возможности новых стандартов C и C++ используется команда target_compile_features(...).
- Для передачи компоновщику дополнительных путей поиска библиотек используется команда link_directories(...). Впрочем, в реальных ситуациях эта команда почти никогда не нужна, так как при добавлении библиотек от других целей или найденных при помощи команд find_library(...) и т.д. компоновщику будет передан путь к библиотеке.
Команда target_compile_definitions(...) аналогична команде add_definitions(...), однако позволяет добавлять определения символов препроцессора через командную вызовов компилятора не только для указанной цели, но и автоматические для всех целей, зависимых от данной, аналогично команде target_include_directories(...).
# CMake version >= 2.8.11
target_compile_definitions({имя_цели}
INTERFACE | PUBLIC | PRIVATE [{определение1,1} ... {определение1,M}]
[INTERFACE | PUBLIC | PRIVATE [{определение2,1} ... {определение2,N}]
...
])
Команда target_compile_options(...) аналогична команде add_compile_options(...), однако позволяет передавать аргументы компилятору не только для указанной цели, но и автоматически для всех целей, зависимых от данной, аналогично команде target_include_directories(...).
# CMake version >= 2.8.11
target_compile_options({имя_цели} [BEFORE]
INTERFACE | PUBLIC | PRIVATE [{аргумент1,1} ... {аргумент1,M}])
[INTERFACE | PUBLIC | PRIVATE [{аргумент2,1} ... {аргумент2,N}]
...
])
- При помощи необязательного аргумента BEFORE можно добавлять аргументы компилятора в начало их списка вместо конца (по умолчанию).
&&&
# CMake version >= 3.1.0
target_compile_features({имя цели} INTERFACE | PUBLIC | PRIVATE {возможность1} ... {возможностьN})
Команда target_link_libraries(...) предназначена для определения подключаемых библиотек к заданной цели или произвольных аргументов командной строки, передаваемых комоновщику.
target_link_libraries({имя_цели} [{строка1} ... {строкаN}]
[
[debug | optimized | general] {строка}
...
])
target_link_libraries({имя_цели} INTERFACE | PUBLIC | PRIVATE {строка1} ... {строкаM}
[
INTERFACE | PUBLIC | PRIVATE {строка1} ... {строкаN}
...
])
Замечание: имя цели должно быть определено в том же самом каталоге проекта, внутри описания которого вызывается эта команда. Команда определяет тип аргументов, начиная со второго по следующим правилам: стр. 106