Поделиться через


Руководство по стилю 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's find_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и т. д.

      • Первый аргумент и MATCHESIN_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's Z_VCPKG_CMAKE_GENERATOR
      • z_vcpkg_get_cmake_vars's Z_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_requiredports.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_общедоступные глобальные переменные.