cmake-buildsystem(7)
- Введение
Введение
Система сборки, основанная на 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, DLL C++/CLI), необходимо, чтобы библиотека не была 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 библиотек будут соблюдаться при компиляции исходных файлов в других целых целях. Кроме того, эти требования к использованию будут распространяться транзитивно на зависимости других целей.
Библиотеки объектов не могут использоваться как 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для целевого объекта.
id7
Свойства связывания целевого объекта
Они представляют собой спецификацию сборки для связывания целевого объекта.
-
LINK_LIBRARIES -
Список библиотек для связывания целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или библиотека модулей. Записи для обычных библиотек передаются компоновщику либо через пути к файлам ссылок, либо с флагами
-lили эквивалентными. Записи для библиотек объектов передаются компоновщику через пути к объектным файлам.Кроме того, для компиляции и связывания самого целевого объекта, требования использования распространяются из записей
LINK_LIBRARIES, называющих обычные библиотеки, библиотеки интерфейса, библиотеки объектов и импортированные целевые объекты, собранных над транзитивным замыканием их свойствINTERFACE_LINK_LIBRARIES. -
LINK_DIRECTORIES -
Новое в версии 3.13.
Список каталогов для компоновки целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или библиотека модулей. Каталоги передаются компоновщику с флагами
-Lили эквивалентными. -
LINK_OPTIONS -
Новое в версии 3.13.
Список параметров компоновки для компоновки целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или библиотека модулей. Параметры передаются компоновщику в качестве флагов в порядке их появления.
Параметры компоновки автоматически экранируются для оболочки.
-
LINK_DEPENDS -
Список файлов, от которых зависит компоновка целевого объекта, если это исполняемый файл, динамически подключаемая библиотека или библиотека модулей. Например, скрипты компоновщика, указанные с помощью
LINK_OPTIONS, могут быть перечислены здесь, чтобы изменения в них приводили к повторному связыванию бинарных файлов.
id8
Требования к использованию целевого объекта
Требования к использованию целевого объекта — это настройки, которые распространяются на потребителей, которые связывают целевой объект с помощью 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_. Например, 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 определяет ряд стандартных конфигураций:
DebugReleaseRelWithDebInfoMinSizeRel
В генераторах с несколькими конфигурациями переменная 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()
Интерфейсные библиотеки
Цепь библиотеки INTERFACE не компилирует исходные файлы и не создаёт артефакт библиотеки на диске, поэтому у неё нет 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 может необязательно содержать исходные файлы. Интерфейсная библиотека, содержащая исходные файлы, будет включена в качестве цели сборки в сгенерированной системе сборки. Она не компилирует исходные файлы, но может содержать пользовательские команды для генерации других исходных файлов. Кроме того, среды разработки покажут исходные файлы как часть цели для интерактивного чтения и редактирования.
Основное применение библиотек 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/v3.30/manual/cmake-buildsystem.7.html