Spec-Zone.ru › CMake 3.7

cmake-developer(7)

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

Введение

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

Разрешённый подмножество C++

CMake требуется для компиляции с устаревшими компиляторами C++ и реализациями стандартной библиотеки. Некоторые распространённые конструкции C++ не могут быть использованы в CMake для компиляции с такими инструментальными цепочками.

std::auto_ptr

Шаблон std::auto_ptr устарел в C++11. Мы хотим его использовать, чтобы компилировать на компиляторах C++98, но не хотим отключать предупреждения компилятора о устаревших интерфейсах в целом. Вместо этого используйте макрос CM_AUTO_PTR.

size_t

У различных реализаций есть разные реализации size_t. При присваивании результата .size() на контейнер, например, результат нужно присвоить к size_t, а не к std::size_t, unsigned int или подобным типам.

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

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

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

При добавлении первой поддерживаемой функции к определённому CompilerId, необходимо указать поддержку всех функций, известных CMake (См. CMAKE_C_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES соответственно), где доступно для компилятора. Убедитесь, что CMAKE_<LANG>_STANDARD_DEFAULT установлено на вычисленную внутреннюю переменную CMAKE_<LANG>_STANDARD_COMPUTED_DEFAULT для версий компиляторов, которые должны быть поддержаны.

Разумно сначала записать функции для последней версии определённого CompilerId, а затем работать в обратном порядке. Разумно попытаться создать непрерывный ряд версий релизов функций компилятора. Пробелы в диапазоне указывают на неправильную запись функций для промежуточных релизов.

В целом, функции делаются доступными для определённой версии, если поставщик компилятора документально подтверждает доступность функции с этой версией. Обратите внимание, что иногда частично реализованные функции, по-видимому, работают в предыдущих выпусках (например, cxx_constexpr в GNU 4.6, хотя доступность документирована в GNU 4.7), и иногда поставщики компиляторов документально подтверждают доступность функций, хотя поддерживающая инфраструктура недоступна (например, __has_feature(cxx_generic_lambdas) указывает на недоступность в Clang 3.4, хотя она документирована как доступная, и исправлена в Clang 3.5). Аналогичные случаи для других компиляторов и версий необходимо расследовать при расширении CMake для их поддержки.

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

Специфичные для стандарта/компилятора переменные, такие как CMAKE_CXX98_COMPILE_FEATURES, намеренно не документированы. Они существуют только для реализации, специфичной для компилятора, добавления флага компиляции -std для компиляторов, которые нуждаются в этом.

Справка

В каталоге Help находятся исходные файлы справочной документации CMake. Они написаны с использованием синтаксиса разметки reStructuredText и обрабатываются Sphinx для генерации справочных руководств CMake.

Маркеры разметки

Помимо использования Sphinx для генерации справочных руководств CMake, мы также используем реализованный на C++ процессор документов для вывода документов для командной строки --help-* опций. Он поддерживает подмножество разметки reStructuredText. При написании или изменении документов убедитесь, что справка командной строки выглядит правильно помимо генерируемых Sphinx html и man-страниц.

Процессор справки командной строки поддерживает следующие конструкции, определённые reStructuredText, Sphinx и расширением CMake для Sphinx.

Директивы области CMake
Директивы, определённые в области CMake для определения объектов документации CMake, отображаются в выводе справки командной строки так, как будто строки являются обычным текстом абзаца с интерпретацией.
Интерпретируемые текстовые роли области CMake
Интерпретируемые текстовые роли, определённые в области CMake для перекрёстных ссылок на объекты документации CMake, заменяются их текстом ссылки в выводе справки командной строки. Другие роли выводятся буквально и не обрабатываются.
code-block directive
Добавить блок с литерными данными без интерпретации. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и со всеми обычными отступами, заменёнными одним пробелом.
include directive
Включить другой файл исходного документа. Процессор справки командной строки выводит включенный документ в строку с запрашивающим документом.
literal block after ::
Абзац, заканчивающийся ::, за которым следует пустая строка, рассматривает следующий отступающий блок как литерный текст без интерпретации. Процессор справки командной строки выводит :: буквально и выводит содержимое блока со всеми обычными отступами, заменёнными одним пробелом.
note directive
Выделить заметку на полях. Процессор справки командной строки выводит содержимое блока так, как будто строки являются обычным текстом абзаца с интерпретацией.
parsed-literal directive
Добавить литерный блок с интерпретацией разметки. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и со всеми обычными отступами, заменёнными одним пробелом.
productionlist directive
Отображать грамматические конструкции без контекста. Процессор справки командной строки выводит содержимое блока так, как будто строки являются обычным текстом абзаца с интерпретацией.
replace directive
Определить замену для |substitution|. Процессор справки командной строки требует, чтобы замена подстановки была определена перед её использованием.
|substitution| reference
Ссылка на замену подстановки, ранее определённую директивой replace. Процессор справки командной строки производит замену и заменяет все символы новой строки в тексте замены на пробелы.
toctree directive
Включить другие источники документов в дерево документации «Содержание». Процессор справки командной строки выводит указанные документы в строку как часть запрашивающего документа.

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

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

Spec-Zone.ru

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