cmake-developer(7)
- Введение
- Разрешенный подмножество C++
- Добавление функций компиляции
- Справка
- Модули
Введение
Данное руководство предназначено для разработчиков, модифицирующих сам исходный код 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 необходимо указать поддержку функции для всех 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 - Включить другие исходные документы в дерево документации таблицы содержания. Процессор справки командной строки печатает ссылки на документы встроены в документ ссылки.
Встроенные конструкции разметки, не перечисленные выше, печатаются дословно в выводе справки командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые правильно выглядят в исходном виде, поэтому избегайте использования -escapes в пользу встроенных литералов, когда это возможно.
Явные блоки разметки, не соответствующие перечисленным директивам, удаляются из вывода справки командной строки. Не используйте их, за исключением обычных .. комментариев, которые также удаляются Sphinx.
Обратите внимание, что вложенные отступы блоков не распознаются процессором справки командной строки. Поэтому:
- Явные блоки разметки распознаются только в том случае, если они не отступают внутри других блоков.
- Литеральные блоки после абзацев, заканчивающихся
::, но не на верхнем уровне отступа, могут потреблять все отступаемые строки, следующие за ними.
Постарайтесь избегать этих случаев на практике.
Область CMake
CMake добавляет домен Sphinx, называемый cmake, также называемый «доменом CMake». Он определяет несколько типов «объектов» для документации CMake:
-
command - Команда языка CMake.
-
generator - Генератор системы сборки CMake. См.
cmake(1)командную утилиту и параметр-G. -
manual - Справочная страница CMake, например,
cmake-developer(7). -
module - Модуль CMake. См.
cmake-modules(7)справочную страницу и командуinclude(). -
policy - Политика CMake. См.
cmake-policies(7)справочную страницу и командуcmake_policy(). -
prop_cache, prop_dir, prop_gbl, prop_sf, prop_inst, prop_test, prop_tgt - Свойство кэша, директории, глобальное, исходный файл, установленный файл, тест или целевой объект соответственно. См.
cmake-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.8/manual/cmake-developer.7.html