Spec-Zone.ru › CMake 3.12

cmake-developer(7)

  • Введение
  • Добавление функций компиляции
  • Справка
    • Конструкции разметки
    • Область CMake
    • Перекрёстные ссылки
    • Стиль
      • Стиль: Заголовки разделов
      • Стиль: Пробелы
      • Стиль: Длина строки
      • Стиль: Проза
      • Стиль: Начало блоков литералов
      • Стиль: Подписи команд CMake
      • Стиль: Булевы константы
      • Стиль: Встроенные литералы
      • Стиль: Перекрёстные ссылки
      • Стиль: Ссылка на концепции CMake
      • Стиль: Ссылка на объекты области CMake
  • Модули
    • Документация модуля
    • Модули поиска
      • Стандартные имена переменных
      • Пример модуля поиска

Введение

Данное руководство предназначено для разработчиков, модифицирующих саму исходную структуру CMake, и для авторов внешних модулей.

Добавление функций компиляции

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

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

При добавлении первой поддерживаемой функции для конкретного 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
Включить другие источники документов в дерево документации таблицы содержания. Обработчик справки командной строки выводит ссылаемые документы в строку как часть ссылающегося документа.

Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в выводе справки командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходном виде, поэтому избегайте использования -escape, отдавая предпочтение встроенным литералам, когда это возможно.

Явные блоки разметки, не соответствующие перечисленным директивам, удаляются из вывода справки командной строки. Не используйте их, кроме обычных .. комментариев, которые также удаляются 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-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 и записи Help/manual/cmake-modules.7.rst в toctree.

Поиск модулей

«Модуль поиска» — это файл Modules/Find<package>.cmake, который должен загружаться командой find_package() при вызове для <package>.

Основная задача модуля поиска — определить, существует ли пакет в системе, установить переменную <package>_FOUND, отражающую это, и предоставить любые переменные, макросы и импортированные цели, необходимые для использования пакета. Модуль поиска полезен в тех случаях, когда библиотека предшественника не предоставляет пакета конфигурационного файла.

Традиционный подход заключается в использовании переменных для всего, включая библиотеки и исполняемые файлы: см. раздел Стандартные имена переменных ниже. Именно это делают большинство существующих модулей поиска, предоставляемых 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 установлено в значение «истина», он должен избегать вывода сообщений, включая сообщения об ошибках, что пакет не найден. Если Foo_FIND_REQUIRED установлено в значение «истина», модуль должен выдать сообщение FATAL_ERROR, если пакет не найден. Если ни одно из них не установлено в значение «истина», он должен вывести сообщение о неисправности, если не может найти пакет.

Пакеты, которые находят несколько полунезависимых частей (например, наборы библиотек), должны искать компоненты, перечисленные в Foo_FIND_COMPONENTS, если оно задано, и устанавливать Foo_FOUND в значение «истина» только в том случае, если для каждого искомого компонента <c>, который не был найден, Foo_FIND_REQUIRED_<c> не установлено в значение «истина». Аргумент HANDLE_COMPONENTS команды find_package_handle_standard_args() можно использовать для реализации этого.

Если Foo_FIND_COMPONENTS не задано, какие модули следует искать и какие требуются, зависит от модуля поиска, но это должно быть задокументировано.

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

Как и все модули, модули поиска должны быть должным образом задокументированы. Чтобы добавить модуль в документацию CMake, следуйте инструкциям в разделе Документация модулей выше.

Стандартные имена переменных разработчика 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, если истина. Убедитесь, что максимум один из них верен.
Xxx_WRAP_Yy
Если ложь, не пытайтесь использовать соответствующую команду обёртки CMake.
Xxx_Yy_FOUND
Если ложь, необязательная часть Yy системы Xxx недоступна.
Xxx_FOUND
Устанавливается в значение «ложь» или не определяется, если мы не нашли или не хотим использовать Xxx.
Xxx_NOT_FOUND_MESSAGE
Должен устанавливаться файлами конфигурации в случае, если он установил Xxx_FOUND в значение «ложь». Содержимое сообщения будет выведено командой 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.12/manual/cmake-developer.7.html

Spec-Zone.ru

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