Spec-Zone.ru › CMake

cmake-buildsystem(7)

  • Введение
  • Бинарные цели

    • Бинарные исполняемые файлы
    • Типы бинарных библиотек

      • Обычные библиотеки

        • Фреймворки Apple
      • Библиотеки объектов
  • Требования к спецификации сборки и использованию

    • Команды цели
    • Спецификация сборки цели

      • Свойства компиляции цели
      • Свойства компоновки цели
    • Требования к использованию цели

      • Переходные свойства компиляции
      • Переходные свойства компоновки
    • Настраиваемые переходные свойства
    • Свойства совместимого интерфейса
    • Отладка источника свойств
    • Спецификация сборки с выражениями генератора

      • Директории включения и требования к использованию
    • Связывание библиотек и выражения генератора
    • Артефакты вывода

      • Артефакты вывода во время выполнения
      • Артефакты вывода библиотек
      • Артефакты вывода архивов
    • Команды, ограниченные каталогом
  • Конфигурации сборки

    • Чувствительность к регистру
    • По умолчанию и настраиваемые конфигурации
  • Псевдоцели

    • Импортированные цели
    • Цели псевдонимов
    • Библиотеки интерфейса

Введение

Система сборки CMake организована как набор логических целей высокого уровня. Каждая цель соответствует исполняемому файлу или библиотеке или является пользовательской целью, содержащей пользовательские команды. Зависимости между целями выражены в системе сборки, чтобы определить порядок сборки и правила перегенерации в ответ на изменение.

Бинарные цели

Исполняемые файлы и библиотеки определяются с помощью команд add_executable() и add_library(). Результирующие бинарные файлы имеют соответствующие PREFIX, SUFFIX и расширения для целевой платформы. Зависимости между бинарными целями выражаются с помощью команды target_link_libraries():

add_library(archive archive.cpp zip.cpp lzma.cpp)
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)

archive определена как STATIC библиотека — архив, содержащий объекты, скомпилированные из 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() определяет STATIC библиотеку, если не указан тип. Тип может быть указан при использовании команды:

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, C++/CLI DLL), требуется, чтобы библиотека не была SHARED библиотекой, так как CMake ожидает, что SHARED библиотеки экспортируют хотя бы один символ.

add_library(archive MODULE 7z.cpp)
Фреймворки Apple

SHARED библиотека может быть помечена свойством цели FRAMEWORK для создания пакета фреймворка macOS или iOS. Библиотека со свойством цели FRAMEWORK должна также установить свойство цели FRAMEWORK_VERSION. Это свойство обычно устанавливается в «A» согласно соглашениям macOS. MACOSX_FRAMEWORK_IDENTIFIER устанавливает ключ CFBundleIdentifier и уникально идентифицирует пакет.

add_library(MyFramework SHARED MyFramework.cpp)
set_target_properties(MyFramework PROPERTIES
  FRAMEWORK TRUE
  FRAMEWORK_VERSION A # Version "A" is macOS convention
  MACOSX_FRAMEWORK_IDENTIFIER org.cmake.MyFramework
)

Библиотеки объектов

Тип библиотеки OBJECT определяет неархивированную коллекцию объектных файлов, полученных в результате компиляции заданных исходных файлов. Коллекция объектных файлов может использоваться в качестве исходных входных данных для других целей с помощью синтаксиса $<TARGET_OBJECTS:name>. Это generator expression, который можно использовать для предоставления содержимого 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)

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

Библиотеки объектов не могут использоваться в качестве TARGET при использовании подписи команды add_custom_command(TARGET). Однако список объектов может быть использован командами add_custom_command(OUTPUT) или file(GENERATE) с использованием $<TARGET_OBJECTS:objlib>.

Требования к спецификации сборки и использованию

Цели собираются в соответствии со своей собственной спецификацией сборки в сочетании с требованиями к использованию, распространяемыми от зависимых компоновки. Оба могут быть указаны с помощью целевых команд.

Например:

add_library(archive SHARED archive.cpp zip.cpp)

if (LZMA_FOUND)
  # Add a source implementing support for lzma.
  target_sources(archive PRIVATE lzma.cpp)

  # Compile the 'archive' library sources with '-DBUILDING_WITH_LZMA'.
  target_compile_definitions(archive PRIVATE BUILDING_WITH_LZMA)
endif()

target_compile_definitions(archive INTERFACE USING_ARCHIVE_LIB)

add_executable(consumer consumer.cpp)

# Link 'consumer' to 'archive'.  This also consumes its usage requirements,
# so 'consumer.cpp' is compiled with '-DUSING_ARCHIVE_LIB'.
target_link_libraries(consumer archive)

Команды для целей

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

Вызовы должны указывать ключевые слова области, каждое из которых влияет на видимость аргументов, следующих за ним. Области:

PUBLIC

Заполняет обе свойства для построения и свойства для использования цели.

PRIVATE

Заполняет только свойства для построения цели.

INTERFACE

Заполняет только свойства для использования цели.

Команды:

target_compile_definitions()

Заполняет COMPILE_DEFINITIONS спецификацию построения и INTERFACE_COMPILE_DEFINITIONS свойства требований к использованию.

Например, вызов

target_compile_definitions(archive
  PRIVATE   BUILDING_WITH_LZMA
  INTERFACE USING_ARCHIVE_LIB
)

добавляет BUILDING_WITH_LZMA к свойству цели COMPILE_DEFINITIONS и добавляет USING_ARCHIVE_LIB к свойству цели INTERFACE_COMPILE_DEFINITIONS.

target_compile_options()

Заполняет COMPILE_OPTIONS спецификацию построения и INTERFACE_COMPILE_OPTIONS свойства требований к использованию.

target_compile_features()

Добавлена в версии 3.1.

Заполняет COMPILE_FEATURES спецификацию построения и INTERFACE_COMPILE_FEATURES свойства требований к использованию.

target_include_directories()

Заполняет INCLUDE_DIRECTORIES спецификацию построения и INTERFACE_INCLUDE_DIRECTORIES свойства требований к использованию. С опцией SYSTEM, также заполняет INTERFACE_SYSTEM_INCLUDE_DIRECTORIES свойство требований к использованию.

Для удобства, переменная CMAKE_INCLUDE_CURRENT_DIR может быть включена для добавления исходной директории и соответствующей директории построения как INCLUDE_DIRECTORIES ко всем целям. Аналогично, переменная CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE может быть включена для добавления их как INTERFACE_INCLUDE_DIRECTORIES ко всем целям.

target_sources()

Добавлена в версии 3.1.

Заполняет SOURCES спецификацию построения и INTERFACE_SOURCES свойства требований к использованию.

Также поддерживает указание Наборов файлов, которые могут добавить исходные файлы и заголовки модуля C++ не перечисленные в свойствах SOURCES и INTERFACE_SOURCES. Наборы файлов также могут заполнить INCLUDE_DIRECTORIES спецификацию построения и INTERFACE_INCLUDE_DIRECTORIES свойства требований к использованию с каталогами заголовков.

target_precompile_headers()

Добавлена в версии 3.16.

Заполняет PRECOMPILE_HEADERS спецификацию построения и INTERFACE_PRECOMPILE_HEADERS свойства требований к использованию.

target_link_libraries()

Заполняет LINK_LIBRARIES спецификацию построения и INTERFACE_LINK_LIBRARIES свойства требований к использованию.

Это основной механизм, с помощью которого зависимости линковки и их требования к использованию транзитивно распространяются, чтобы повлиять на компиляцию и линковку цели.

target_link_directories()

Добавлена в версии 3.13.

Заполняет LINK_DIRECTORIES спецификацию построения и INTERFACE_LINK_DIRECTORIES свойства требований к использованию.

target_link_options()

Добавлена в версии 3.13.

Заполняет LINK_OPTIONS спецификацию построения и INTERFACE_LINK_OPTIONS свойства требований к использованию.

Спецификация построения цели

Спецификация построения бинарных целей представлена свойствами целей. Для каждого из следующих свойств компиляции и линковки, компиляция и линковка цели влияют как на собственное значение, так и на соответствующее требование к использованию свойство, названное с INTERFACE_ префиксом, собранное из транзитивного замыкания зависимостей линковки.

Свойства компиляции целей

Эти свойства представляют спецификацию построения для компиляции цели.

COMPILE_DEFINITIONS

Список определений компиляции для компиляции исходных кодов в целевом объекте. Они передаются компилятору со флагами -D, или их эквивалентами, в неопределённом порядке.

Свойство целевого объекта DEFINE_SYMBOL также используется как определение компиляции в качестве специального удобного случая для целевых объектов SHARED и MODULE библиотек.

COMPILE_OPTIONS

Список опций компиляции для компиляции исходных кодов в целевом объекте. Они передаются компилятору в качестве флагов, в порядке появления.

Опции компиляции автоматически экранируются для оболочки.

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

COMPILE_FEATURES

Добавлена в версии 3.1.

Список compile features, необходимых для компиляции исходных кодов в целевом объекте. Как правило, они гарантируют, что исходные коды целевого объекта скомпилированы с достаточным уровнем стандарта языка.

INCLUDE_DIRECTORIES

Список директорий включения для компиляции исходных кодов в целевом объекте. Они передаются компилятору со флагами -I или -isystem, или их эквивалентами, в порядке появления.

Для удобства может быть включена переменная CMAKE_INCLUDE_CURRENT_DIR для добавления директории исходных кодов и соответствующей директории построения в качестве INCLUDE_DIRECTORIES для всех целевых объектов.

SOURCES

Список исходных файлов, связанных с целевым объектом. Это включает в себя исходные файлы, указанные при создании целевого объекта командами add_executable(), add_library() или add_custom_target(). Это также включает в себя исходные файлы, добавленные командой target_sources(), но не включает Наборы файлов.

PRECOMPILE_HEADERS

Добавлена в версии 3.16.

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

AUTOMOC_MACRO_NAMES

Добавлена в версии 3.10.

Список имён макросов, используемых AUTOMOC, чтобы определить, нужно ли обрабатывать исходный код C++ в целевом объекте с помощью moc.

AUTOUIC_OPTIONS

Добавлена в версии 3.0.

Список опций, используемых AUTOUIC при вызове uic для целевого объекта.

Свойства связи целевого объекта

Эти свойства представляют собой спецификацию построения для связи целевого объекта.

LINK_LIBRARIES

Список библиотек для связи целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или модульная библиотека. Записи для обычных библиотек передаются компоновщику либо путями к их скомпилированным файлам, либо с флагами -l или их эквивалентами. Записи для библиотек объектов передаются компоновщику путями к их объектным файлам.

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

LINK_DIRECTORIES

Добавлена в версии 3.13.

Список директорий компоновки для компоновки целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или модульная библиотека. Директории передаются компоновщику с флагами -L или их эквивалентами.

LINK_OPTIONS

Добавлена в версии 3.13.

Список опций компоновки для компоновки целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или модульная библиотека. Опции передаются компоновщику в качестве флагов, в порядке появления.

Опции компоновки автоматически экранируются для оболочки.

LINK_DEPENDS

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

Требования к использованию целевого объекта

Требования к использованию целевого объекта — это настройки, которые распространяются на потребителей, которые связывают целевой объект с помощью target_link_libraries(), чтобы правильно скомпилировать и связать его. Они представлены транзитивными свойствами компиляции и компоновки.

Обратите внимание, что требования к использованию не предназначены для удобства, чтобы заставить последующие использовать конкретные COMPILE_OPTIONS, COMPILE_DEFINITIONS и т. д. Содержимое свойств должно быть требованиями, а не просто рекомендациями.

См. раздел Создание переносимых пакетов руководства cmake-packages(7) для обсуждения дополнительных мер предосторожности, которые необходимо принять при указании требований к использованию при создании пакетов для перераспределения.

Требования к использованию целевого объекта могут распространяться на зависимые объекты. Команда 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_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). Дополнительная информация содержится в разделе Создание пакетов.

Свойства транзитивной компиляции

Эти свойства представляют требования к использованию для компиляции потребителей.

INTERFACE_COMPILE_DEFINITIONS

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

INTERFACE_COMPILE_OPTIONS

Список параметров компиляции для компиляции исходных кодов в потребителях целевого объекта.

INTERFACE_COMPILE_FEATURES

Добавлен в версии 3.1.

Список compile features, необходимых для компиляции исходных кодов в потребителях целевого объекта. Как правило, они гарантируют обработку заголовочных файлов целевого объекта при компиляции потребителей с достаточным уровнем стандарта языка.

INTERFACE_INCLUDE_DIRECTORIES

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

INTERFACE_SYSTEM_INCLUDE_DIRECTORIES

Список каталогов, которые, при указании в качестве каталогов включения, например, с помощью INCLUDE_DIRECTORIES или INTERFACE_INCLUDE_DIRECTORIES, должны обрабатываться как "системные" каталоги включения при компиляции исходных кодов в потребителях целевого объекта.

INTERFACE_SOURCES

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

INTERFACE_PRECOMPILE_HEADERS

Добавлен в версии 3.16.

Список заголовочных файлов для предварительной компиляции и включения при компиляции исходных кодов в потребителях целевого объекта.

INTERFACE_AUTOMOC_MACRO_NAMES

Добавлен в версии 3.27.

Список имён макросов, используемых AUTOMOC для определения, требуется ли обработка исходного кода C++ в потребителях целевого объекта инструментом moc.

INTERFACE_AUTOUIC_OPTIONS

Добавлен в версии 3.0.

Список опций, используемых AUTOUIC при вызове uic для потребителей целевого объекта.

Свойства транзитивного линковки

Эти свойства представляют требования к использованию для линковки потребителей.

INTERFACE_LINK_LIBRARIES

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

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

INTERFACE_LINK_DIRECTORIES

Добавлен в версии 3.13.

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

INTERFACE_LINK_OPTIONS

Добавлен в версии 3.13.

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

INTERFACE_LINK_DEPENDS

Добавлен в версии 3.13.

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

Пользовательские свойства транзитивности

Добавлен в версии 3.30.

Генераторское выражение TARGET_PROPERTY оценивает вышеперечисленные свойства спецификации построения и требований к использованию как встроенные транзитивные свойства. Он также поддерживает пользовательские транзитивные свойства, определённые свойствами TRANSITIVE_COMPILE_PROPERTIES и TRANSITIVE_LINK_PROPERTIES целевого объекта и его зависимостей линковки.

Например:

add_library(example INTERFACE)
set_target_properties(example PROPERTIES
  TRANSITIVE_COMPILE_PROPERTIES "CUSTOM_C"
  TRANSITIVE_LINK_PROPERTIES    "CUSTOM_L"

  INTERFACE_CUSTOM_C "EXAMPLE_CUSTOM_C"
  INTERFACE_CUSTOM_L "EXAMPLE_CUSTOM_L"
  )

add_library(mylib STATIC mylib.c)
target_link_libraries(mylib PRIVATE example)
set_target_properties(mylib PROPERTIES
  CUSTOM_C           "MYLIB_PRIVATE_CUSTOM_C"
  CUSTOM_L           "MYLIB_PRIVATE_CUSTOM_L"
  INTERFACE_CUSTOM_C "MYLIB_IFACE_CUSTOM_C"
  INTERFACE_CUSTOM_L "MYLIB_IFACE_CUSTOM_L"
  )

add_executable(myexe myexe.c)
target_link_libraries(myexe PRIVATE mylib)
set_target_properties(myexe PROPERTIES
  CUSTOM_C "MYEXE_CUSTOM_C"
  CUSTOM_L "MYEXE_CUSTOM_L"
  )

add_custom_target(print ALL VERBATIM
  COMMAND ${CMAKE_COMMAND} -E echo
    # Prints "MYLIB_PRIVATE_CUSTOM_C;EXAMPLE_CUSTOM_C"
    "$<TARGET_PROPERTY:mylib,CUSTOM_C>"

    # Prints "MYLIB_PRIVATE_CUSTOM_L;EXAMPLE_CUSTOM_L"
    "$<TARGET_PROPERTY:mylib,CUSTOM_L>"

    # Prints "MYEXE_CUSTOM_C"
    "$<TARGET_PROPERTY:myexe,CUSTOM_C>"

    # Prints "MYEXE_CUSTOM_L;MYLIB_IFACE_CUSTOM_L;EXAMPLE_CUSTOM_L"
    "$<TARGET_PROPERTY:myexe,CUSTOM_L>"
  )

Совместимые свойства интерфейса

Некоторые целевые свойства должны быть совместимы между целью и интерфейсом каждой зависимости. Например, свойство цели 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 ссылается на оба, и они находятся в конфликте, CMake выводит сообщение об ошибке:

CMake Error: The INTERFACE_POSITION_INDEPENDENT_CODE property of "lib2" does
not agree with the value of POSITION_INDEPENDENT_CODE already determined
for "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.

Унарное выражение генератора 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 установленного целевого объекта определяет это поведение (см. свойство EXPORT_NO_SYSTEM для изменения установленного значения для целевого объекта). Также можно изменить то, как потребители интерпретируют системное поведение импортированных целевых объектов, установив свойство целевого объекта NO_SYSTEM_FROM_IMPORTED на потребителе.

Если целевой объект двоичного типа связан транзитивно с macOS FRAMEWORK, каталог 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 установлено.
  • На AIX: файл импорта компоновщика (например, .imp) целевого объекта исполняемого файла, созданного командой add_executable(), когда его свойство целевого объекта ENABLE_EXPORTS установлено.
  • На macOS: файл импорта компоновщика (например, .tbd) целевого объекта динамической библиотеки, созданного командой add_library() с опцией SHARED и когда свойство целевого объекта 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() имеют аналогичную функцию, но для удобства действуют на уровне каталога, а не целевого объекта.

Настройки сборки

Настройки определяют параметры для определённого типа сборки, например, Release или Debug. Способ их задания зависит от типа используемого generator. Для генераторов с одной конфигурацией, таких как Генераторы Makefile и Ninja, конфигурация задаётся во время настройки переменной CMAKE_BUILD_TYPE. Для генераторов с несколькими конфигурациями, таких как Visual Studio, Xcode и Ninja Multi-Config, конфигурация выбирается пользователем во время сборки, и CMAKE_BUILD_TYPE игнорируется. В случае с несколькими конфигурациями набор *доступных* конфигураций задаётся во время настройки переменной CMAKE_CONFIGURATION_TYPES, но фактическая используемая конфигурация не может быть известна до стадии сборки. Это различие часто неправильно понимается, что приводит к проблематичному коду, подобному следующему:

# WARNING: This is wrong for multi-config generators because they don't use
#          and typically don't even set CMAKE_BUILD_TYPE
string(TOLOWER ${CMAKE_BUILD_TYPE} build_type)
if (build_type STREQUAL debug)
  target_compile_definitions(exe1 PRIVATE DEBUG_BUILD)
endif()

Вместо этого следует использовать Generator expressions для правильной обработки конфигурационно-зависимой логики независимо от используемого генератора. Например:

# Works correctly for both single and multi-config generators
target_compile_definitions(exe1 PRIVATE
  $<$<CONFIG:Debug>:DEBUG_BUILD>
)

В присутствии целевых объектов IMPORTED содержимое MAP_IMPORTED_CONFIG_DEBUG также учитывается вышеупомянутым выражением $<CONFIG:Debug>.

Регистронезависимость

CMAKE_BUILD_TYPE и CMAKE_CONFIGURATION_TYPES ведут себя как и другие переменные, поэтому любые сравнения строк с их значениями будут регистрозависимыми. Выражение генератора $<CONFIG> также сохраняет регистр конфигурации, установленной пользователем или по умолчанию CMake. Например:

# NOTE: Don't use these patterns, they are for illustration purposes only.

set(CMAKE_BUILD_TYPE Debug)
if(CMAKE_BUILD_TYPE STREQUAL DEBUG)
  # ... will never get here, "Debug" != "DEBUG"
endif()
add_custom_target(print_config ALL
  # Prints "Config is Debug" in this single-config case
  COMMAND ${CMAKE_COMMAND} -E echo "Config is $<CONFIG>"
  VERBATIM
)

set(CMAKE_CONFIGURATION_TYPES Debug Release)
if(DEBUG IN_LIST CMAKE_CONFIGURATION_TYPES)
  # ... will never get here, "Debug" != "DEBUG"
endif()

В отличие от этого, CMake обрабатывает тип конфигурации регистронезависимо при внутреннем использовании в местах, где изменение поведения зависит от конфигурации. Например, выражение генератора $<CONFIG:Debug> примет значение 1 не только для конфигурации Debug, но и для DEBUG, debug или даже DeBuG . Поэтому вы можете указывать типы конфигураций в CMAKE_BUILD_TYPE и CMAKE_CONFIGURATION_TYPES с любой комбинацией верхнего и нижнего регистра, хотя существуют сильные соглашения (см. следующий раздел). Если вам необходимо проверить значение в строковых сравнениях, сначала преобразуйте значение в верхний или нижний регистр и соответствующим образом скорректируйте проверку.

Конфигурации по умолчанию и пользовательские конфигурации

По умолчанию CMake определяет ряд стандартных конфигураций:

  • Debug
  • Release
  • RelWithDebInfo
  • MinSizeRel

В генераторах с несколькими конфигурациями переменная CMAKE_CONFIGURATION_TYPES будет заполняться (возможно, подмножеством) вышеперечисленного списка по умолчанию, если не переопределено проектом или пользователем. Фактическая используемая конфигурация выбирается пользователем во время сборки.

Для генераторов с одной конфигурацией конфигурация задаётся с помощью переменной CMAKE_BUILD_TYPE во время настройки и не может быть изменена во время сборки. Значение по умолчанию часто не совпадает ни с одной из вышеперечисленных стандартных конфигураций и вместо этого будет пустой строкой. Распространённое заблуждение заключается в том, что это то же самое, что Debug, но это не так. Пользователи всегда должны явно указывать тип сборки, чтобы избежать этой распространённой проблемы.

Вышеперечисленные стандартные типы конфигураций обеспечивают разумное поведение на большинстве платформ, но их можно расширить для обеспечения других типов. Каждая конфигурация определяет набор переменных флагов компилятора и компоновщика для используемого языка. Эти переменные следуют соглашению CMAKE_<LANG>_FLAGS_<CONFIG>, где <CONFIG> всегда является конфигурацией с заглавными буквами. При определении пользовательского типа конфигурации убедитесь, что эти переменные установлены соответствующим образом, обычно в качестве переменных кэша.

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

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

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

Цепь 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 также может быть прочитано из цели IMPORTED, хотя редко есть причина для этого. Команды, такие как add_custom_command(), могут прозрачно использовать цель IMPORTED EXECUTABLE как исполняемый файл COMMAND.

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

Также возможно определить глобально доступную в системе сборки 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()

Интерфейсные библиотеки

Цель библиотеки интерфейса не компилирует исходные файлы и не создаёт артефакт библиотеки на диске, поэтому у неё нет LOCATION.

Она может определять требования использования, такие как 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.

Начиная с CMake 3.19, в цель библиотеки интерфейса можно добавлять исходные файлы. Библиотека интерфейса, содержащая исходные файлы, будет включена в качестве цели сборки в сгенерированной системе сборки. Она не компилирует исходные файлы, но может содержать пользовательские команды для генерации других исходных файлов. Кроме того, среды разработки отобразят исходные файлы как часть цели для интерактивного чтения и редактирования.

Основным применением библиотек INTERFACE является использование только заголовочных файлов. Начиная с CMake 3.23, к библиотеке можно привязать заголовочные файлы, добавив их в набор заголовков с помощью команды target_sources():

add_library(Eigen INTERFACE)

target_sources(Eigen PUBLIC
  FILE_SET HEADERS
    BASE_DIRS src
    FILES src/eigen.h src/vector.h src/matrix.h
)

add_executable(exe1 exe1.cpp)
target_link_libraries(exe1 Eigen)

Когда мы здесь указываем FILE_SET, BASE_DIRS, которые мы определяем, автоматически становятся каталогами включения в требования использования для цели 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 могут быть установлены и экспортированы. Мы можем установить набор заголовков по умолчанию вместе с целью:

add_library(Eigen INTERFACE)

target_sources(Eigen INTERFACE
  FILE_SET HEADERS
    BASE_DIRS src
    FILES src/eigen.h src/vector.h src/matrix.h
)

install(TARGETS Eigen EXPORT eigenExport
  FILE_SET HEADERS DESTINATION include/Eigen)
install(EXPORT eigenExport NAMESPACE Upstream::
  DESTINATION lib/cmake/Eigen
)

Здесь заголовки, определённые в наборе заголовков, устанавливаются в include/Eigen. Путь установки автоматически становится каталогом включения, являющимся требованием использования для потребителей.

© 2000–2024 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html

Spec-Zone.ru

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