Spec-Zone.ru › CMake 3.12

cmake-buildsystem(7)

  • Введение
  • Бинарные цели
    • Бинарные исполняемые файлы
    • Типы бинарных библиотек
      • Обычные библиотеки
        • Фреймворки Apple
      • Библиотеки объектов
  • Требования к спецификации построения и использованию
    • Свойства целевых объектов
    • Требования к транзитивному использованию
    • Свойства совместимого интерфейса
    • Отладка происхождения свойства
    • Спецификация построения с генераторными выражениями
      • Директории включения и требования к использованию
    • Связывание библиотек и генераторные выражения
    • Выходные артефакты
      • Выходные артефакты выполнения
      • Выходные артефакты библиотек
      • Выходные артефакты архивов
    • Команды, ограниченные директорией
  • Псевдоцели
    • Импортированные цели
    • Цели-алиасы
    • Библиотеки интерфейса

Введение

Система построения на основе 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)

Этап компоновки (или архивирования) этих других целевых объектов будет использовать набор файлов объектов в дополнение к тем, которые получены из их собственных исходных файлов.

В качестве альтернативы, библиотеки объектов могут быть подключены к другим целевым объектам:

add_library(archive OBJECT archive.cpp zip.cpp lzma.cpp)

add_library(archiveExtras STATIC extras.cpp)
target_link_libraries(archiveExtras PUBLIC archive)

add_executable(test_exe test.cpp)
target_link_libraries(test_exe archive)

Этап компоновки (или архивирования) этих других целевых объектов будет использовать файлы объектов из библиотек объектов, к которым они непосредственно подключены. Кроме того, требования к использованию библиотек объектов будут выполняться при компиляции исходных файлов в этих других целевых объектах. Кроме того, эти требования к использованию будут распространяться транзитивно на зависимые от этих других целевых объектов.

Библиотеки объектов не могут быть использованы в качестве TARGET при использовании подписи команды add_custom_command(TARGET). Однако список объектов может быть использован командой add_custom_command(OUTPUT) или file(GENERATE) с использованием $<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 зависимостью archiveExtras, требования к использованию не распространяются на 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. Библиотека требует, чтобы исполняемые модули были построены как position-independent-code, в то время как исполняемый файл задаёт не построение как position-independent-code, поэтому выводится диагностическое сообщение.

Требования lib1 и lib2 несовместимы. Одно из них требует, чтобы исполняемые модули были построены как position-independent-code, а другое — нет. Поскольку 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_compile_definitions(), add_compile_options() и include_directories() имеют аналогичную функцию, но для удобства работают на уровне каталога, а не на уровне целевого объекта.

Псевдоцелевые объекты

Некоторые типы целевых объектов не представляют выходные данные системы сборки, а только входные данные, такие как внешние зависимости, псевдонимы или другие не связанные со сборкой артефакты. Псевдоцелевые объекты не представлены в сгенерированной системе сборки.

Импортированные целевые объекты

Целевой объект IMPORTED представляет собой существующую зависимость. Обычно такие целевые объекты определяются пакетом вышестоящего уровня и должны рассматриваться как неизменяемые. После объявления целевого объекта IMPORTED можно настроить его свойства, используя обычные команды, такие как target_compile_definitions(), target_include_directories(), target_compile_options() или target_link_libraries(), как и с любым другим обычным целевым объектом.

Целевые объекты IMPORTED могут иметь те же свойства требований к использованию, что и бинарные целевые объекты, такие как INTERFACE_INCLUDE_DIRECTORIES, INTERFACE_COMPILE_DEFINITIONS, INTERFACE_COMPILE_OPTIONS, INTERFACE_LINK_LIBRARIES и INTERFACE_POSITION_INDEPENDENT_CODE.

Расположение LOCATION также можно считать из импортированного целевого объекта, хотя редко есть причина для этого. Команды, такие как add_custom_command(), могут прозрачно использовать целевой объект IMPORTED EXECUTABLE в качестве COMMAND исполняемого файла.

Область определения целевого объекта IMPORTED находится в каталоге, где он был определен. К нему можно получить доступ и использовать его из подкаталогов, но не из родительских или соседних каталогов. Область аналогична области переменной cmake.

Также можно определить GLOBAL целевой объект IMPORTED, который доступен глобально в системе сборки.

Дополнительные сведения о создании пакетов с целевыми объектами IMPORTED см. в руководстве cmake-packages(7).

Целевые объекты-псевдонимы

Целевой объект-псевдоним 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_NAME
  • IMPORTED
  • NAME
  • Свойства, соответствующие IMPORTED_LIBNAME_*
  • Свойства, соответствующие 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.12/manual/cmake-buildsystem.7.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API