Spec-Zone.ru › CMake 3.10

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

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

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

Подписи команд должны быть помечены как обычные блоки литералов, а не как code-blocks CMake.

Подписи отделяются от предыдущего содержимого заголовком раздела. То есть используйте:

... 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), свойству цели (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 для отражения этого и предоставить все переменные, макросы и импортированные целевые элементы, необходимые для использования пакета. Модуль поиска полезен в тех случаях, когда пакет 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.10/manual/cmake-developer.7.html

Spec-Zone.ru

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