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 необходимо указать поддержку функции для всех CompilerId, которые уже имеют одну или несколько поддерживаемых функций, если новая функция доступна для любой версии компилятора.
При добавлении первой поддерживаемой функции для конкретного CompilerId необходимо указать поддержку всех функций, известных cmake (см. CMAKE_C_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES соответственно), если они доступны для компилятора. Убедитесь, что CMAKE_<LANG>_STANDARD_DEFAULT установлено на вычисленную внутреннюю переменную CMAKE_<LANG>_STANDARD_COMPUTED_DEFAULT для версий компиляторов, которые должны поддерживаться.
Разумно сначала записать функции для самой последней версии конкретного CompilerId, а затем двигаться назад. Разумно пытаться создать непрерывный ряд версий выпусков функций компилятора. Пробелы в диапазоне указывают на неправильную запись функций для промежуточных релизов.
Обычно функции становятся доступными для конкретной версии, если поставщик компилятора документирует доступность функции с этой версией. Обратите внимание, что иногда частично реализованные функции кажутся функциональными в предыдущих выпусках (например, cxx_constexpr в GNU 4.6, хотя доступность документирована в GNU 4.7), а иногда поставщики компиляторов документируют доступность функций, хотя поддерживающая инфраструктура недоступна (например, __has_feature(cxx_generic_lambdas) указывает на недоступность в Clang 3.4, хотя она документирована как доступная, и исправлена в Clang 3.5). При расширении CMake для поддержки других компиляторов и версий необходимо изучить подобные случаи.
Когда поставщик выпускает новую версию известного компилятора, поддерживающую ранее недоступную функцию, и для этого компилятора уже есть известные функции, функция должна быть указана как поддерживаемая в CMake для этой версии компилятора как можно скорее.
Специфичные для стандарта/компилятора переменные, такие как CMAKE_CXX98_COMPILE_FEATURES, намеренно не документированы. Они существуют только для реализации специфичной для компилятора добавления флага компиляции -std для компиляторов, которым это нужно.
Справка
В каталоге Help находятся исходные файлы руководства по справке CMake. Они написаны с использованием синтаксиса разметки reStructuredText и обрабатываются Sphinx для генерации руководств по справке CMake.
Маркировочные конструкции
Помимо использования Sphinx для генерации руководств по справке CMake, мы также используем реализованный на C++ процессор документов для вывода документов для параметров командной строки --help-*. Он поддерживает подмножество маркировки reStructuredText. При написании или изменении документов убедитесь, что справка командной строки выглядит хорошо помимо сгенерированных Sphinx html и man-страниц.
Процессор справки командной строки поддерживает следующие конструкции, определённые в reStructuredText, Sphinx и расширении CMake для Sphinx.
- Директивы области CMake
- Директивы, определённые в области CMake для определения объектов документации CMake, выводятся в выводе справки командной строки, как если бы строки были обычным текстом абзаца с интерпретацией.
- Интерпретируемые текстовые роли области CMake
- Интерпретируемые текстовые роли, определённые в области CMake для перекрёстных ссылок на объекты документации CMake, заменяются их текстом ссылки в выводе справки командной строки. Другие роли выводятся буквально и не обрабатываются.
-
code-block directive - Добавить блок кода с литералами без интерпретации. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и со стандартным отступом, заменённым одним пробелом.
-
include directive - Включить другой файл исходного документа. Процессор справки командной строки выводит включённый документ в строку с документом, который его ссылается.
-
literal block after :: - Абзац, заканчивающийся
::, за которым следует пустая строка, обрабатывает следующий отступающий блок как текст с литералами без интерпретации. Процессор справки командной строки выводит::буквально, а содержимое блока — со стандартным отступом, заменённым одним пробелом. -
note directive - Выделить примечание. Процессор справки командной строки выводит содержимое блока, как если бы строки были обычным текстом абзаца с интерпретацией.
-
parsed-literal directive - Добавить блок литералов с интерпретацией разметки. Процессор справки командной строки выводит содержимое блока без строки директивы в начале и со стандартным отступом, заменённым одним пробелом.
-
productionlist directive - Отобразить грамматические правила без контекста. Процессор справки командной строки выводит содержимое блока, как если бы строки были обычным текстом абзаца с интерпретацией.
-
replace directive - Определить замену
|substitution|. Процессору справки командной строки требуется определение замены перед её использованием. -
|substitution| reference - Ссылка на замену, определённую ранее директивой
replace. Процессор справки командной строки выполняет подстановку и заменяет все символы новой строки в тексте замены пробелами. -
toctree directive - Включить другие источники документов в дерево структуры оглавления. Процессор справки командной строки выводит ссылаемые документы в строку как часть ссылающегося документа.
Встроенные конструкции разметки, не перечисленные выше, выводятся буквально в выводе справки командной строки. Мы предпочитаем использовать встроенные конструкции разметки, которые выглядят правильно в исходной форме, поэтому избегайте использования -escapes в пользу встроенных литералов, когда это возможно.
Явные блоки разметки, не соответствующие перечисленным выше директивам, удаляются из вывода справки командной строки. Не используйте их, за исключением обычных .. комментариев, которые также удаляются Sphinx.
Обратите внимание, что вложенные отступы блоков не распознаются процессором справки командной строки. Поэтому:
- Явные блоки разметки распознаются только в том случае, если они не отступлены внутри других блоков.
- Блоки литералов после абзацев, оканчивающихся на
::, но не на верхнем уровне отступа, могут потреблять все отступающие строки, которые следуют за ними.
Постарайтесь избегать таких случаев на практике.
Область CMake
CMake добавляет область Sphinx под названием cmake, также называемую «областью CMake». Она определяет несколько типов «объектов» для документации CMake:
-
command - Команда языка CMake.
-
generator - Родной генератор системы сборки CMake. Смотрите опцию
cmake(1)командной утилиты. -
manual - Справочная страница CMake, например,
cmake-developer(7). -
module - Модуль CMake. Смотрите
cmake-modules(7)иinclude()команду. -
policy - Политика CMake. Смотрите
cmake-policies(7)иcmake_policy()команду. -
prop_cache, prop_dir, prop_gbl, prop_sf, prop_inst, prop_test, prop_tgt - Свойство кэша CMake, директории, глобальное свойство, исходного файла, установленного файла, теста или целевой задачи, соответственно. Смотрите
cmake-properties(7)иset_property()команду. -
variable - Переменная языка CMake. Смотрите
cmake-variables(7)иset()команду.
Объекты документации в домене CMake происходят из двух источников. Во-первых, расширение CMake для Sphinx преобразует каждый документ с именем в формате Help/<type>/<file-name>.rst в объект домена типа <type>. Имя объекта извлекается из заголовка документа, который ожидается в формате:
<object-name> -------------
и должен быть в начале или вблизи верха файла .rst перед любыми другими строками, начинающимися с буквы, цифры или <. Если такой заголовок не встречается в файле .rst, имя объекта — это <file-name>. Если заголовок появляется, ожидается, что <file-name> равно <object-name> с удаленными символами < и >.
Во-вторых, домен CMake предоставляет директивы для определения объектов внутри других документов:
.. command:: <command-name> This indented block documents <command-name>. .. variable:: <variable-name> This indented block documents <variable-name>.
Типы объектов, для которых нет доступной директивы, должны быть определены с использованием вышеуказанного первого подхода.
Перекрёстные ссылки
Sphinx использует интерпретируемые текстовые роли reStructuredText для обеспечения синтаксиса перекрестных ссылок. Домен CMake предоставляет для каждого типа объекта домена роль с тем же именем для перекрестной ссылки. Роли домена CMake — это встроенная разметка в форматах:
:type:`name` :type:`text <name>`
где type — тип объекта домена, а name — имя объекта домена. В первом формате текст ссылки будет name (или name(), если тип — command), а во втором формате — явный текст text. Например, код:
* The :command:`list` command. * The :command:`list(APPEND)` sub-command. * The :command:`list() command <list>`. * The :command:`list(APPEND) sub-command <list>`. * The :variable:`CMAKE_VERSION` variable. * The :prop_tgt:`OUTPUT_NAME_<CONFIG>` target property.
генерирует:
- Команда
list(). - Подкоманда
list(APPEND). - Команда
list() command. list(APPEND) sub-command.- Переменная
CMAKE_VERSION. - Свойство целевой задачи
OUTPUT_NAME_<CONFIG>.
Обратите внимание, что роли домена CMake отличаются от соглашений Sphinx и reStructuredText тем, что форма a<b>, без пробела перед <, интерпретируется как имя, а не текст ссылки с явной целевой задачей. Это необходимо, потому что мы часто используем <placeholders> в именах объектов, таких как OUTPUT_NAME_<CONFIG>. Форма a <b>, с пробелом перед <, всё ещё интерпретируется как текст ссылки с явной целевой задачей.
Стиль
Стиль: Заголовки разделов
При маркировке заголовков разделов делайте линию раздела такой же длины, как текст заголовка. Используйте только строку под заголовком, а не над ним. Например:
Title Text ----------
Заглавные буквы пишите с большой буквы для каждого существительного в заголовке.
Иерархия символов подчеркивания для заголовков разделов:
-
#: Группа руководств (часть) в главном документе -
*: Руководство (глава) заголовок -
=: Раздел внутри руководства -
-: Подраздел или заголовок документа объекта домена CMake -
^: Подподраздел или раздел документа объекта домена CMake -
": Абзац или подподраздел документа объекта домена CMake
Стиль: Отступы
Используйте два пробела для отступов. Используйте два пробела между предложениями в прозе.
Стиль: Длина строки
Предпочтительно ограничивать ширину строк 75-80 символами. Это не жёсткое ограничение, но написание новых абзацев с обёртыванием на 75 столбцах позволяет размещать дополнительный контент без значительного переформатирования.
Стиль: Проза
В прозе используйте американское написание.
Стиль: Начало блоков литералов
Предпочтительнее отмечать начало блоков литералов маркером :: в конце предыдущего абзаца. В случаях, когда следующий блок получает маркер code-block, поставьте один маркер : в конце предыдущего абзаца.
Стиль: Подписи команд CMake
Подписи команд должны быть помечены как обычные блоки литералов, а не как code-blocks CMake.
Подписи разделены от предыдущего контента заголовком раздела. То есть используйте:
... preceding paragraph. Normal Libraries ^^^^^^^^^^^^^^^^ :: add_library(<lib> ...) This signature is used for ...
Подписи команд должны оборачивать необязательные части в квадратные скобки и должны помечать список необязательных аргументов многоточием (...). Элементы подписи, которые задаются пользователем, должны быть указаны в угловых скобках и могут быть указаны в прозе с помощью синтаксиса inline-literal.
Стиль: Булевы константы
Используйте «OFF» и «ON» для булевых значений, которые могут быть изменены пользователем, таких как POSITION_INDEPENDENT_CODE. Такие свойства могут быть «включены» и «выключены». Используйте «True» и «False» для встроенных значений, которые не могут быть изменены после установки, таких как свойство IMPORTED целевой задачи сборки.
Стиль: Встроенные литералы
Помечайте ссылки на ключевые слова в подписях, имена файлов и другие технические термины с помощью синтаксиса inline-literal, например:
If ``WIN32`` is used with :command:`add_executable`, the :prop_tgt:`WIN32_EXECUTABLE` target property is enabled. That command creates the file ``<name>.exe`` on Windows.
Стиль: Перекрёстные ссылки
Помечайте ссылки, которые можно связать, как ссылки, включая повторения. Альтернатива, которая используется в Википедии (http://en.wikipedia.org/wiki/WP:REPEATLINK), заключается в том, чтобы ссылаться на ссылку только один раз в статье. Этот стиль не используется в документации CMake.
Стиль: Ссылка на концепции CMake
Если вы ссылаетесь на концепцию, соответствующую свойству, и эта концепция описана в руководстве высокого уровня, предпочтительнее ссылаться на раздел руководства, а не на свойство. Например:
This command creates an :ref:`Imported Target <Imported Targets>`.
вместо:
This command creates an :prop_tgt:`IMPORTED` target.
Последнее следует использовать только при ссылках на конкретное свойство.
Ссылки на разделы руководств не создаются автоматически при создании раздела, но код, такой как:
.. _`Imported Targets`:
создаёт подходящий якорь. Используйте имя якоря, которое соответствует имени соответствующего раздела. Ссылайтесь на якорь с помощью перекрёстной ссылки с указанным текстом.
Импортированные целевые задачи требуют, чтобы термин IMPORTED был помечен с осторожностью, особенно потому, что термин может относиться к ключевому слову команды (IMPORTED), свойству целевой задачи (IMPORTED) или концепции (Импортированные целевые задачи).
Если свойство, команда или переменная концептуально связаны с другими, например, связаны с описанием системы сборки, выражениями генератора или Qt, каждое соответствующее свойство, команда или переменная должны ссылаться на основное руководство, которое предоставляет информацию высокого уровня. Только конкретная информация, относящаяся к команде, должна быть в документации команды.
Стиль: Ссылки на объекты домена CMake
При ссылке на объекты домена CMake, такие как свойства, переменные, команды и т. д., предпочтительнее ссылаться на целевой объект и после этого указывать тип объекта. Например:
Set the :prop_tgt:`AUTOMOC` target property to ``ON``.
Вместо
Set the target property :prop_tgt:`AUTOMOC` to ``ON``.
Директива policy — исключение, и тип обычно указывается перед ссылкой:
If policy :prop_tgt:`CMP0022` is set to ``NEW`` the behavior is ...
Однако ссылки на себя нужно помечать синтаксисом inline-literal. Например, в документации команды add_executable() используйте
``add_executable``
а не
:command:`add_executable`
что используется в других местах.
Модули
Директория Modules содержит файлы модулей .cmake языка CMake.
Документация модуля
Для документирования модуля CMake Modules/<module-name>.cmake, измените Help/manual/cmake-modules.7.rst для ссылки на модуль в директиве toctree, в отсортированном порядке, как:
/module/<module-name>
Затем добавьте файл документации модуля Help/module/<module-name>.rst содержащий только строку:
.. cmake-module:: ../../Modules/<module-name>.cmake
Директива cmake-module будет сканировать файл модуля для извлечения разметки reStructuredText из блоков комментариев, начинающихся с .rst:. Добавьте в верхнюю часть Modules/<module-name>.cmake блок Комментарии в строке в формате:
#.rst: # <module-name> # ------------- # # <reStructuredText documentation of module>
или блок Комментарии в скобках в формате:
#[[.rst: <module-name> ------------- <reStructuredText documentation of module> #]]
Можно использовать любое количество = в открывающих и закрывающих скобках, при условии что они совпадают. Содержимое строки, содержащей закрывающую скобку, исключается, если и только если строка начинается с #.
Дополнительные такие комментарии .rst: могут появляться в любом месте файла модуля. Все такие комментарии должны начинаться с # в первом столбце.
Например, модуль Modules/Findxxx.cmake может содержать:
#.rst: # FindXxx # ------- # # This is a cool module. # This module does really cool stuff. # It can do even more than you think. # # It even needs two paragraphs to tell you about it. # And it defines the following variables: # # * VAR_COOL: this is great isn't it? # * VAR_REALLY_COOL: cool right? <code> #[========================================[.rst: .. command:: xxx_do_something This command does something for Xxx:: xxx_do_something(some arguments) #]========================================] macro(xxx_do_something) <code> endmacro()
После верхнего блока документации оставьте пустую строку, а затем добавьте блок авторских прав и лицензии, подобный этому (измените только диапазон года и имя)
#============================================================================= # Copyright 2009-2011 Your Name # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.)
Протестируйте форматирование документации, запустив cmake --help-module <module-name>, а также включив опции SPHINX_HTML и SPHINX_MAN для построения документации. Измените комментарии, пока сгенерированная документация не будет удовлетворительной. Чтобы файл .cmake в этом каталоге не отображался в документации по модулям, просто удалите файл Help/module/<module-name>.rst и запись Help/manual/cmake-modules.7.rst в файле toctree.
Модули поиска
«Модуль поиска» — это файл Modules/Find<package>.cmake, который должен загружаться командой find_package() при вызове для <package>.
Основная задача модуля поиска — определить, существует ли пакет на системе, установить переменную <package>_FOUND для отражения этого и предоставить любые переменные, макросы и импортированные цели, необходимые для использования пакета. Модуль поиска полезен в тех случаях, когда библиотека upstream не предоставляет пакет конфигурационного файла.
Традиционный подход заключается в использовании переменных для всего, включая библиотеки и исполняемые файлы: см. раздел Стандартные имена переменных ниже. Именно это делают большинство существующих модулей поиска, предоставляемых CMake.
Более современный подход заключается в поведении максимально похожем на файлы пакетов конфигурационных файлов, предоставляя импортированные целевые объекты. Это обеспечивает преимущество распространения требований по использованию зависимых целей для потребителей.
В любом случае (или даже при предоставлении как переменных, так и импортированных целевых объектов), модули поиска должны обеспечивать обратную совместимость со старыми версиями, имеющими то же имя.
Модуль FindFoo.cmake обычно загружается командой:
find_package(Foo [major[.minor[.patch[.tweak]]]]
[EXACT] [QUIET] [REQUIRED]
[[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
См. документацию find_package() для подробной информации о том, какие переменные устанавливаются для модуля поиска. Большинство из них обрабатывается с помощью FindPackageHandleStandardArgs.
Вкратце, модуль должен находить только версии пакета, совместимые с запрошенной версией, как описано в семействе переменных Foo_FIND_VERSION. Если Foo_FIND_REQUIRED установлено в true, модуль должен выдать FATAL_ERROR в случае, если пакет не найден. Если ни один из них не установлен в true, он должен выводить сообщение об ошибке, если не найдет пакет.
Пакеты, которые находят несколько полунезависимых частей (например, наборы библиотек), должны искать компоненты, перечисленные в Foo_FIND_COMPONENTS, если оно установлено, и устанавливать Foo_FOUND в true только в том случае, если для каждого искомого компонента <c>, который не был найден, Foo_FIND_REQUIRED_<c> не установлено в true. Аргумент HANDLE_COMPONENTS команды find_package_handle_standard_args() может быть использован для реализации этого.
Если Foo_FIND_COMPONENTS не установлено, какие модули ищутся и требуются — это определяется модулем поиска, но должно быть задокументировано.
Для внутренней реализации общепринято, что переменные, начинающиеся с подчеркивания, предназначены только для временного использования.
Как и все модули, модули поиска должны быть должным образом задокументированы. Для добавления модуля в документацию CMake следуйте инструкциям в разделе Документация модулей выше.
Стандартные имена переменных
Для модуля FindXxx.cmake, который использует подход установки переменных (вместо или дополнительно к созданию импортированных целевых объектов), для обеспечения согласованности между модулями поиска следует использовать следующие имена переменных. Обратите внимание, что все переменные начинаются с Xxx_, чтобы избежать конфликтов с другими модулями поиска; то же самое касается макросов, функций и импортированных целевых объектов.
-
Xxx_INCLUDE_DIRS - Окончательный набор каталогов включения, перечисленных в одной переменной для использования кодом клиента. Это не должно быть записью кэша.
-
Xxx_LIBRARIES - Библиотеки для линковки с использованием Xxx. Они должны включать полные пути. Это не должно быть записью кэша.
-
Xxx_DEFINITIONS - Определения для использования при компиляции кода, использующего Xxx. Это действительно не должно включать такие опции, как
-DHAS_JPEG, которые используется файлом исходного кода клиента, чтобы определить, следует ли#include <jpeg.h> -
Xxx_EXECUTABLE - Где найти инструмент Xxx.
-
Xxx_Yyy_EXECUTABLE - Где найти инструмент Yyy, который входит в состав Xxx.
-
Xxx_LIBRARY_DIRS - Необязательно, окончательный набор каталогов библиотек, перечисленных в одной переменной для использования кодом клиента. Это не должно быть записью кэша.
-
Xxx_ROOT_DIR - Где найти базовый каталог Xxx.
-
Xxx_VERSION_Yy - Ожидать версию Yy, если true. Убедитесь, что не более одной из этих переменных истинна.
-
Xxx_WRAP_Yy - Если False, не пытаться использовать соответствующую команду обертки CMake.
-
Xxx_Yy_FOUND - Если False, необязательная часть Yy системы Xxx недоступна.
-
Xxx_FOUND - Установите в значение false или не определено, если мы не нашли или не хотим использовать Xxx.
-
Xxx_NOT_FOUND_MESSAGE - Должно устанавливаться файлами конфигурации в том случае, если они установили
Xxx_FOUNDв значение FALSE. Содержащееся сообщение будет выводиться командойfind_package()иfind_package_handle_standard_args()для информирования пользователя о проблеме. -
Xxx_RUNTIME_LIBRARY_DIRS - Необязательно, путь поиска динамических библиотек во время выполнения для использования при запуске исполняемого файла, связанного с динамическими библиотеками. Список должен использоваться кодом пользователя для создания
PATHв Windows илиLD_LIBRARY_PATHв UNIX. Это не должно быть записью кэша. -
Xxx_VERSION - Полная строка версии найденного пакета, если есть. Обратите внимание, что многие существующие модули вместо этого предоставляют
Xxx_VERSION_STRING. -
Xxx_VERSION_MAJOR - Основная версия найденного пакета, если есть.
-
Xxx_VERSION_MINOR - Дополнительная версия найденного пакета, если есть.
-
Xxx_VERSION_PATCH - Версия исправления найденного пакета, если есть.
Следующие имена обычно не должны использоваться в файлах CMakeLists.txt, но обычно являются переменными кэша, которые пользователи могут редактировать и управлять поведением модулей поиска (например, вводом пути к библиотеке вручную)
-
Xxx_LIBRARY - Путь к библиотеке Xxx (например, используемый с
find_library()). -
Xxx_Yy_LIBRARY - Путь к библиотеке Yy, которая входит в систему Xxx. Она может быть или не быть необходимой для использования Xxx.
-
Xxx_INCLUDE_DIR - Где найти заголовки для использования библиотеки Xxx.
-
Xxx_Yy_INCLUDE_DIR - Где найти заголовки для использования библиотеки Yy системы Xxx.
Чтобы предотвратить перегрузку пользователей настройками конфигурации, старайтесь выносить как можно больше опций за пределы кэша, оставляя хотя бы одну опцию, которая может использоваться для отключения использования модуля или поиска не найденной библиотеки (например, Xxx_ROOT_DIR). По той же причине, отмечайте большинство опций кэша как расширенные. Для пакетов, предоставляющих как отладочные, так и релизные двоичные файлы, обычно создаются переменные кэша с суффиксом _LIBRARY_<CONFIG>, например Foo_LIBRARY_RELEASE и Foo_LIBRARY_DEBUG.
Хотя это стандартные имена переменных, вы должны обеспечить обратную совместимость для любых старых имен, которые фактически использовались. Убедитесь, что вы комментируете их как устаревшие, чтобы никто не начал их использовать.
Пример модуля поиска
Мы опишем, как создать простой модуль поиска для библиотеки Foo.
Первое, что нужно — это документация. Система документации CMake требует начать файл с маркера документации и именем модуля. Вы должны последовать этому простым описанием того, что делает модуль.
#.rst: # FindFoo # ------- # # Finds the Foo library #
Для некоторых пакетов может потребоваться больше описания. Если есть ограничения или другие детали, которые пользователи модуля должны знать, вы можете добавить дополнительные абзацы ниже. Затем вам нужно задокументировать, какие переменные и импортированные целевые объекты устанавливаются модулем, такие как
# This will define the following variables:: # # Foo_FOUND - True if the system has the Foo library # Foo_VERSION - The version of the Foo library which was found # # and the following imported targets:: # # Foo::Foo - The Foo library
Если пакет предоставляет макросы, они должны быть перечислены здесь, но могут быть задокументированы в месте их определения. Смотрите раздел Документация модулей выше для получения более подробной информации.
После документации оставьте пустую строку, а затем добавьте блок авторских прав и лицензии
#============================================================================= # Copyright 2009-2011 Your Name # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.)
Теперь необходимо найти фактические библиотеки и т. д. Код здесь, очевидно, будет различаться в зависимости от модуля (в этом, собственно, и заключается смысл модулей поиска), но для библиотек существует общая схема.
Сначала мы пытаемся использовать pkg-config для поиска библиотеки. Обратите внимание, что мы не можем полагаться на это, так как оно может быть недоступно, но это дает хорошую отправную точку.
find_package(PkgConfig) pkg_check_modules(PC_Foo QUIET Foo)END_OF_DOCUMENT_MARKER
Это должно определить некоторые переменные, начиная с PC_Foo_, которые содержат информацию из файла Foo.pc.
Теперь нам нужно найти библиотеки и включаемые файлы; мы используем информацию из pkg-config, чтобы дать подсказки CMake о том, где искать.
find_path(Foo_INCLUDE_DIR
NAMES foo.h
PATHS ${PC_Foo_INCLUDE_DIRS}
PATH_SUFFIXES Foo
)
find_library(Foo_LIBRARY
NAMES foo
PATHS ${PC_Foo_LIBRARY_DIRS}
)
Если у вас есть хороший способ получить версию (например, из заголовочного файла), вы можете использовать эту информацию для установки Foo_VERSION (хотя обратите внимание, что модули поиска традиционно использовали Foo_VERSION_STRING, поэтому вы можете захотеть установить оба). В противном случае попробуйте использовать информацию из pkg-config.
set(Foo_VERSION ${PC_Foo_VERSION})
Теперь мы можем использовать FindPackageHandleStandardArgs, чтобы выполнить большую часть оставшейся работы за нас.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Foo
FOUND_VAR Foo_FOUND
REQUIRED_VARS
Foo_LIBRARY
Foo_INCLUDE_DIR
VERSION_VAR Foo_VERSION
)
Это проверит, что REQUIRED_VARS содержат значения (которые не заканчиваются на -NOTFOUND) и установит Foo_FOUND соответствующим образом. Он также кэширует эти значения. Если Foo_VERSION установлено, и требуемая версия была передана в find_package(), она проверит запрошенную версию по сравнению с версией в pkg-config. Она также будет печатать сообщения по мере необходимости; обратите внимание, что если пакет был найден, он выведет содержимое первой требуемой переменной, чтобы указать, где он был найден.
На данном этапе нам нужно предоставить способ для пользователей модуля поиска связаться с библиотекой или библиотеками, которые были найдены. Существует два подхода, как обсуждалось в разделе «Модули поиска» выше. Традиционный подход с переменными выглядит следующим образом
if(Foo_FOUND)
set(Foo_LIBRARIES ${Foo_LIBRARY})
set(Foo_INCLUDE_DIRS ${Foo_INCLUDE_DIR})
set(Foo_DEFINITIONS ${PC_Foo_CFLAGS_OTHER})
endif()
Если было найдено более одной библиотеки, все они должны быть включены в эти переменные (см. раздел «Стандартные имена переменных» для получения дополнительной информации).
При предоставлении импортированных целей они должны быть простанствено-именными (отсюда и префикс Foo::); CMake распознает, что значения, переданные в target_link_libraries(), которые содержат :: в своём имени, предназначены для импортированных целей (а не просто имён библиотек) и выведут соответствующие диагностические сообщения, если такая цель не существует (см. политику CMP0028).
if(Foo_FOUND AND NOT TARGET Foo::Foo)
add_library(Foo::Foo UNKNOWN IMPORTED)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION "${Foo_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
)
endif()
Следует отметить, что INTERFACE_INCLUDE_DIRECTORIES и аналогичные свойства должны содержать только информацию о самом целевом объекте, а не о его зависимостях. Вместо этого эти зависимости также должны быть целевыми объектами, и CMake должно быть сообщено, что они являются зависимостями этого целевого объекта. CMake затем автоматически комбинирует всю необходимую информацию.
Тип целевого объекта IMPORTED, созданного в команде add_library(), всегда можно указать как тип UNKNOWN. Это упрощает код в случаях, когда могут быть найдены статические или динамические варианты, и CMake определит тип, проверив файлы.
Если библиотека доступна с несколькими конфигурациями, свойство целевого объекта IMPORTED_CONFIGURATIONS также должно быть заполнено:
if(Foo_FOUND)
if (NOT TARGET Foo::Foo)
add_library(Foo::Foo UNKNOWN IMPORTED)
endif()
if (Foo_LIBRARY_RELEASE)
set_property(TARGET Foo::Foo APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE
)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION_RELEASE "${Foo_LIBRARY_RELEASE}"
)
endif()
if (Foo_LIBRARY_DEBUG)
set_property(TARGET Foo::Foo APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG
)
set_target_properties(Foo::Foo PROPERTIES
IMPORTED_LOCATION_DEBUG "${Foo_LIBRARY_DEBUG}"
)
endif()
set_target_properties(Foo::Foo PROPERTIES
INTERFACE_COMPILE_OPTIONS "${PC_Foo_CFLAGS_OTHER}"
INTERFACE_INCLUDE_DIRECTORIES "${Foo_INCLUDE_DIR}"
)
endif()
Вариант RELEASE должен быть указан первым в свойстве, чтобы этот вариант был выбран, если пользователь использует конфигурацию, которая не является точной копией ни одной из перечисленных IMPORTED_CONFIGURATIONS.
Большинство переменных кэша должны быть скрыты в интерфейсе ccmake, если пользователь явно не попросит их отредактировать.
mark_as_advanced( Foo_INCLUDE_DIR Foo_LIBRARY )
Если этот модуль заменяет более старую версию, вы должны установить переменные совместимости, чтобы минимизировать возможные нарушения.
# compatibility variables
set(Foo_VERSION_STRING ${Foo_VERSION})
© 2000–2019 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.6/manual/cmake-developer.7.html