Spec-Zone.ru › CMake 3.6

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, который нельзя использовать в качестве возвращаемого значения функции. std::auto_ptr использовать нельзя. Используйте cmsys::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
Включить другие источники документов в дерево структуры оглавления. Процессор справки командной строки выводит ссылаемые документы в строку как часть ссылающегося документа.

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

Явные блоки разметки, не соответствующие перечисленным выше директивам, удаляются из вывода справки командной строки. Не используйте их, за исключением обычных .. комментариев, которые также удаляются Sphinx.

Обратите внимание, что вложенные отступы блоков не распознаются процессором справки командной строки. Поэтому:

  • Явные блоки разметки распознаются только в том случае, если они не отступлены внутри других блоков.
  • Блоки литералов после абзацев, оканчивающихся на ::, но не на верхнем уровне отступа, могут потреблять все отступающие строки, которые следуют за ними.

Постарайтесь избегать таких случаев на практике.

Область CMake

CMake добавляет область Sphinx под названием cmake, также называемую «областью CMake». Она определяет несколько типов «объектов» для документации CMake:

command
Команда языка CMake.
generator
Родной генератор системы сборки CMake. Смотрите опцию cmake(1) командной утилиты.
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

Подписи команд должны быть помечены как обычные блоки литералов, а не как 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) или концепции (Импортированные целевые задачи).

Если свойство, команда или переменная концептуально связаны с другими, например, связаны с описанием системы сборки, выражениями генератора или 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 блок Комментарии в строке в формате:

#.rst:
# <module-name>
# -------------
#
# <reStructuredText documentation of module>

или блок Комментарии в скобках в формате:

#[[.rst:
<module-name>
-------------

<reStructuredText documentation of module>
#]]

Можно использовать любое количество = в открывающих и закрывающих скобках, при условии что они совпадают. Содержимое строки, содержащей закрывающую скобку, исключается, если и только если строка начинается с #.

Дополнительные такие комментарии .rst: могут появляться в любом месте файла модуля. Все такие комментарии должны начинаться с # в первом столбце.

Например, модуль Modules/Findxxx.cmake может содержать:

#.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()

После верхнего блока документации оставьте пустую строку, а затем добавьте блок авторских прав и лицензии, подобный этому (измените только диапазон года и имя)

#=============================================================================
# Copyright 2009-2011 Your Name
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
#  License text for the above reference.)

Протестируйте форматирование документации, запустив cmake --help-module <module-name>, а также включив опции SPHINX_HTML и SPHINX_MAN для построения документации. Измените комментарии, пока сгенерированная документация не будет удовлетворительной. Чтобы файл .cmake в этом каталоге не отображался в документации по модулям, просто удалите файл Help/module/<module-name>.rst и запись Help/manual/cmake-modules.7.rst в файле toctree.

Модули поиска

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

Основная задача модуля поиска — определить, существует ли пакет на системе, установить переменную <package>_FOUND для отражения этого и предоставить любые переменные, макросы и импортированные цели, необходимые для использования пакета. Модуль поиска полезен в тех случаях, когда библиотека 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_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.

Первое, что нужно — это документация. Система документации 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

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

После документации оставьте пустую строку, а затем добавьте блок авторских прав и лицензии

#=============================================================================
# Copyright 2009-2011 Your Name
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
#  License text for the above reference.)

Теперь необходимо найти фактические библиотеки и т. д. Код здесь, очевидно, будет различаться в зависимости от модуля (в этом, собственно, и заключается смысл модулей поиска), но для библиотек существует общая схема.

Сначала мы пытаемся использовать pkg-config для поиска библиотеки. Обратите внимание, что мы не можем полагаться на это, так как оно может быть недоступно, но это дает хорошую отправную точку.

find_package(PkgConfig)
pkg_check_modules(PC_Foo QUIET Foo)
END_OF_DOCUMENT_MARKER

Это должно определить некоторые переменные, начиная с 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(), она проверит запрошенную версию по сравнению с версией в pkg-config. Она также будет печатать сообщения по мере необходимости; обратите внимание, что если пакет был найден, он выведет содержимое первой требуемой переменной, чтобы указать, где он был найден.

На данном этапе нам нужно предоставить способ для пользователей модуля поиска связаться с библиотекой или библиотеками, которые были найдены. Существует два подхода, как обсуждалось в разделе «Модули поиска» выше. Традиционный подход с переменными выглядит следующим образом

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.6/manual/cmake-developer.7.html

Spec-Zone.ru

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