cmake-buildsystem(7)
- Введение
- Бинарные цели
- Требования к спецификации сборки и использованию
- Псевдоцели
Введение
Система сборки на основе CMake организована как набор логических целей высокого уровня. Каждая цель соответствует исполняемому файлу или библиотеке, или является пользовательской целью, содержащей пользовательские команды. Зависимости между целями выражены в системе сборки для определения порядка сборки и правил перегенерации в ответ на изменения.
Бинарные цели
Исполняемые файлы и библиотеки определяются с помощью команд add_executable() и add_library(). Результирующие бинарные файлы имеют соответствующие префиксы, суффиксы и расширения для целевой платформы. Зависимости между бинарными целями выражаются с помощью команды target_link_libraries():
add_library(archive archive.cpp zip.cpp lzma.cpp) add_executable(zipapp zipapp.cpp) target_link_libraries(zipapp archive)
archive определена как статическая библиотека — архив, содержащий объекты, скомпилированные из archive.cpp, zip.cpp, и lzma.cpp. zipapp определена как исполняемый файл, сформированный путем компиляции и компоновки zipapp.cpp. При компоновке исполняемого файла zipapp, подключается статическая библиотека archive.
Бинарные исполняемые файлы
Команда add_executable() определяет исполняемую цель:
add_executable(mytool mytool.cpp)
Команды, такие как add_custom_command(), генерирующие правила, которые выполняются во время сборки, могут прозрачно использовать цель типа EXECUTABLE как исполняемый файл COMMAND. Правила системы сборки гарантируют, что исполняемый файл будет собран перед попыткой выполнения команды.
Типы бинарных библиотек
Обычные библиотеки
По умолчанию, команда add_library() определяет статическую библиотеку, если не указан тип. Тип можно указать при использовании команды:
add_library(archive SHARED archive.cpp zip.cpp lzma.cpp)
add_library(archive STATIC archive.cpp zip.cpp lzma.cpp)
Переменная BUILD_SHARED_LIBS может быть включена для изменения поведения команды add_library() на построение динамических библиотек по умолчанию.
В контексте определения системы сборки в целом, почти не имеет значения, являются ли конкретные библиотеки SHARED или STATIC — команды, спецификации зависимостей и другие API работают аналогично независимо от типа библиотеки. Тип библиотеки MODULE отличается тем, что обычно не подключается — он не используется в правой части команды target_link_libraries(). Это тип, который загружается как плагин с помощью методов времени выполнения. Если библиотека не экспортирует какие-либо необработанные символы (например, DLL ресурсов Windows, DLL C++/CLI), то она не должна быть библиотекой типа SHARED, потому что CMake ожидает, что библиотеки типа SHARED экспортируют по крайней мере один символ.
add_library(archive MODULE 7z.cpp)
Фреймворки Apple
Библиотека SHARED может быть помечена свойством цели FRAMEWORK для создания пакета фреймворка OS X или iOS. MACOSX_FRAMEWORK_IDENTIFIER устанавливает ключ CFBundleIdentifier и уникально идентифицирует пакет.
add_library(MyFramework SHARED MyFramework.cpp) set_target_properties(MyFramework PROPERTIES FRAMEWORK TRUE FRAMEWORK_VERSION A MACOSX_FRAMEWORK_IDENTIFIER org.cmake.MyFramework )
Библиотеки объектов
Тип библиотеки OBJECT также не подключается. Он определяет неархивный набор файлов объектов, полученных в результате компиляции заданных исходных файлов. Коллекция файлов объектов может использоваться как исходный ввод для других целей:
add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp) add_library(archiveExtras STATIC $<TARGET_OBJECTS:archive> extras.cpp) add_executable(test_exe $<TARGET_OBJECTS:archive> test.cpp)
Библиотеки OBJECT могут использоваться только локально как источники в системе сборки — они не могут быть установлены, экспортированы или использованы в правой части target_link_libraries(). Они также не могут использоваться как TARGET в использовании команды add_custom_command(TARGET).
Хотя библиотеки объектов не могут быть названы напрямую в вызовах команды target_link_libraries(), они могут быть «связаны» косвенно, используя библиотеку интерфейса, для которой свойство цели INTERFACE_SOURCES установлено для именования $<TARGET_OBJECTS:objlib>.
Требования к спецификации сборки и использованию
Команды target_include_directories(), target_compile_definitions() и target_compile_options() определяют спецификации сборки и требования к использованию бинарных целей. Команды заполняют свойства целей INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS и COMPILE_OPTIONS соответственно, или свойства целей INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_COMPILE_DEFINITIONS и INTERFACE_COMPILE_OPTIONS.
Каждый из команд имеет режим PRIVATE, PUBLIC и INTERFACE. Режим PRIVATE заполняет только не-INTERFACE_ вариант целевого свойства, а режим INTERFACE заполняет только INTERFACE_ варианты. Режим PUBLIC заполняет оба варианта соответствующего целевого свойства. Каждая команда может быть вызвана с использованием нескольких раз каждого ключевого слова:
target_compile_definitions(archive PRIVATE BUILDING_WITH_LZMA INTERFACE USING_ARCHIVE_LIB )
Обратите внимание, что требования к использованию не предназначены для того, чтобы сделать последующее использование конкретных COMPILE_OPTIONS или COMPILE_DEFINITIONS и т. д. для удобства только. Содержимое свойств должно быть требованиями, а не просто рекомендациями или удобством.
См. раздел Создание переносимых пакетов руководства cmake-packages(7) для обсуждения дополнительной осторожности, которая должна быть принята при указании требований к использованию при создании пакетов для распространения.
Свойства целей
Содержимое свойств цели INCLUDE_DIRECTORIES, COMPILE_DEFINITIONS и COMPILE_OPTIONS используются соответствующим образом при компиляции исходных файлов целевого бинарного файла.
Записи в INCLUDE_DIRECTORIES добавляются к строке компиляции с префиксами -I или -isystem в порядке их появления в значении свойства.
Записи в COMPILE_DEFINITIONS снабжены префиксами -D или /D и добавляются к строке компиляции в неопределенном порядке. Свойство цели DEFINE_SYMBOL также добавляется как определение компиляции в качестве специального удобного случая для SHARED и MODULE целевых библиотек.
Записи в COMPILE_OPTIONS экранируются для оболочки и добавляются в порядке их появления в значении свойства. Некоторые параметры компиляции имеют специальную отдельную обработку, например, POSITION_INDEPENDENT_CODE.
Содержимое свойств INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_COMPILE_DEFINITIONS и INTERFACE_COMPILE_OPTIONS целевых свойств являются Требованиями к использованию — они определяют содержимое, которое потребители должны использовать для правильной компиляции и линковки с целью, на которой они появляются. Для любой целевой программы бинарного типа содержимое каждого INTERFACE_ свойства на каждой цели, указанной в команде target_link_libraries(), используется:
set(srcs archive.cpp zip.cpp)
if (LZMA_FOUND)
list(APPEND srcs lzma.cpp)
endif()
add_library(archive SHARED ${srcs})
if (LZMA_FOUND)
# The archive library sources are compiled with -DBUILDING_WITH_LZMA
target_compile_definitions(archive PRIVATE BUILDING_WITH_LZMA)
endif()
target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)
add_executable(consumer)
# Link consumer to archive and consume its usage requirements. The consumer
# executable sources are compiled with -DUSING_ARCHIVE_LIB.
target_link_libraries(consumer archive)
Поскольку часто требуется, чтобы директория исходного кода и соответствующая директория сборки добавлялись в INCLUDE_DIRECTORIES, переменная CMAKE_INCLUDE_CURRENT_DIR может быть включена для удобного добавления соответствующих директорий в INCLUDE_DIRECTORIES всех целей. Переменная CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE может быть включена для добавления соответствующих директорий в INTERFACE_INCLUDE_DIRECTORIES всех целей. Это делает удобным использование целей в нескольких разных директориях с помощью команды target_link_libraries().
Переходные требования к использованию
Требования к использованию цели могут распространяться по цепочке зависимостей. Команда target_link_libraries() имеет ключевые слова PRIVATE, INTERFACE и PUBLIC для управления распространением.
add_library(archive archive.cpp) target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB) add_library(serialization serialization.cpp) target_compile_definitions(serialization INTERFACE USING_SERIALIZATION_LIB) add_library(archiveExtras extras.cpp) target_link_libraries(archiveExtras PUBLIC archive) target_link_libraries(archiveExtras PRIVATE serialization) # archiveExtras is compiled with -DUSING_ARCHIVE_LIB # and -DUSING_SERIALIZATION_LIB add_executable(consumer consumer.cpp) # consumer is compiled with -DUSING_ARCHIVE_LIB target_link_libraries(consumer archiveExtras)
Поскольку archive является PUBLIC зависимостью archiveExtras, требования к её использованию распространяются и на consumer тоже. Поскольку serialization является PRIVATE зависимостью archive, требования к её использованию не распространяются на consumer.
Как правило, зависимость должна быть указана в использовании команды target_link_libraries() с ключевым словом PRIVATE, если она используется только реализацией библиотеки, а не в заголовочных файлах. Если зависимость дополнительно используется в заголовочных файлах библиотеки (например, для наследования классов), то она должна быть указана как PUBLIC зависимость. Зависимость, которая не используется реализацией библиотеки, а только её заголовочными файлами, должна быть указана как INTERFACE зависимость. Команда target_link_libraries() может быть вызвана с использованием нескольких раз каждого ключевого слова:
target_link_libraries(archiveExtras PUBLIC archive PRIVATE serialization )
Требования к использованию распространяются путем чтения INTERFACE_ вариантов свойств целей из зависимостей и добавления значений к не-INTERFACE_ вариантам операнда. Например, INTERFACE_INCLUDE_DIRECTORIES зависимостей читается и добавляется в INCLUDE_DIRECTORIES операнда. В тех случаях, когда порядок важен и поддерживается, а порядок, полученный из вызовов target_link_libraries(), не позволяет правильно скомпилировать, можно использовать соответствующую команду для непосредственного задания свойства, чтобы обновить порядок.
Например, если связанные библиотеки для целевого объекта должны быть указаны в порядке lib1 lib2 lib3, но каталоги включаемых файлов должны быть указаны в порядке lib3 lib1 lib2:
target_link_libraries(myExe lib1 lib2 lib3) target_include_directories(myExe PRIVATE $<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>)
Обратите внимание, что при указании требований к использованию для целей, которые будут экспортированы для установки с помощью команды install(EXPORT), необходимо соблюдать осторожность. См. Создание пакетов для получения дополнительной информации.
Совместимые свойства интерфейса
Некоторые свойства целевых объектов должны быть совместимы между целью и интерфейсом каждой зависимости. Например, свойство целевого объекта POSITION_INDEPENDENT_CODE может указывать булево значение о том, следует ли компилировать целевой объект как независимый от позиции, что имеет платформоспецифические последствия. Целевой объект также может указывать требование к использованию INTERFACE_POSITION_INDEPENDENT_CODE для передачи информации о том, что потребители должны компилироваться как независимые от позиции.
add_executable(exe1 exe1.cpp) set_property(TARGET exe1 PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(lib1 SHARED lib1.cpp) set_property(TARGET lib1 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON) add_executable(exe2 exe2.cpp) target_link_libraries(exe2 lib1)
Здесь и exe1 и exe2 будут компилироваться как позиционно-независимый код. lib1 также будет скомпилирован как позиционно-независимый код, так как это значение по умолчанию для библиотек SHARED. Если у зависимостей есть конфликтующие, несовместимые требования, cmake(1) выдаёт диагностическое сообщение:
add_library(lib1 SHARED lib1.cpp) set_property(TARGET lib1 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON) add_library(lib2 SHARED lib2.cpp) set_property(TARGET lib2 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 lib1) set_property(TARGET exe1 PROPERTY POSITION_INDEPENDENT_CODE OFF) add_executable(exe2 exe2.cpp) target_link_libraries(exe2 lib1 lib2)
Требование lib1 INTERFACE_POSITION_INDEPENDENT_CODE не «совместимо» со свойством POSITION_INDEPENDENT_CODE целевого объекта exe1. Библиотека требует, чтобы потребители были построены как позиционно-независимый код, в то время как исполняемый файл задаёт не построение как позиционно-независимый код, поэтому выдаётся диагностическое сообщение.
Требования lib1 и lib2 не «совместимы». Одно из них требует, чтобы потребители были построены как позиционно-независимый код, а другое — нет. Так как exe2 ссылается на оба, и они конфликтуют, выдаётся диагностическое сообщение.
Чтобы быть «совместимым», свойство POSITION_INDEPENDENT_CODE, если задано, должно быть таким же, в булевом смысле, как свойство INTERFACE_POSITION_INDEPENDENT_CODE всех транзитивных зависимостей, для которых это свойство задано.
Это свойство «совместимого интерфейса» может быть расширено на другие свойства путём указания свойства в содержании свойства целевого объекта COMPATIBLE_INTERFACE_BOOL. Каждое указанное свойство должно быть совместимым между целевым объектом-потребителем и соответствующим свойством с префиксом INTERFACE_ от каждой зависимости:
add_library(lib1Version2 SHARED lib1_v2.cpp) set_property(TARGET lib1Version2 PROPERTY INTERFACE_CUSTOM_PROP ON) set_property(TARGET lib1Version2 APPEND PROPERTY COMPATIBLE_INTERFACE_BOOL CUSTOM_PROP ) add_library(lib1Version3 SHARED lib1_v3.cpp) set_property(TARGET lib1Version3 PROPERTY INTERFACE_CUSTOM_PROP OFF) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 lib1Version2) # CUSTOM_PROP will be ON add_executable(exe2 exe2.cpp) target_link_libraries(exe2 lib1Version2 lib1Version3) # Diagnostic
Небулевые свойства также могут участвовать в вычислениях «совместимого интерфейса». Свойства, указанные в свойстве COMPATIBLE_INTERFACE_STRING, должны быть либо не указаны, либо сравниваться с той же строкой среди всех транзитивных зависимостей. Это может быть полезно для обеспечения того, что несколько несовместимых версий библиотеки не будут связаны вместе через транзитивные требования целевого объекта:
add_library(lib1Version2 SHARED lib1_v2.cpp) set_property(TARGET lib1Version2 PROPERTY INTERFACE_LIB_VERSION 2) set_property(TARGET lib1Version2 APPEND PROPERTY COMPATIBLE_INTERFACE_STRING LIB_VERSION ) add_library(lib1Version3 SHARED lib1_v3.cpp) set_property(TARGET lib1Version3 PROPERTY INTERFACE_LIB_VERSION 3) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 lib1Version2) # LIB_VERSION will be "2" add_executable(exe2 exe2.cpp) target_link_libraries(exe2 lib1Version2 lib1Version3) # Diagnostic
Свойство целевого объекта COMPATIBLE_INTERFACE_NUMBER_MAX указывает, что содержимое будет вычисляться численно, и будет вычислено максимальное число среди всех указанных:
add_library(lib1Version2 SHARED lib1_v2.cpp) set_property(TARGET lib1Version2 PROPERTY INTERFACE_CONTAINER_SIZE_REQUIRED 200) set_property(TARGET lib1Version2 APPEND PROPERTY COMPATIBLE_INTERFACE_NUMBER_MAX CONTAINER_SIZE_REQUIRED ) add_library(lib1Version3 SHARED lib1_v3.cpp) set_property(TARGET lib1Version3 PROPERTY INTERFACE_CONTAINER_SIZE_REQUIRED 1000) add_executable(exe1 exe1.cpp) # CONTAINER_SIZE_REQUIRED will be "200" target_link_libraries(exe1 lib1Version2) add_executable(exe2 exe2.cpp) # CONTAINER_SIZE_REQUIRED will be "1000" target_link_libraries(exe2 lib1Version2 lib1Version3)
Аналогично, свойство COMPATIBLE_INTERFACE_NUMBER_MIN может использоваться для вычисления минимального числового значения для свойства из зависимостей.
Каждое вычисленное «совместимое» значение свойства может быть прочитано потребителем во время генерации с помощью выражений генератора.
Обратите внимание, что для каждой зависимой сущности набор свойств, указанных в каждом свойстве совместимого интерфейса, не должен пересекаться с набором, указанным в любом из других свойств.
Отладка происхождения свойств
Поскольку спецификации сборки могут определяться зависимостями, отсутствие локальности кода, который создаёт целевой объект, и кода, который отвечает за установку спецификаций сборки, может затруднить понимание кода. cmake(1) предоставляет механизм отладки для вывода происхождения содержимого свойств, которые могут определяться зависимостями. Свойства, которые можно отладить, перечислены в документации переменной CMAKE_DEBUG_TARGET_PROPERTIES:
set(CMAKE_DEBUG_TARGET_PROPERTIES INCLUDE_DIRECTORIES COMPILE_DEFINITIONS POSITION_INDEPENDENT_CODE CONTAINER_SIZE_REQUIRED LIB_VERSION ) add_executable(exe1 exe1.cpp)
В случае свойств, перечисленных в COMPATIBLE_INTERFACE_BOOL или COMPATIBLE_INTERFACE_STRING, вывод отладки показывает, какой целевой объект был ответственным за установку свойства, и какие другие зависимости также определили это свойство. В случае COMPATIBLE_INTERFACE_NUMBER_MAX и COMPATIBLE_INTERFACE_NUMBER_MIN, вывод отладки показывает значение свойства от каждой зависимости и определяет, является ли это значение новым экстремумом.
Указание спецификаций сборки с выражениями генератора
Спецификации сборки могут использовать generator expressions содержащие содержимое, которое может быть условным или известным только во время генерации. Например, вычисленное «совместимое» значение свойства может быть прочитано с помощью выражения TARGET_PROPERTY:
add_library(lib1Version2 SHARED lib1_v2.cpp)
set_property(TARGET lib1Version2 PROPERTY
INTERFACE_CONTAINER_SIZE_REQUIRED 200)
set_property(TARGET lib1Version2 APPEND PROPERTY
COMPATIBLE_INTERFACE_NUMBER_MAX CONTAINER_SIZE_REQUIRED
)
add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 lib1Version2)
target_compile_definitions(exe1 PRIVATE
CONTAINER_SIZE=$<TARGET_PROPERTY:CONTAINER_SIZE_REQUIRED>
)
В этом случае файлы исходников exe1 будут скомпилированы с -DCONTAINER_SIZE=200.
Спецификации сборки, определённые конфигурацией, удобно задавать с помощью выражения генератора CONFIG.
target_compile_definitions(exe1 PRIVATE
$<$<CONFIG:Debug>:DEBUG_BUILD>
)
Параметр CONFIG сравнивается с конфигурацией, которая собирается, без учёта регистра. В присутствии целевых объектов IMPORTED, содержимое MAP_IMPORTED_CONFIG_DEBUG также учитывается этим выражением.
Некоторые системы сборки, сгенерированные cmake(1), имеют предопределённую конфигурацию сборки, заданную в переменной CMAKE_BUILD_TYPE. Система сборки для таких IDE, как Visual Studio и Xcode, генерируется независимо от конфигурации сборки, и фактическая конфигурация сборки неизвестна до времени сборки. Поэтому код вроде
string(TOLOWER ${CMAKE_BUILD_TYPE} _type)
if (_type STREQUAL debug)
target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
endif()
может показаться работающим для генераторов на основе Makefile и Ninja, но не является переносимым на генераторы IDE. Кроме того, соответствия конфигураций IMPORTED не учитываются таким кодом, поэтому его следует избегать.
Унарное выражение генератора TARGET_PROPERTY и выражение генератора TARGET_POLICY оцениваются в контексте целевого объекта-потребителя. Это означает, что спецификация требования использования может оцениваться по-разному в зависимости от потребителя:
add_library(lib1 lib1.cpp) target_compile_definitions(lib1 INTERFACE $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:LIB1_WITH_EXE> $<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:LIB1_WITH_SHARED_LIB> $<$<TARGET_POLICY:CMP0041>:CONSUMER_CMP0041_NEW> ) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 lib1) cmake_policy(SET CMP0041 NEW) add_library(shared_lib shared_lib.cpp) target_link_libraries(shared_lib lib1)
Исполняемый файл exe1 будет скомпилирован с -DLIB1_WITH_EXE, а общая библиотека shared_lib будет скомпилирована с -DLIB1_WITH_SHARED_LIB и -DCONSUMER_CMP0041_NEW, потому что политика CMP0041 имеет значение NEW в момент создания целевого объекта shared_lib.
Выражение BUILD_INTERFACE оборачивает требования, которые используются только тогда, когда они потребляются из целевого объекта в той же системе сборки или когда они потребляются из целевого объекта, экспортированного в каталог сборки с помощью команды export(). Выражение INSTALL_INTERFACE оборачивает требования, которые используются только тогда, когда они потребляются из целевого объекта, который был установлен и экспортирован с помощью команды install(EXPORT):
add_library(ClimbingStats climbingstats.cpp)
target_compile_definitions(ClimbingStats INTERFACE
$<BUILD_INTERFACE:ClimbingStats_FROM_BUILD_LOCATION>
$<INSTALL_INTERFACE:ClimbingStats_FROM_INSTALLED_LOCATION>
)
install(TARGETS ClimbingStats EXPORT libExport ${InstallArgs})
install(EXPORT libExport NAMESPACE Upstream::
DESTINATION lib/cmake/ClimbingStats)
export(EXPORT libExport NAMESPACE Upstream::)
add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 ClimbingStats)
В этом случае исполняемый файл exe1 будет скомпилирован с -DClimbingStats_FROM_BUILD_LOCATION. Команды экспорта генерируют целевые объекты IMPORTED с опущенным INSTALL_INTERFACE или BUILD_INTERFACE и удалённым маркером *_INTERFACE . Отдельный проект, использующий пакет ClimbingStats будет содержать:
find_package(ClimbingStats REQUIRED) add_executable(Downstream main.cpp) target_link_libraries(Downstream Upstream::ClimbingStats)
В зависимости от того, был ли пакет ClimbingStats использован из каталога сборки или каталога установки, целевой объект Downstream будет скомпилирован либо с -DClimbingStats_FROM_BUILD_LOCATION, либо с -DClimbingStats_FROM_INSTALL_LOCATION. Для получения дополнительной информации о пакетах и экспорте см. руководство cmake-packages(7).
Директории включения и требования к использованию
Директории включения требуют особого рассмотрения, когда они указаны как требования к использованию и используются с выражениями генератора. Команда target_include_directories() принимает как относительные, так и абсолютные директории включения:
add_library(lib1 lib1.cpp) target_include_directories(lib1 PRIVATE /absolute/path relative/path )
Относительные пути интерпретируются относительно исходного каталога, где появляется команда. Относительные пути запрещены в INTERFACE_INCLUDE_DIRECTORIES целей IMPORTED.
В случаях использования нетривиального выражения генератора, выражение INSTALL_PREFIX может быть использовано внутри аргумента выражения INSTALL_INTERFACE. Это маркер замены, который расширяется до префикса установки при импорте потребляющим проектом.
Требования к использованию каталогов включения обычно различаются между деревом сборки и деревом установки. Выражения генератора BUILD_INTERFACE и INSTALL_INTERFACE могут использоваться для описания отдельных требований к использованию, в зависимости от места использования. Относительные пути разрешены внутри выражения INSTALL_INTERFACE и интерпретируются относительно префикса установки. Например:
add_library(ClimbingStats climbingstats.cpp)
target_include_directories(ClimbingStats INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/generated>
$<INSTALL_INTERFACE:/absolute/path>
$<INSTALL_INTERFACE:relative/path>
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/$<CONFIG>/generated>
)
Предоставляются два удобных API, относящиеся к требованиям использования каталогов включения. Переменная CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE может быть включена, с эквивалентным эффектом:
set_property(TARGET tgt APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR}>
)
для каждой затронутой цели. Удобная функция для установленных целей — это компонент INCLUDES DESTINATION, с командой install(TARGETS):
install(TARGETS foo bar bat EXPORT tgts ${dest_args}
INCLUDES DESTINATION include
)
install(EXPORT tgts ${other_args})
install(FILES ${headers} DESTINATION include)
Это эквивалентно добавлению ${CMAKE_INSTALL_PREFIX}/include к INTERFACE_INCLUDE_DIRECTORIES каждой установленной цели IMPORTED при генерации командой install(EXPORT).
Когда INTERFACE_INCLUDE_DIRECTORIES импортированной цели импортированной цели используется, записи в свойстве обрабатываются как SYSTEM каталоги включения, как если бы они были перечислены в INTERFACE_SYSTEM_INCLUDE_DIRECTORIES зависимости. Это может привести к пропуску предупреждений компилятора о заголовочных файлах, найденных в этих каталогах. Это поведение для импортированных целей может быть настроено свойством цели NO_SYSTEM_FROM_IMPORTED.
Если бинарная цель транзитивно связана с Mac OX фреймворком, каталог Headers фреймворка также обрабатывается как требование к использованию. Это имеет тот же эффект, что и передача каталога фреймворка как каталога включения.
Связывание библиотек и выражения генератора
Как и спецификации сборки, link libraries могут быть заданы с условиями выражения генератора. Однако, поскольку потребление требований к использованию основано на сборке из связанных зависимостей, существует дополнительное ограничение, что связанные зависимости должны образовывать «ориентированный ациклический граф». То есть, если связывание с целью зависит от значения свойства цели, то это свойство цели не может зависеть от связанных зависимостей:
add_library(lib1 lib1.cpp) add_library(lib2 lib2.cpp) target_link_libraries(lib1 PUBLIC $<$<TARGET_PROPERTY:POSITION_INDEPENDENT_CODE>:lib2> ) add_library(lib3 lib3.cpp) set_property(TARGET lib3 PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 lib1 lib3)
Поскольку значение свойства POSITION_INDEPENDENT_CODE цели exe1 зависит от связанных библиотек (lib3), а ребро связывания exe1 определяется тем же свойством POSITION_INDEPENDENT_CODE, граф зависимостей выше содержит цикл. cmake(1) выдает диагностическое сообщение в этом случае.
Артефакты вывода
Цели системы сборки, созданные командами add_library() и add_executable(), создают правила для создания двоичных выходных данных. Точное местоположение выходных двоичных файлов может быть определено только во время генерации, поскольку оно может зависеть от конфигурации сборки и языка связывания связанных зависимостей и т. д. TARGET_FILE, TARGET_LINKER_FILE и связанные выражения могут использоваться для доступа к имени и расположению сгенерированных бинарных файлов. Однако эти выражения не работают для библиотек OBJECT, так как для таких библиотек не существует одного файла, релевантного для этих выражений.
Существует три типа артефактов вывода, которые могут быть созданы целями, как подробно описано в следующих разделах. Их классификация отличается для платформ DLL и платформ, не являющихся DLL. Все платформы на базе Windows, включая Cygwin, являются платформами DLL.
Артефакты вывода времени выполнения
Артефакт времени выполнения цели системы сборки может быть:
- Исполняемый файл (например,
.exe) исполняемой цели, созданной командойadd_executable(). - На платформах DLL: исполняемый файл (например,
.dll) цели разделяемой библиотеки, созданной командойadd_library()с опциейSHARED.
Свойства цели RUNTIME_OUTPUT_DIRECTORY и RUNTIME_OUTPUT_NAME могут использоваться для управления расположением и именами артефактов вывода времени выполнения в дереве сборки.
Артефакты вывода библиотеки
Артефакт библиотеки цели системы сборки может быть:
- Файл модуля загрузки (например,
.dllили.so) цели модульной библиотеки, созданной командойadd_library()с опциейMODULE. - На платформах, не являющихся DLL: файл разделяемой библиотеки (например,
.soили.dylib) цели разделяемой библиотеки, созданной командойadd_library()с опциейSHARED.
Свойства цели LIBRARY_OUTPUT_DIRECTORY и LIBRARY_OUTPUT_NAME могут использоваться для управления расположением и именами артефактов вывода библиотеки в дереве сборки.
Артефакты вывода архива
Артефакт архива цели системы сборки может быть:
- Файл статической библиотеки (например,
.libили.a) цели статической библиотеки, созданной командойadd_library()с опциейSTATIC. - На платформах DLL: файл импортной библиотеки (например,
.lib) цели разделяемой библиотеки, созданной командойadd_library()с опциейSHARED. Этот файл гарантированно существует только в том случае, если библиотека экспортирует по крайней мере один необработанный символ. - На платформах DLL: файл импортной библиотеки (например,
.lib) цели исполняемого файла, созданной командойadd_executable(), когда свойство целиENABLE_EXPORTSустановлено.
Свойства цели ARCHIVE_OUTPUT_DIRECTORY и ARCHIVE_OUTPUT_NAME могут использоваться для управления расположением и именами артефактов вывода архива в дереве сборки.
Команды, привязанные к каталогу
Команды target_include_directories(), target_compile_definitions() и target_compile_options() влияют только на один целевой объект за раз. Команды add_definitions(), add_compile_options() и include_directories() выполняют аналогичную функцию, но для удобства работают на уровне каталога, а не на уровне целевого объекта.
Псевдоцелевые объекты
Некоторые типы целевых объектов не представляют выходные данные системы сборки, а только входные данные, такие как внешние зависимости, псевдонимы или другие артефакты, не связанные со сборкой. Псевдоцелевые объекты не представлены в сгенерированной системе сборки.
Импортированные целевые объекты
Целевой объект типа IMPORTED представляет собой уже существующую зависимость. Обычно такие целевые объекты определяются пакетом вышестоящего уровня и должны рассматриваться как неизменяемые. Невозможно использовать целевой объект типа IMPORTED в левой части команд target_compile_definitions(), target_include_directories(), target_compile_options() или target_link_libraries(), так как это попытка изменить его. Целевые объекты типа IMPORTED предназначены для использования только в правой части этих команд.
Целевые объекты типа IMPORTED могут иметь те же свойства, что и бинарные целевые объекты, такие как INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_COMPILE_DEFINITIONS, INTERFACE_COMPILE_OPTIONS, INTERFACE_LINK_LIBRARIES и INTERFACE_POSITION_INDEPENDENT_CODE.
Расположение LOCATION также может быть прочитано из целевого объекта типа IMPORTED, хотя для этого редко есть причина. Такие команды, как add_custom_command(), могут прозрачно использовать целевой объект типа IMPORTED EXECUTABLE как исполняемый файл COMMAND.
Область определения целевого объекта типа IMPORTED — это каталог, в котором он был определен. К нему можно получить доступ и использовать из подкаталогов, но не из родительских каталогов или каталогов-братьев.
Также возможно определить глобально доступный в системе сборки целевой объект типа GLOBAL IMPORTED.
См. руководство cmake-packages(7) для получения дополнительной информации о создании пакетов с целевыми объектами типа IMPORTED.
Псевдонимы целевых объектов
Целевой объект типа ALIAS — это имя, которое может быть использовано взаимозаменяемо с именем бинарного целевого объекта в контекстах только для чтения. Основное применение целевых объектов типа ALIAS — это, например, исполняемые файлы для примеров или модульных тестов, сопровождающие библиотеку, которые могут быть частью одной системы сборки или собираться отдельно в зависимости от конфигурации пользователя.
add_library(lib1 lib1.cpp)
install(TARGETS lib1 EXPORT lib1Export ${dest_args})
install(EXPORT lib1Export NAMESPACE Upstream:: ${other_args})
add_library(Upstream::lib1 ALIAS lib1)
В другом каталоге мы можем безусловно связать ссылку с целевым объектом Upstream::lib1, который может быть целевым объектом типа IMPORTED из пакета или целевым объектом типа ALIAS в случае сборки в рамках одной системы сборки.
if (NOT TARGET Upstream::lib1) find_package(lib1 REQUIRED) endif() add_executable(exe1 exe1.cpp) target_link_libraries(exe1 Upstream::lib1)
Целевые объекты типа ALIAS не изменяемы, не устанавливаются и не экспортируются. Они полностью локальны для описания системы сборки. Можно проверить, является ли имя именем ALIAS объекта, прочитав свойство ALIASED_TARGET из него:
get_target_property(_aliased Upstream::lib1 ALIASED_TARGET)
if(_aliased)
message(STATUS "The name Upstream::lib1 is an ALIAS for ${_aliased}.")
endif()
Интерфейсные библиотеки
Целевой объект типа INTERFACE не имеет LOCATION и изменяем, но в остальном похож на целевой объект типа IMPORTED.
Он может указывать требования к использованию, такие как INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_COMPILE_DEFINITIONS, INTERFACE_COMPILE_OPTIONS, INTERFACE_LINK_LIBRARIES, INTERFACE_SOURCES и INTERFACE_POSITION_INDEPENDENT_CODE. Только режимы INTERFACE команд target_include_directories(), target_compile_definitions(), target_compile_options(), target_sources() и target_link_libraries() могут использоваться с библиотеками INTERFACE.
Основное применение библиотек INTERFACE — это библиотеки только для заголовков.
add_library(Eigen INTERFACE)
target_include_directories(Eigen INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include/Eigen>
)
add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 Eigen)
Здесь требования к использованию из целевого объекта Eigen потребляются и используются при компиляции, но не влияют на компоновку.
Другое применение — использовать полностью ориентированный на целевой объект подход к требованиям использования:
add_library(pic_on INTERFACE) set_property(TARGET pic_on PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE ON) add_library(pic_off INTERFACE) set_property(TARGET pic_off PROPERTY INTERFACE_POSITION_INDEPENDENT_CODE OFF) add_library(enable_rtti INTERFACE) target_compile_options(enable_rtti INTERFACE $<$<OR:$<COMPILER_ID:GNU>,$<COMPILER_ID:Clang>>:-rtti> ) add_executable(exe1 exe1.cpp) target_link_libraries(exe1 pic_on enable_rtti)
Таким образом, спецификация сборки exe1 полностью выражается как связанные целевые объекты, а сложность флагов, специфичных для компилятора, инкапсулирована в целевой объект библиотеки INTERFACE.
Свойства, которые разрешено устанавливать или считывать из библиотеки INTERFACE, следующие:
- Свойства, соответствующие
INTERFACE_* - Встроенные свойства, соответствующие
COMPATIBLE_INTERFACE_* EXPORT_NAMEIMPORTEDNAME- Свойства, соответствующие
MAP_IMPORTED_CONFIG_*
INTERFACE библиотеки могут быть установлены и экспортированы. Любой контент, на который они ссылаются, должен быть установлен отдельно:
add_library(Eigen INTERFACE)
target_include_directories(Eigen INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include/Eigen>
)
install(TARGETS Eigen EXPORT eigenExport)
install(EXPORT eigenExport NAMESPACE Upstream::
DESTINATION lib/cmake/Eigen
)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/eigen.h
${CMAKE_CURRENT_SOURCE_DIR}/src/vector.h
${CMAKE_CURRENT_SOURCE_DIR}/src/matrix.h
DESTINATION include/Eigen
)
© 2000–2019 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.6/manual/cmake-buildsystem.7.html