cmake-developer(7)
- Введение
- Разрешённый подмножество C++
- Добавление функций компиляции
- Справка
- Модули
Введение
Данное руководство предназначено для разработчиков, которые изменяют сам исходный код 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 необходимо указать поддержку функции для всех 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. Обработчик справки командной строки вставляет вставляемые документы в текущий документ.
Встроенные конструкции разметки, не указанные выше, выводятся буквально в справке по командной строке. Мы предпочитаем использовать встроенные конструкции разметки, которые корректно отображаются в исходном коде, поэтому избегайте использования экранирования -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, каталога, глобальное, исходный файл, установленный файл, тест или целевой объект соответственно. См.
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 блок Комментарии в строке в формате:
#.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 и запись 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_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. Убедитесь, что не более одной из этих переменных имеет значение 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(), она проверит запрошенную версию по отношению к версии в 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.5/manual/cmake-developer.7.html