Spec-Zone.ru › CMake 3.9

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
Включает другие источники документов в дерево документации Table-of-Contents. Процессор справки командной строки выводит указанные документы встраиваемо, как часть документа, к которому он относится.

Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в выводе справки командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходном виде, поэтому избегайте использования -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<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 установлено в значение 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, если истинно. Убедитесь, что одновременно истинными могут быть не более одной из таких переменных.
Xxx_WRAP_Yy
Если ложь, не пытаться использовать соответствующую команду оболочки CMake.
Xxx_Yy_FOUND
Если ложь, необязательная часть 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.9/manual/cmake-developer.7.html

Spec-Zone.ru

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