cmake-developer(7)
- Введение
- Добавление функций компиляции
- Справка
- Модули
Введение
Данное руководство предназначено для разработчиков, изменяющих саму исходную структуру CMake, и для тех, кто создаёт внешние модули.
Добавление функций компиляции
CMake сообщает об ошибке, если компилятор, чьи функции известны, не сообщает о поддержке конкретной запрошенной функции. Компилятор считается имеющим известные функции, если он сообщает о поддержке хотя бы одной функции.
При добавлении новой функции компиляции в CMake необходимо, следовательно, перечислить поддержку этой функции для всех CompilerId, которые уже поддерживают одну или несколько функций, если новая функция доступна для любой версии компилятора.
При добавлении первой поддерживаемой функции для конкретного CompilerId необходимо указать поддержку всех функций, известных cmake (См. CMAKE_C_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES соответственно), если они доступны для компилятора. Убедитесь, что CMAKE_<LANG>_STANDARD_DEFAULT установлено в вычисленную внутреннюю переменную CMAKE_<LANG>_STANDARD_COMPUTED_DEFAULT для версий компилятора, которые должны поддерживаться.
Целесообразно сначала записать функции для последней версии конкретного CompilerId, а затем работать в обратном порядке. Целесообразно попытаться создать непрерывный ряд версий выпусков функций компилятора. Пробелы в ряду указывают на неправильно записанные функции для промежуточных релизов.
Как правило, функции становятся доступными для конкретной версии, если поставщик компилятора документирует доступность функции с этой версией. Обратите внимание, что иногда частично реализованные функции кажутся функциональными в предыдущих выпусках (например, cxx_constexpr в GNU 4.6, хотя доступность документирована в GNU 4.7), и иногда поставщики компиляторов документируют доступность функций, хотя поддерживающая инфраструктура недоступна (например, __has_feature(cxx_generic_lambdas) указывает на недоступность в Clang 3.4, хотя она документирована как доступная, и исправлена в Clang 3.5). Аналогичные случаи для других компиляторов и версий необходимо изучить при расширении CMake для их поддержки.
Когда поставщик выпускает новую версию известного компилятора, поддерживающую ранее недоступную функцию, и для этого компилятора уже есть известные функции, функция должна быть указана как поддерживаемая в CMake для этой версии компилятора как можно скорее.
Специфичные для стандарта/компилятора переменные, такие как CMAKE_CXX98_COMPILE_FEATURES, намеренно не документированы. Они существуют только для реализации специфичной для компилятора задачи добавления -std флага компиляции для компиляторов, которым это необходимо.
Справка
В каталоге Help находятся исходные файлы руководства CMake по справке. Они написаны с использованием синтаксиса разметки reStructuredText и обрабатываются Sphinx для генерации руководств по справке CMake.
Конструкции разметки
Помимо использования Sphinx для генерации руководств по справке CMake, мы также используем реализованный на C++ процессор документов для вывода документов для опций справки --help-* командной строки. Он поддерживает подмножество разметки reStructuredText. При написании или изменении документов, пожалуйста, проверьте, что справка командной строки выглядит хорошо, помимо сгенерированных Sphinx html и man страниц.
Процессор справки командной строки поддерживает следующие конструкции, определённые reStructuredText, Sphinx и расширением CMake для Sphinx.
- Директивы области CMake
- Директивы, определённые в области CMake для определения объектов документации CMake, выводятся в справке командной строки так, как будто строки были обычным текстом абзаца с интерпретацией.
- Интерпретируемые текстовые роли области CMake
- Интерпретируемые текстовые роли, определённые в области CMake для перекрестных ссылок на объекты документации CMake, заменяются текстом ссылки в справке командной строки. Другие роли выводятся буквально и не обрабатываются.
-
code-block directive - Добавляет блок кода с литералом без интерпретации. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и с заменой общего отступа одним пробелом.
-
include directive - Включает другой файл исходного документа. Процессор справки командной строки выводит включённый документ в строку с документом, на который он ссылается.
-
literal block after :: - Абзац, заканчивающийся
::, за которым следует пустая строка, рассматривает следующий отстуженный блок как текстовый литерал без интерпретации. Процессор справки командной строки выводит::буквально и выводит содержимое блока, заменив общий отступ одним пробелом. -
note directive - Выделяет примечание в стороне. Процессор справки командной строки выводит содержимое блока так, как будто строки были обычным текстом абзаца с интерпретацией.
-
parsed-literal directive - Добавляет литеральный блок с интерпретацией разметки. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и с заменой общего отступа одним пробелом.
-
productionlist directive - Отображает производства грамматики без контекста. Процессор справки командной строки выводит содержимое блока так, как будто строки были обычным текстом абзаца с интерпретацией.
-
replace directive - Определяет замену
|substitution|. Процессору справки командной строки необходима замена подстановки, прежде чем она будет использована. -
|substitution| reference - Ссылка на замену подстановки, ранее определённую директивой
replace. Процессор справки командной строки выполняет подстановку и заменяет все новые строки в тексте замены пробелами. -
toctree directive - Включает другие источники документов в дерево документации о содержании. Процессор справки командной строки выводит ссылаемые документы в строку как часть ссылающегося документа.
Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в справке командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходной форме, поэтому избегайте использования -escapes в пользу встроенных литералов, когда это возможно.
Явные блоки разметки, не соответствующие перечисленным выше директивам, удаляются из вывода справки командной строки. Не используйте их, за исключением обычных .. комментариев, которые также удаляются Sphinx.
Обратите внимание, что вложенные отступы блоков не распознаются процессором справки командной строки. Поэтому:
- Явные блоки разметки распознаются только тогда, когда они не отступлены внутри других блоков.
- Блоки литералов после абзацев, заканчивающихся
::, но не на верхнем уровне отступа, могут потреблять все отступы, следующие за ними.
Старайтесь избегать таких случаев на практике.
Область CMake
CMake добавляет область Sphinx под названием cmake, также называемую «областью CMake». Она определяет несколько типов «объектов» для документации CMake:
-
command - Команда языка CMake.
-
generator - Родной генератор системы сборки CMake. См.
cmake(1)инструмент командной строки, параметр-G. -
manual - Справочная страница CMake, например, эта
cmake-developer(7). -
module - Модуль CMake. См.
cmake-modules(7)справочную страницу и командуinclude(). -
policy - Политика CMake. См.
cmake-policies(7)справочную страницу и командуcmake_policy(). -
prop_cache, prop_dir, prop_gbl, prop_sf, prop_inst, prop_test, prop_tgt - Свойство кэша CMake, директории, глобальное, исходный файл, установленный файл, тест или целевой объект соответственно. См.
cmake-properties(7)справочную страницу и командуset_property(). -
variable - Переменная языка CMake. См.
cmake-variables(7)справочную страницу и командуset().
Объекты документации в области CMake берут данные из двух источников. Во-первых, расширение CMake для Sphinx преобразует каждый документ с именем в формате Help/<type>/<file-name>.rst в объект области с типом <type>. Имя объекта извлекается из заголовка документа, который должен иметь вид:
<object-name> -------------
и должен находиться в начале или вблизи начала файла .rst перед другими строками, начинающимися с буквы, цифры или <. Если такой заголовок не встречается в файле .rst, имя объекта — <file-name>. Если заголовок есть, ожидается, что <file-name> равно <object-name> с удаленными символами < и >.
Во-вторых, область CMake предоставляет директивы для определения объектов внутри других документов:
.. command:: <command-name> This indented block documents <command-name>. .. variable:: <variable-name> This indented block documents <variable-name>.
Типы объектов, для которых нет доступных директив, должны быть определены с использованием первого подхода выше.
Перекрёстные ссылки
Sphinx использует интерпретированные текстовые роли reStructuredText для обеспечения синтаксиса перекрёстных ссылок. Область CMake предоставляет для каждого типа объекта области роль с тем же именем для перекрёстной ссылки на него. Роли области CMake — это встроенная разметка в форматах:
:type:`name` :type:`text <name>`
где type — тип объекта области, а name — имя объекта области. В первом формате текст ссылки будет name (или name() если тип — command), а во втором формате текст ссылки будет явным text. Например, код:
* The :command:`list` command. * The :command:`list(APPEND)` sub-command. * The :command:`list() command <list>`. * The :command:`list(APPEND) sub-command <list>`. * The :variable:`CMAKE_VERSION` variable. * The :prop_tgt:`OUTPUT_NAME_<CONFIG>` target property.
производит:
- Команда
list(). - Подкоманда
list(APPEND). - Команда
list() command. - Команда
list(APPEND) sub-command. - Переменная
CMAKE_VERSION. - Свойство целевого объекта
OUTPUT_NAME_<CONFIG>.
Обратите внимание, что роли области CMake отличаются от конвенции Sphinx и reStructuredText в том, что форма a<b>, без пробела перед <, интерпретируется как имя, а не текст ссылки с явным целевым объектом. Это необходимо, потому что мы часто используем <placeholders> в именах объектов, таких как OUTPUT_NAME_<CONFIG>. Форма a <b>, с пробелом перед <, всё ещё интерпретируется как текст ссылки с явным целевым объектом.
Стиль
Стиль: Заголовки разделов
При маркировке заголовков разделов делайте линию разметки раздела такой же длины, как текст заголовка. Используйте только линию ниже заголовка, а не выше. Например:
Title Text ----------
Заглавная буква пишется в начале каждого не-вспомогательного слова в заголовке.
Иерархия символов подчеркивания для заголовков разделов:
-
#: Группа руководств (часть) в главном документе -
*: Руководство (глава) заголовок -
=: Раздел в руководстве -
-: Подраздел или заголовок документа объекта области CMake -
^: Подподраздел или раздел документа объекта области CMake -
": Абзац или подподраздел документа объекта области CMake
Стиль: Пробелы
Используйте два пробела для отступов. Используйте два пробела между предложениями в прозе.
Стиль: Длина строки
Предпочтительно ограничивать ширину строк 75-80 столбцами. Это не жёсткое ограничение, но написание новых абзацев, обёрнутых в 75 столбцов, позволяет добавить небольшое содержание без существенного повторного обёртывания.
Стиль: Проза
В прозе используйте американскую орфографию.
Стиль: Начало блоков с литералами
Предпочтительно отмечать начало блоков с литералами маркёром :: в конце предшествующего абзаца. В случаях, когда последующий блок получает маркёр code-block, поместите один маркёр : в конце предшествующего абзаца.
Стиль: Подписи команд CMake
Подписи команд должны быть помечены как обычные блоки с литералами, а не как блоки CMake code-blocks.
Подписи отделяются от предшествующего содержимого заголовком раздела. То есть используйте:
... preceding paragraph. Normal Libraries ^^^^^^^^^^^^^^^^ :: add_library(<lib> ...) This signature is used for ...
Подписи команд должны оборачивать необязательные части в квадратные скобки и должны отмечать список необязательных аргументов многоточием (...). Элементы подписи, которые задаются пользователем, должны задаваться в угловых скобках и могут упоминаться в прозе с помощью синтаксиса inline-literal.
Стиль: Булевы константы
Используйте «OFF» и «ON» для булевых значений, которые может изменить пользователь, таких как POSITION_INDEPENDENT_CODE. Такие свойства могут быть «включены» и «выключены». Используйте «True» и «False» для встроенных значений, которые не могут быть изменены после установки, таких как свойство IMPORTED целевого объекта сборки.
Стиль: Встроенные литералы
Помечайте ссылки на ключевые слова в подписях, имена файлов и другие технические термины с помощью синтаксиса inline-literal , например:
If ``WIN32`` is used with :command:`add_executable`, the :prop_tgt:`WIN32_EXECUTABLE` target property is enabled. That command creates the file ``<name>.exe`` on Windows.
Стиль: Перекрёстные ссылки
Помечайте ссылки, которые можно использовать как ссылки, включая повторения. Альтернатива, которая используется Википедией (http://en.wikipedia.org/wiki/WP:REPEATLINK), заключается в том, чтобы ссылаться на ссылку только один раз на статью. Этот стиль не используется в документации CMake.
Стиль: Ссылка на концепции CMake
Если вы ссылаетесь на концепцию, которая соответствует свойству, и эта концепция описана в руководстве высокого уровня, предпочтительно ссылаться на раздел руководства вместо свойства. Например:
This command creates an :ref:`Imported Target <Imported Targets>`.
вместо:
This command creates an :prop_tgt:`IMPORTED` target.
Последнее следует использовать только при упоминании конкретно свойства.
Ссылки на разделы руководств не создаются автоматически при создании раздела, но код, такой как:
.. _`Imported Targets`:
создаёт подходящий якорь. Используйте имя якоря, соответствующее имени соответствующего раздела. Ссылайтесь на якорь с помощью перекрёстной ссылки со специфицированным текстом.
Для целевых импортированных объектов термин IMPORTED должен быть помечен с осторожностью, потому что он может относиться к ключевому слову команды (IMPORTED), свойству целевого объекта (IMPORTED) или концепции (Импортированные целевые объекты).
Когда свойство, команда или переменная концептуально связаны с другими, например, связаны с описанием системы сборки, выражениями генератора или Qt, каждое соответствующее свойство, команда или переменная должны ссылаться на основное руководство, которое предоставляет информацию высокого уровня. Только конкретная информация, относящаяся к команде, должна содержаться в документации команды.
Стиль: Ссылка на объекты области CMake
При ссылке на объекты области CMake, такие как свойства, переменные, команды и т. д., предпочтительно ссылаться на целевой объект и следовать этому типом объекта. Например:
Set the :prop_tgt:`AUTOMOC` target property to ``ON``.
Вместо
Set the target property :prop_tgt:`AUTOMOC` to ``ON``.
Директива policy — исключение, и тип обычно упоминается перед ссылкой:
If policy :prop_tgt:`CMP0022` is set to ``NEW`` the behavior is ...
Однако ссылки на себя помечены синтаксисом inline-literal. Например, в документации команды add_executable() используйте
``add_executable``
а не
:command:`add_executable`
что используется в других местах.
Модули
Директория Modules содержит файлы модулей языка CMake .cmake.
Документация модулей
Для документирования модуля CMake Modules/<module-name>.cmake, измените Help/manual/cmake-modules.7.rst для ссылки на модуль в директиве toctree, в отсортированном порядке, как:
/module/<module-name>
Затем добавьте файл документации модуля Help/module/<module-name>.rst, содержащий только строку:
.. cmake-module:: ../../Modules/<module-name>.cmake
Директива cmake-module будет сканировать файл модуля для извлечения разметки reStructuredText из блоков комментариев, которые начинаются с .rst:. В начале Modules/<module-name>.cmake, начните с следующего лицензионного уведомления:
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details.
После этого уведомления добавьте ПУСТУЮ строку. Затем добавьте документацию, используя блок комментария в строке в формате:
#.rst: # <module-name> # ------------- # # <reStructuredText documentation of module>
или блок комментария в скобках в формате:
#[[.rst: <module-name> ------------- <reStructuredText documentation of module> #]]
Любое количество = может быть использовано в открывающих и закрывающих скобках, при условии, что они совпадают. Содержимое строки, содержащей закрывающую скобку, исключается, если и только если строка начинается с #.
Дополнительные такие .rst: комментарии могут появляться где угодно в файле модуля. Все такие комментарии должны начинаться с # в первой колонке.
Например, модуль Modules/Findxxx.cmake может содержать:
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # FindXxx # ------- # # This is a cool module. # This module does really cool stuff. # It can do even more than you think. # # It even needs two paragraphs to tell you about it. # And it defines the following variables: # # * VAR_COOL: this is great isn't it? # * VAR_REALLY_COOL: cool right? <code> #[========================================[.rst: .. command:: xxx_do_something This command does something for Xxx:: xxx_do_something(some arguments) #]========================================] macro(xxx_do_something) <code> endmacro()
Проверьте форматирование документации, запустив cmake --help-module <module-name>, а также включив опции SPHINX_HTML и SPHINX_MAN для построения документации. Редактируйте комментарии, пока сгенерированная документация не станет удовлетворительной. Чтобы файл .cmake в этом каталоге не отображался в документации модулей, просто опустите файл Help/module/<module-name>.rst и запись toctree Help/manual/cmake-modules.7.rst.
Поиск Модулей
«Модуль поиска» — это файл Modules/Find<PackageName>.cmake, который загружается командой find_package() при вызове для <PackageName>.
Основной задачей модуля поиска является определение наличия пакета в системе, установка переменной <PackageName>_FOUND для отражения этого и предоставление любых переменных, макросов и импортированных целей, необходимых для использования пакета. Модуль поиска полезен в тех случаях, когда пакет upstream библиотеки не предоставляет пакет конфигурационного файла.
Традиционный подход заключается в использовании переменных для всего, включая библиотеки и исполняемые файлы: см. раздел Стандартные имена переменных ниже. Именно это делают большинство существующих модулей поиска, предоставляемых CMake.
Более современный подход заключается в поведении как можно более похожим на файлы пакетов конфигурационных файлов, предоставляя импортированные цели. Это позволяет распространять требования к использованию зависимостей на потребителей.
В любом случае (или даже при предоставлении как переменных, так и импортированных целей), модули поиска должны обеспечивать обратную совместимость со старыми версиями, имеющими то же имя.
Модуль FindFoo.cmake обычно загружается командой:
find_package(Foo [major[.minor[.patch[.tweak]]]]
[EXACT] [QUIET] [REQUIRED]
[[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
См. документацию по find_package() для получения подробной информации о том, какие переменные устанавливаются для модуля поиска. Большая часть из них обрабатывается с помощью FindPackageHandleStandardArgs.
Вкратце, модуль должен находить только версии пакета, совместимые с запрошенной версией, как описано переменными из семейства Foo_FIND_VERSION. Если Foo_FIND_QUIETLY установлено в значение true, модуль должен избегать вывода сообщений, включая любые жалобы на то, что пакет не найден. Если Foo_FIND_REQUIRED установлено в значение true, модуль должен выдать сообщение об ошибке FATAL_ERROR, если пакет не найден. Если ни одно из этих значений не установлено в true, модуль должен вывести сообщение, не являющееся ошибкой, если не может найти пакет.
Пакеты, которые находят несколько полунезависимых частей (например, наборы библиотек), должны искать компоненты, перечисленные в Foo_FIND_COMPONENTS, если оно установлено, и устанавливать Foo_FOUND в значение true только в том случае, если для каждого искомого компонента <c>, который не был найден, Foo_FIND_REQUIRED_<c> не установлено в значение true. Аргумент HANDLE_COMPONENTS команды find_package_handle_standard_args() можно использовать для реализации этого.
Если Foo_FIND_COMPONENTS не установлено, какие модули ищутся и требуются, зависит от модуля поиска, но должно быть задокументировано.
Для внутренней реализации общепринято, что переменные, начинающиеся с подчеркивания, предназначены только для временного использования.
Как и все модули, модули поиска должны быть должным образом задокументированы. Чтобы добавить модуль в документацию CMake, следуйте инструкциям в разделе Документация модулей выше.
Стандартные имена переменных
Для модуля FindXxx.cmake, который использует подход установки переменных (вместо или дополнительно к созданию импортированных целей), для сохранения согласованности между модулями поиска следует использовать следующие имена переменных. Обратите внимание, что все переменные начинаются с Xxx_, чтобы гарантировать, что они не будут конфликтовать с другими модулями поиска; то же самое относится к макросам, функциям и импортированным целям.
-
Xxx_INCLUDE_DIRS - Конечный набор каталогов включения, перечисленных в одной переменной для использования кодом клиента. Это не должно быть записью кэша.
-
Xxx_LIBRARIES - Библиотеки для связывания с использованием Xxx. Они должны включать полные пути. Это не должно быть записью кэша.
-
Xxx_DEFINITIONS - Определения для использования при компиляции кода, использующего Xxx. Это действительно не должно включать такие параметры, как
-DHAS_JPEG, которые клиентский файл исходного кода использует для определения, следует ли#include <jpeg.h>. -
Xxx_EXECUTABLE - Где найти инструмент Xxx.
-
Xxx_Yyy_EXECUTABLE - Где найти инструмент Yyy, который входит в Xxx.
-
Xxx_LIBRARY_DIRS - Необязательно, конечный набор каталогов библиотек, перечисленных в одной переменной для использования кодом клиента. Это не должно быть записью кэша.
-
Xxx_ROOT_DIR - Где найти базовый каталог Xxx.
-
Xxx_VERSION_Yy - Ожидать версию Yy, если true. Убедитесь, что не более одной из них истинна.
-
Xxx_WRAP_Yy - Если False, не пытайтесь использовать соответствующую команду обертки CMake.
-
Xxx_Yy_FOUND - Если False, необязательная часть Yy системы Xxx недоступна.
-
Xxx_FOUND - Установите в значение false или не определено, если мы не нашли или не хотим использовать Xxx.
-
Xxx_NOT_FOUND_MESSAGE - Должно устанавливаться файлами конфигурации в случае, если оно установило
Xxx_FOUNDв значение FALSE. Содержащееся сообщение будет выведено командойfind_package()иfind_package_handle_standard_args(), чтобы проинформировать пользователя о проблеме. -
Xxx_RUNTIME_LIBRARY_DIRS - Необязательно, путь поиска динамических библиотек во время выполнения для использования при запуске исполняемого файла, связанного с динамическими библиотеками. Список должен использоваться кодом пользователя для создания
PATHв Windows илиLD_LIBRARY_PATHв UNIX. Это не должно быть записью кэша. -
Xxx_VERSION - Полная строка версии найденного пакета, если таковая имеется. Обратите внимание, что многие существующие модули предоставляют
Xxx_VERSION_STRINGвместо этого. -
Xxx_VERSION_MAJOR - Главная версия найденного пакета, если таковая имеется.
-
Xxx_VERSION_MINOR - Вспомогательная версия найденного пакета, если таковая имеется.
-
Xxx_VERSION_PATCH - Версия исправления найденного пакета, если таковая имеется.
Следующие имена обычно не должны использоваться в файлах CMakeLists.txt, но обычно являются переменными кэша, которые пользователи могут редактировать и управлять поведением модулей поиска (например, вручную вводя путь к библиотеке).
-
Xxx_LIBRARY - Путь к библиотеке Xxx (например, используемый с
find_library()). -
Xxx_Yy_LIBRARY - Путь к библиотеке Yy, которая является частью системы Xxx. Она может быть или не быть необходимой для использования Xxx.
-
Xxx_INCLUDE_DIR - Где найти заголовки для использования библиотеки Xxx.
-
Xxx_Yy_INCLUDE_DIR - Где найти заголовки для использования библиотеки Yy системы Xxx.
Чтобы избежать перегрузки пользователей настройками, старайтесь по возможности избегать параметров кэша, оставляя, по крайней мере, один параметр, который может использоваться для отключения использования модуля или для поиска ненайденной библиотеки (например, Xxx_ROOT_DIR). По той же причине большинство параметров кэша помечайте как расширенные. Для пакетов, которые предоставляют как отладочные, так и релизные двоичные файлы, часто создаются переменные кэша с суффиксом _LIBRARY_<CONFIG>, например, Foo_LIBRARY_RELEASE и Foo_LIBRARY_DEBUG.
Хотя это стандартные имена переменных, вы должны предоставить обратную совместимость для любых старых имен, которые фактически использовались. Убедитесь, что вы прокомментировали их как устаревшие, чтобы никто не начал их использовать.
Пример модуля поиска
Мы опишем, как создать простой модуль поиска для библиотеки Foo.
Первое, что необходимо, это лицензионное уведомление.
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details.
Далее нам нужна документация модуля. Система документации CMake требует следовать за лицензионным уведомлением пустой строкой, а затем маркером документации и именем модуля. Следующей должна быть простая запись о том, что делает модуль.
#.rst: # FindFoo # ------- # # Finds the Foo library #
Для некоторых пакетов может потребоваться более подробное описание. Если есть какие-либо оговорки или другие детали, о которых пользователи модуля должны знать, вы можете добавить дополнительные абзацы ниже. Затем вам необходимо задокументировать, какие переменные и импортированные цели устанавливаются модулем, такие как
# This will define the following variables:: # # Foo_FOUND - True if the system has the Foo library # Foo_VERSION - The version of the Foo library which was found # # and the following imported targets:: # # Foo::Foo - The Foo library
Если пакет предоставляет макросы, они должны быть перечислены здесь, но могут быть задокументированы там, где они определены. См. раздел Документация модулей выше для получения дополнительных сведений.
Теперь необходимо найти фактические библиотеки и так далее. Код здесь, очевидно, будет отличаться от модуля к модулю (работа с этим, в конце концов, и есть смысл модулей поиска), но часто встречается общая схема для библиотек.
Сначала мы попытаемся использовать pkg-config для поиска библиотеки. Обратите внимание, что мы не можем полагаться на это, так как оно может быть недоступно, но это хорошее отправное значение.
find_package(PkgConfig) pkg_check_modules(PC_Foo QUIET Foo)
Это должно определить некоторые переменные, начинающиеся с PC_Foo_, которые содержат информацию из файла Foo.pc.
Теперь нам нужно найти библиотеки и включить файлы; мы используем информацию из pkg-config для предоставления подсказок CMake о том, где искать.
find_path(Foo_INCLUDE_DIR
NAMES foo.h
PATHS ${PC_Foo_INCLUDE_DIRS}
PATH_SUFFIXES Foo
)
find_library(Foo_LIBRARY
NAMES foo
PATHS ${PC_Foo_LIBRARY_DIRS}
)
Если у вас есть хороший способ получения версии (например, из заголовочного файла), вы можете использовать эту информацию для установки Foo_VERSION (хотя обратите внимание, что модули поиска традиционно использовали Foo_VERSION_STRING, поэтому вы можете захотеть установить оба). В противном случае попробуйте использовать информацию из pkg-config
set(Foo_VERSION ${PC_Foo_VERSION})
Теперь мы можем использовать FindPackageHandleStandardArgs, чтобы выполнить большую часть оставшейся работы за нас
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Foo
FOUND_VAR Foo_FOUND
REQUIRED_VARS
Foo_LIBRARY
Foo_INCLUDE_DIR
VERSION_VAR Foo_VERSION
)
Это проверит, что REQUIRED_VARS содержат значения (которые не заканчиваются на -NOTFOUND) и установит Foo_FOUND соответствующим образом. Он также кэширует эти значения. Если Foo_VERSION установлено, и требуемая версия была передана в find_package(), он проверит запрошенную версию по сравнению с версией в Foo_VERSION. Он также будет выводить сообщения при необходимости; обратите внимание, что если пакет был найден, он выведет содержимое первой требуемой переменной, чтобы указать, где он был найден.
На этом этапе мы должны предоставить способ для пользователей модуля поиска, чтобы связаться с библиотекой или библиотеками, которые были найдены. Существует два подхода, как обсуждалось в разделе «Модули поиска» выше. Традиционный подход с переменными выглядит так
if(Foo_FOUND)
set(Foo_LIBRARIES ${Foo_LIBRARY})
set(Foo_INCLUDE_DIRS ${Foo_INCLUDE_DIR})
set(Foo_DEFINITIONS ${PC_Foo_CFLAGS_OTHER})
endif()
Если было найдено более одной библиотеки, все они должны быть включены в эти переменные (см. раздел «Стандартные имена переменных» для получения дополнительной информации).
При предоставлении импортированных целей они должны быть именованными (отсюда и Foo:: префикс); CMake распознает, что значения, передаваемые в target_link_libraries(), которые содержат :: в своём имени, предназначены для импортированных целей (а не просто для имён библиотек), и будет выводить соответствующие диагностические сообщения, если эта цель не существует (см. политику CMP0028).
if(Foo_FOUND AND NOT TARGET Foo::Foo)
add_library(Foo::Foo UNKNOWN IMPORTED)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION "${Foo_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
)
endif()
Следует отметить, что INTERFACE_INCLUDE_DIRECTORIES и аналогичные свойства должны содержать только информацию о самой цели, а не о каких-либо её зависимостях. Вместо этого эти зависимости также должны быть целями, и CMake должно быть указано, что они являются зависимостями этой цели. CMake затем автоматически объединит всю необходимую информацию.
Тип IMPORTED цели, созданной в команде add_library(), всегда может быть задан как тип UNKNOWN. Это упрощает код в случаях, когда могут быть найдены статические или динамические варианты, и CMake определит тип, проанализировав файлы.
Если библиотека доступна с несколькими конфигурациями, свойство цели IMPORTED_CONFIGURATIONS также должно быть заполнено:
if(Foo_FOUND)
if (NOT TARGET Foo::Foo)
add_library(Foo::Foo UNKNOWN IMPORTED)
endif()
if (Foo_LIBRARY_RELEASE)
set_property(TARGET Foo::Foo APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION_RELEASE "${Foo_LIBRARY_RELEASE}"
)
endif()
if (Foo_LIBRARY_DEBUG)
set_property(TARGET Foo::Foo APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG
)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION_DEBUG "${Foo_LIBRARY_DEBUG}"
)
endif()
set_target_properties(Foo::Foo PROPERTIES
INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
)
endif()
Вариант RELEASE должен быть перечислен первым в свойстве, чтобы вариант был выбран, если пользователь использует конфигурацию, которая не является точным соответствием ни одной из перечисленных IMPORTED_CONFIGURATIONS.
Большинство переменных кэша должны быть скрыты в интерфейсе ccmake интерфейса, если пользователь явно не попросит их отредактировать.
mark_as_advanced( Foo_INCLUDE_DIR Foo_LIBRARY )
Если этот модуль заменяет более старую версию, вы должны установить переменные совместимости, чтобы вызвать наименьшее возможное нарушение.
# compatibility variables
set(Foo_VERSION_STRING ${Foo_VERSION})
© 2000–2019 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.13/manual/cmake-developer.7.html