cmake-developer(7)
- Введение
- Добавление функций компиляции
- Справка
- Модули
Введение
Данное руководство предназначено для разработчиков, изменяющих сам исходный код CMake, и для авторов модулей, поддерживаемых извне.
Добавление функций компиляции
CMake сообщает об ошибке, если компилятор, чьи возможности известны, не сообщает о поддержке конкретной запрашиваемой функции. Компилятор считается имеющим известные возможности, если он сообщает о поддержке хотя бы одной функции.
При добавлении новой функции компиляции в CMake необходимо указать поддержку этой функции для всех CompilerIds, которые уже поддерживают одну или несколько функций, если новая функция доступна для любой версии компилятора.
При добавлении первой поддерживаемой функции для конкретного CompilerId необходимо указать поддержку всех функций, известных CMake (см. CMAKE_C_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES соответственно), если они доступны для компилятора. Убедитесь, что CMAKE_<LANG>_STANDARD_DEFAULT установлено в вычисленную внутреннюю переменную CMAKE_<LANG>_STANDARD_COMPUTED_DEFAULT для версий компиляторов, которые должны поддерживаться.
Разумно сначала записать функции для последней версии конкретного CompilerId, а затем работать в обратном порядке. Разумно пытаться создать непрерывный диапазон версий релизов функций компилятора. Пропуски в диапазоне указывают на неправильно записанные функции для промежуточных релизов.
Как правило, функции становятся доступными для определённой версии, если поставщик компилятора документирует доступность функции с этой версией. Обратите внимание, что иногда частично реализованные функции, по-видимому, работают в предыдущих релизах (например, cxx_constexpr в GNU 4.6, хотя доступность документирована в GNU 4.7), а иногда поставщики компиляторов документируют доступность функций, хотя поддерживающая инфраструктура недоступна (например, __has_feature(cxx_generic_lambdas) указывает на недоступность в Clang 3.4, хотя она документирована как доступная, и исправлена в Clang 3.5). Аналогичные случаи для других компиляторов и версий необходимо исследовать при расширении CMake для их поддержки.
Когда поставщик выпускает новую версию известного компилятора, поддерживающую ранее неподдерживаемую функцию, и для этого компилятора уже есть известные функции, функция должна быть указана как поддерживаемая в CMake для этой версии компилятора как можно скорее.
Специфические для стандарта/компилятора переменные, такие как CMAKE_CXX98_COMPILE_FEATURES, намеренно не документированы. Они существуют только для реализации специфичной для компилятора функции добавления флага компиляции -std для компиляторов, которые его нуждаются.
Справка
Директория Help содержит исходные файлы справочной документации CMake. Они написаны с использованием синтаксиса разметки reStructuredText и обрабатываются Sphinx для генерации справочной документации CMake.
Конструкции разметки
Помимо использования Sphinx для генерации справочной документации CMake, мы также используем обработчик документов, реализованный на C++, для вывода документов для опций командной строки --help-*. Он поддерживает подмножество разметки reStructuredText. При написании или изменении документов убедитесь, что справка командной строки выглядит хорошо, помимо сгенерированных Sphinx html и man страниц.
Обработчик справки командной строки поддерживает следующие конструкции, определённые reStructuredText, Sphinx и расширением CMake для Sphinx.
- Директивы области CMake
- Директивы, определённые в области CMake для определения объектов документации CMake, выводятся в справке командной строки как обычный текстовый абзац с интерпретацией.
- Интерпретируемые текстовые роли области CMake
- Интерпретируемые текстовые роли, определённые в области CMake для перекрёстных ссылок на объекты документации CMake, заменяются на текст ссылки в справке командной строки. Другие роли выводятся буквально и не обрабатываются.
-
code-block directive - Добавление блока литерального кода без интерпретации. Обработчик справки командной строки выводит содержимое блока без строки директивы и с заменой стандартного отступа на один пробел.
-
include directive - Включение другого файла документа. Обработчик справки командной строки выводит включённый документ внутри ссылающегося документа.
-
literal block after :: - Абзац, заканчивающийся
::, за которым следует пустая строка, обрабатывает следующий отступаемый блок как текстовый литерал без интерпретации. Обработчик справки командной строки выводит::буквально и выводит содержимое блока с заменой стандартного отступа на один пробел. -
note directive - Выделение примечания. Обработчик справки командной строки выводит содержимое блока, как если бы строки были обычным текстовым абзацем с интерпретацией.
-
parsed-literal directive - Добавление литерального блока с интерпретацией разметки. Обработчик справки командной строки выводит содержимое блока без строки директивы и с заменой стандартного отступа на один пробел.
-
productionlist directive - Вывод грамматических правил без контекста. Обработчик справки командной строки выводит содержимое блока, как если бы строки были обычным текстовым абзацем с интерпретацией.
-
replace directive - Определение замены для
|substitution|. Обработчик справки командной строки требует определения замены перед ссылкой на неё. -
|substitution| reference - Ссылка на замену, определённую ранее директивой
replace. Обработчик справки командной строки выполняет замену и заменяет все новые строки в тексте замены пробелами. -
toctree directive - Включение других источников документа в дерево документации Table-of-Contents. Обработчик справки командной строки выводит ссылаемые документы в строку в качестве части ссылающегося документа.
Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в справке командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходном виде, поэтому избегаем использования экранирования, отдавая предпочтение встроенным литералам, когда это возможно.
Явные блоки разметки, не соответствующие перечисленным выше директивам, удаляются из справки командной строки. Не используйте их, за исключением обычных .. комментариев, которые также удаляются Sphinx.
Обратите внимание, что вложенные отступы блоков не распознаются обработчиком справки командной строки. Следовательно:
- Явные блоки разметки распознаются только при отсутствии отступов внутри других блоков.
- Блоки литералов после абзацев, заканчивающихся
::, но не на верхнем уровне отступа, могут потреблять все отступаемые строки, следующие за ними.
Постарайтесь избегать этих случаев на практике.
Область CMake
CMake добавляет область Sphinx под названием cmake, также называемую «областью CMake». Она определяет несколько типов «объектов» для документации CMake.
-
command - Команда языка CMake.
-
generator - Нативный генератор системы построения CMake. См.
cmake(1)инструмент командной строки опцию-G. -
manual - Руководство CMake, например, это
cmake-developer(7)руководство. -
module - Модуль CMake. См.
cmake-modules(7)руководство иinclude()команду. -
policy - Политика CMake. См.
cmake-policies(7)руководство иcmake_policy()команду. -
prop_cache, prop_dir, prop_gbl, prop_sf, prop_inst, prop_test, prop_tgt - Свойство кэша CMake, директории, глобальное свойство, исходного файла, установленного файла, теста или целевого объекта, соответственно. См.
cmake-properties(7)руководство иset_property()команду. -
variable - Переменная языка CMake. См.
cmake-variables(7)руководство иset()команду.
Объекты документации в домене CMake берутся из двух источников. Во-первых, расширение CMake для Sphinx преобразует каждый документ, имеющий имя в формате Help/<type>/<file-name>.rst, в объект домена с типом <type>. Имя объекта извлекается из заголовка документа, который ожидается в формате:
<object-name> -------------
и должен появляться в начале или недалеко от начала файла .rst перед другими строками, начинающимися с буквы, цифры или <. Если такой заголовок не появляется в файле .rst, имя объекта — это <file-name>. Если заголовок присутствует, ожидается, что <file-name> равно <object-name> с удалёнными символами < и >.
Во-вторых, домен CMake предоставляет директивы для определения объектов внутри других документов:
.. command:: <command-name> This indented block documents <command-name>. .. variable:: <variable-name> This indented block documents <variable-name>.
Типы объектов, для которых нет доступных директив, должны быть определены с помощью первого подхода выше.
Перекрёстные ссылки
Sphinx использует интерпретированные текстовые роли reStructuredText для предоставления синтаксиса перекрёстных ссылок. Домен CMake предоставляет для каждого типа объекта домена роль с тем же именем для перекрёстной ссылки. Роли домена CMake — это встроенная разметка в форматах:
:type:`name` :type:`text <name>`
где type — тип объекта домена, а name — имя объекта домена. В первом формате текст ссылки будет name (или name(), если тип — command), а во втором формате — явным text. Например, код:
* The :command:`list` command. * The :command:`list(APPEND)` sub-command. * The :command:`list() command <list>`. * The :command:`list(APPEND) sub-command <list>`. * The :variable:`CMAKE_VERSION` variable. * The :prop_tgt:`OUTPUT_NAME_<CONFIG>` target property.
производит:
- Команда
list(). - Подкоманда
list(APPEND). - Команда
list() command. - Команда
list(APPEND) sub-command. - Переменная
CMAKE_VERSION. - Свойство целевого объекта
OUTPUT_NAME_<CONFIG>.
Обратите внимание, что роли домена CMake отличаются от конвенций Sphinx и reStructuredText тем, что форма a<b>, без пробела перед <, интерпретируется как имя, а не текст ссылки с явным целевым объектом. Это необходимо, потому что мы часто используем <placeholders> в именах объектов, таких как OUTPUT_NAME_<CONFIG>. Форма a <b>, с пробелом перед <, по-прежнему интерпретируется как текст ссылки с явным целевым объектом.
Стиль
Стиль: Заголовки разделов
При маркировке заголовков разделов делайте линию декорации раздела такой же длины, как текст заголовка. Используйте только линию ниже заголовка, а не выше. Например:
Title Text ----------
Заглавные буквы должны стоять в начале каждого существительного в заголовке.
Иерархия символов подчёркивания в заголовках разделов:
-
#: Группа руководства (часть) в главном документе -
*: Руководство (глава) заголовок -
=: Раздел внутри руководства -
-: Подраздел или заголовок документа объекта домена CMake -
^: Подподраздел или раздел документа объекта домена CMake -
": Абзац или подподраздел документа объекта домена CMake
Стиль: Отступы
Используйте два пробела для отступов. Используйте два пробела между предложениями в прозе.
Стиль: Длина строки
Предпочтительно ограничивать ширину строк 75-80 столбцами. Это не жёсткое ограничение, но написание новых абзацев с обёртыванием на 75 столбцах позволяет добавить дополнительный контент без значительного переформатирования.
Стиль: Проза
Используйте американскую орфографию в прозе.
Стиль: Начало текстовых блоков
Предпочтительно обозначать начало текстовых блоков маркером :: в конце предыдущего абзаца. В случаях, когда следующий блок имеет маркер code-block, поместите одиночный : в конце предыдущего абзаца.
Стиль: Подписи команд CMake
Подписи команд должны быть помечены как обычные текстовые блоки, а не как команды CMake code-blocks.
Подписи отделяются от предшествующего содержимого заголовком раздела. То есть используйте:
... preceding paragraph. Normal Libraries ^^^^^^^^^^^^^^^^ :: add_library(<lib> ...) This signature is used for ...
Подписи команд должны обертывать необязательные части в квадратные скобки и отмечать список необязательных аргументов многоточием (...). Элементы подписи, которые указываются пользователем, должны быть указаны в угловых скобках и могут быть указаны в прозе с использованием синтаксиса inline-literal.
Стиль: Булевы константы
Используйте «OFF» и «ON» для булевых значений, которые могут быть изменены пользователем, таких как POSITION_INDEPENDENT_CODE. Такие свойства могут быть «включены» и «выключены». Используйте «True» и «False» для внутренних значений, которые нельзя изменить после установки, таких как свойство IMPORTED целевого объекта построения.
Стиль: Встроенные литералы
Отмечайте ссылки на ключевые слова в подписях, имена файлов и другие технические термины с помощью синтаксиса inline-literal, например:
If ``WIN32`` is used with :command:`add_executable`, the :prop_tgt:`WIN32_EXECUTABLE` target property is enabled. That command creates the file ``<name>.exe`` on Windows.
Стиль: Перекрёстные ссылки
Помечайте ссылки, которые можно использовать в ссылках, в том числе повторяющиеся. Альтернативный подход, используемый Википедией (http://en.wikipedia.org/wiki/WP:REPEATLINK), заключается в том, чтобы ссылаться на ссылку только один раз в статье. В документации CMake этот стиль не используется.
Стиль: Ссылка на концепции CMake
Если вы ссылаетесь на концепцию, соответствующую свойству, и эта концепция описана в руководстве высокого уровня, предпочтительнее ссылаться на раздел руководства, а не на свойство. Например:
This command creates an :ref:`Imported Target <Imported Targets>`.
вместо:
This command creates an :prop_tgt:`IMPORTED` target.
Последний вариант следует использовать только при конкретной ссылке на свойство.
Ссылки на разделы руководства не создаются автоматически при создании раздела, но код, например:
.. _`Imported Targets`:
создаёт подходящий якорь. Используйте имя якоря, соответствующее названию соответствующего раздела. Ссылайтесь на якорь с помощью перекрёстной ссылки со специфицированным текстом.
Целевые импортированные объекты требуют, чтобы термин IMPORTED был помечен с особой осторожностью, потому что он может относиться к ключевому слову команды (IMPORTED), свойству целевого объекта (IMPORTED) или концепции (Импортированные целевые объекты).
Если свойство, команда или переменная концептуально связаны с другими (например, связаны с описанием системы построения, выражениями генератора или Qt), каждое соответствующее свойство, команда или переменная должны ссылаться на основное руководство, которое предоставляет информацию высокого уровня. Только конкретная информация, относящаяся к команде, должна быть в документации команды.
Стиль: Ссылка на объекты домена CMake
При ссылке на объекты домена CMake, такие как свойства, переменные, команды и т.д., предпочтительнее ссылаться на целевой объект и следовать этому типом объекта. Например:
Set the :prop_tgt:`AUTOMOC` target property to ``ON``.
Вместо
Set the target property :prop_tgt:`AUTOMOC` to ``ON``.
Директива policy является исключением, и тип обычно указывается перед ссылкой:
If policy :prop_tgt:`CMP0022` is set to ``NEW`` the behavior is ...
Однако, ссылки на себя с использованием синтаксиса inline-literal. Например, в документации команды add_executable() используйте
``add_executable``
а не
:command:`add_executable`
что используется в других местах.
Модули
Директория Modules содержит файлы модулей языка CMake .cmake.
Документация модуля
Для документирования модуля CMake Modules/<module-name>.cmake, измените Help/manual/cmake-modules.7.rst для ссылки на модуль в директиве toctree, в отсортированном порядке, как:
/module/<module-name>
Затем добавьте файл документации модуля Help/module/<module-name>.rst содержащий только строку:
.. cmake-module:: ../../Modules/<module-name>.cmake
Директива cmake-module будет сканировать файл модуля для извлечения разметки reStructuredText из блоков комментариев, которые начинаются с .rst:. В верхней части Modules/<module-name>.cmake, начните с следующего уведомления о лицензии:
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details.
После этого уведомления добавьте ПУСТУЮ строку. Затем добавьте документацию, используя блок комментария в строке следующего вида:
#.rst: # <module-name> # ------------- # # <reStructuredText documentation of module>
или блок комментария в скобках следующего вида:
#[[.rst: <module-name> ------------- <reStructuredText documentation of module> #]]
Любое количество = может быть использовано в открывающих и закрывающих скобках, при условии, что они совпадают. Содержимое строки, содержащей закрывающую скобку, исключается только в том случае, если строка начинается с #.
Дополнительные такие .rst: комментарии могут появляться в любом месте файла модуля. Все такие комментарии должны начинаться с # в первом столбце.
Например, модуль Modules/Findxxx.cmake может содержать:
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # FindXxx # ------- # # This is a cool module. # This module does really cool stuff. # It can do even more than you think. # # It even needs two paragraphs to tell you about it. # And it defines the following variables: # # * VAR_COOL: this is great isn't it? # * VAR_REALLY_COOL: cool right? <code> #[========================================[.rst: .. command:: xxx_do_something This command does something for Xxx:: xxx_do_something(some arguments) #]========================================] macro(xxx_do_something) <code> endmacro()
Протестируйте форматирование документации, выполнив cmake --help-module <module-name>, а также включив SPHINX_HTML и SPHINX_MAN опции для построения документации. Редактируйте комментарии до тех пор, пока сгенерированная документация не будет удовлетворительной. Чтобы файл .cmake в этом каталоге не отображался в документации по модулям, просто удалите файл Help/module/<module-name>.rst и запись в toctree Help/manual/cmake-modules.7.rst.
Поиск модулей
«Модуль поиска» — это файл Modules/Find<package>.cmake, который должен быть загружен командой find_package(), когда она вызвана для <package>.
Основная задача модуля поиска — определить, существует ли пакет в системе, установить переменную <package>_FOUND для отражения этого и предоставить любые переменные, макросы и импортированные целевые объекты, необходимые для использования пакета. Модуль поиска полезен в тех случаях, когда пакет вышестоящей библиотеки не предоставляет пакет файлов конфигурации.
Традиционный подход заключается в использовании переменных для всего, включая библиотеки и исполняемые файлы: см. раздел Стандартные имена переменных ниже. Именно так делают большинство существующих модулей поиска, предоставляемых CMake.
Более современный подход заключается в поведении как можно более похожим на файлы пакетов файлов конфигурации, предоставив импортированные целевые объекты. Это имеет преимущество распространения требований к использованию целевых объектов к потребителям.
В любом случае (или даже при предоставлении как переменных, так и импортированных целевых объектов), модули поиска должны обеспечивать обратную совместимость со старыми версиями, имеющими то же самое имя.
Модуль FindFoo.cmake обычно загружается командой:
find_package(Foo [major[.minor[.patch[.tweak]]]]
[EXACT] [QUIET] [REQUIRED]
[[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
См. документацию по find_package() для получения подробностей о том, какие переменные устанавливаются для модуля поиска. Большинство из них обрабатывается с помощью FindPackageHandleStandardArgs.
Вкратце, модуль должен находить только версии пакета, совместимые с запрошенной версией, как описано в переменных семейства Foo_FIND_VERSION. Если Foo_FIND_VERSION установлено в true, он должен избегать вывода сообщений, в том числе любых сообщений об отсутствии пакета. Если Foo_FIND_QUIETLY установлено в 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. Убедитесь, что не более одной из этих переменных может быть 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.11/manual/cmake-developer.7.html