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. Процессор справки командной строки выводит указанные документы встраиваемо, как часть документа, к которому он относится.
Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в выводе справки командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходном виде, поэтому избегайте использования -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, начните с следующего лицензионного уведомления:
# 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_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, если истинно. Убедитесь, что одновременно истинными могут быть не более одной из таких переменных.
-
Xxx_WRAP_Yy - Если ложь, не пытаться использовать соответствующую команду оболочки CMake.
-
Xxx_Yy_FOUND - Если ложь, необязательная часть 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.9/manual/cmake-developer.7.html