Руководство по стилю CMake
Мы ожидаем, что все скрипты CMake, которые являются следующими:
- В каталоге
scripts/
или vcpkg-*
В порту
следует следовать рекомендациям, изложенным в этом документе. Существующие скрипты пока не следуют этим рекомендациям; Ожидается, что мы будем продолжать обновлять старые скрипты, чтобы они соответствовали этим рекомендациям.
Эти рекомендации предназначены для создания стабильности в наших сценариях. Мы надеемся, что они сделают как вперед, так и обратную совместимость проще.
Рекомендации
За исключением вне параметров, мы всегда используем
cmake_parse_arguments()
не параметры функции или ссылаемся на${ARG<N>}
него.Это не обязательно нужно следовать за "вспомогательными функциями с локальным скриптом"
- В этом случае позиционные параметры должны быть помещены в объявление функции (а не с помощью
${ARG<N>}
), и должны быть названы в соответствии с локальными правилами (т. е.snake_case
). - Исключение: позиционные параметры, которые являются необязательными, следует указать имя с помощью
set(argument_name "${ARG<N>}")
проверкиARGC
.
- В этом случае позиционные параметры должны быть помещены в объявление функции (а не с помощью
Out-parameters должен быть первым параметром функции. Пример:
function(format out_var) cmake_parse_arguments(PARSE_ARGV 1 "arg" ...) # ... set(buffer "output") set("${out_var}" "${buffer}" PARENT_SCOPE) endfunction()
Нет неиспользуемых или неиспользуемых аргументов. Всегда проверяйте или
ARGN
arg_UNPARSED_ARGUMENTS
.FATAL_ERROR
если это возможно,WARNING
при необходимости для обратной совместимости.Все
cmake_parse_arguments
должны использоватьсяPARSE_ARGV
.Все
foreach
циклы должны использоватьIN LISTS
,IN ITEMS
илиRANGE
.Переменные
${ARGV}
и${ARGN}
не перенаправляются, за исключением полезных сообщений пользователю.- (т. е.,
message(FATAL_ERROR "blah was passed extra arguments: ${ARGN}")
)
- (т. е.,
Мы всегда используем функции, а не макросы или код верхнего уровня.
- Исключение: "макросы вспомогательного средства на основе скрипта". Иногда полезно определить небольшой макрос. Это необходимо сделать смешно, и функции должны быть предпочтительнее.
- Исключение:
vcpkg.cmake
'sfind_package
.
Скрипты в дереве сценариев не должны ожидать наблюдаемых изменений в рамках нормальной работы.
- Пример нарушения:
vcpkg_acquire_msys()
имеет жестко закодированные пакеты и версии, которые требуют обновления с течением времени из-за удаления старых пакетов MSYS. - Пример исключения:
vcpkg_from_sourceforge()
содержит список зеркал, для которых требуется обслуживание, но не влияет на наблюдаемое поведение вызывающих объектов.
- Пример нарушения:
Правила для кавычки: в CMake имеется три типа аргументов : неquoted (), кавычки (
foo(BAR)
foo("BAR")
) и квадратные скобки (foo([[BAR]])
). Чтобы правильно провести кавычки, выполните следующие правила:Если аргумент содержит расширение
${...}
переменной, он должен быть кавычек.Исключение: расширение переменной splat, когда одна переменная будет передана функции в виде нескольких аргументов. В этом случае аргумент должен быть
${foo}
:vcpkg_list(SET working_directory) if(DEFINED "arg_WORKING_DIRECTORY") vcpkg_list(SET working_directory WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}") endif() # calls do_the_thing() if NOT DEFINED arg_WORKING_DIRECTORY, # else calls do_the_thing(WORKING_DIRECTORY "${arg_WORKING_DIRECTORY}") do_the_thing(${working_directory})
В противном случае, если аргумент содержит все escape-последовательности, которые не
\\
являются ,\"
или\$
этот аргумент должен быть кавычек.- Например,
"foo\nbar"
необходимо процитировать.
- Например,
В противном случае, если аргумент содержит
\
аргумент , a"
или a$
, этот аргумент должен быть скоблен.Пример:
set(x [[foo\bar]]) set(y [=[foo([[bar\baz]])]=])
В противном случае, если аргумент содержит символы, которые не являются буквенно-цифровыми или
_
, этот аргумент должен быть кавычек.В противном случае аргумент должен быть неквалирован.
Исключение: аргументы
if()
типа<variable|string>
всегда должны быть кавычки:Оба аргумента для операторов сравнения —
EQUAL
,STREQUAL
,VERSION_LESS
и т. д.Первый аргумент и
MATCHES
IN_LIST
Пример:
if("${FOO}" STREQUAL "BAR") # ... if("${BAZ}" EQUAL "0") # ... if("FOO" IN_LIST list_variable) # ... if("${bar}" MATCHES [[a[bcd]+\.[bcd]+]]) # ...
Для отдельных выражений и для других типов предикатов, которые не принимают
<variable|string>
, используйте обычные правила.
Нет параметров "указателя" или "вне" (где пользователь передает имя переменной, а не содержимое), за исключением простых вне параметров.
Переменные не считаются пустыми. Если переменная предназначена для локального использования, она должна быть явно инициализирована для пустой
set(foo "")
, если это строковая переменная, иvcpkg_list(SET foo)
если она является переменной списка.set(var)
не следует использовать. Используйтеunset(var)
для отмены настройки переменной,set(var "")
чтобы задать пустую строку иvcpkg_list(SET var)
задать ее пустому списку. Примечание. Пустая строка и пустой список совпадают со значением;это нотация, а не разница в результатеВсе переменные, которые, как ожидается, наследуются от родительской области через границу API (т. е. не локальной функции) должны быть документированы. Все переменные, упомянутые в triplet-файлах , считаются документированы.
Параметры out задаются только в
PARENT_SCOPE
и никогда не считываются. См. также вспомогательный элементz_vcpkg_forward_output_variable()
для пересылки параметров через область функции.CACHE
переменные используются только для глобальных переменных, которые совместно используются внутренне между строго сопряженными функциями и для внутреннего состояния в одной функции, чтобы избежать дедупликации работы. Они должны использоваться очень экономно и должны использоватьZ_VCPKG_
префикс, чтобы избежать столкновения с любыми локальными переменными, которые будут определены любым другим кодом.- Примеры:
vcpkg_cmake_configure
'sZ_VCPKG_CMAKE_GENERATOR
z_vcpkg_get_cmake_vars
'sZ_VCPKG_GET_CMAKE_VARS_FILE
- Примеры:
include()
s разрешено только вports.cmake
илиvcpkg-port-config.cmake
.foreach(RANGE)
Аргументы должны всегда быть естественными числами, и<start>
всегда должно быть меньше или равно<stop>
.Это должно быть проверено примерно следующим образом:
if("${start}" LESS_EQUAL "${end}") foreach(RANGE "${start}" "${end}") ... endforeach() endif()
Все скрипты на основе портов должны использовать
include_guard(GLOBAL)
, чтобы избежать включения нескольких раз.
Необходимые версии CMake
- Все скрипты CMake, за исключением
vcpkg.cmake
, могут предполагать версию CMake, которая присутствует вcmake_minimum_required
ports.cmake
.- Это
cmake_minimum_required
должно быть ударноvcpkgTools.xml
при каждом добавлении новой версии CMake, как и вcmake_minimum_required
всех вспомогательныхCMakeLists.txt
файлах.
- Это
vcpkg.cmake
необходимо предположить, что версия CMake возвращается к версии 3.7.2 в целом- Определенные функции и параметры могут предполагать более высокую версию CMake; Если они делают, обязательно закомментируйте функцию или параметр с требуемой версией CMake.
Изменение существующих функций
- Никогда не удаляйте аргументы в не внутренних функциях; если они больше не должны ничего делать, просто возьмите их как обычные и предупреждают об использовании.
- Никогда не добавляйте новый обязательный аргумент.
Именование переменных
cmake_parse_arguments
: задайте для префикса значение ."arg"
Локальные переменные именуются с именем
snake_case
Имена внутренних глобальных переменных префиксируются с
Z_VCPKG_
префиксом.Имена внешних экспериментальных глобальных переменных префиксируются с
X_VCPKG_
префиксом.Внутренние функции префиксируются с помощью
z_vcpkg_
- Функции, которые являются внутренними для одной функции (т. е. вспомогательных функций), называются
[z_]<func>_<name>
, где<func>
имя функции, которую они являются вспомогательным, и<name>
является тем, что выполняет вспомогательный функции.z_
следует добавить на передний план, если<func>
у него нетz_
вспомогательной функцииz_z_foo_bar
, но не присвойте ей имя.
- Функции, которые являются внутренними для одной функции (т. е. вспомогательных функций), называются
Именуются
VCPKG_
общедоступные глобальные переменные.