Spec-Zone.ru › CMake 3.22

cmake-compile-features(7)

  • Введение
  • Требования к функциям компиляции

    • Требование к стандартам языка
    • Доступность расширений компилятора
  • Необязательные функции компиляции
  • Условные параметры компиляции
  • Поддерживаемые компиляторы

Введение

Исходный код проекта может зависеть от или быть условным в зависимости от наличия определенных функций компилятора. Возникают три случая использования: Требования к функциям компиляции, Необязательные функции компиляции и Условные параметры компиляции.

Хотя функции обычно указываются в стандартах языков программирования, CMake предоставляет основной пользовательский интерфейс на основе поштучного управления функциями, а не стандартом языка, который ввёл эту функцию.

Глобальные свойства CMAKE_C_KNOWN_FEATURES, CMAKE_CUDA_KNOWN_FEATURES и CMAKE_CXX_KNOWN_FEATURES содержат все известные CMake функции, независимо от поддержки компилятором данной функции. Переменные CMAKE_C_COMPILE_FEATURES, CMAKE_CUDA_COMPILE_FEATURES и CMAKE_CXX_COMPILE_FEATURES содержат все функции, которые CMake знает, что поддерживает компилятор, независимо от языка или флагов компиляции, необходимых для их использования.

Функции, известные CMake, в основном следуют той же конвенции именования, что и макросы тестирования функций Clang. Есть некоторые исключения, например, CMake использует cxx_final и cxx_override вместо единственного cxx_override_control используемого Clang.

Обратите внимание, что нет отдельных свойств или переменных компиляции для языков OBJC или OBJCXX. Они основаны на C или C++ соответственно, поэтому следует использовать свойства и переменные для соответствующего базового языка.

Требования к функциям компиляции

Требования к функциям компиляции могут быть заданы с помощью команды target_compile_features(). Например, если для компиляции целевого объекта требуется поддержка компилятора для функции cxx_constexpr:

add_library(mylib requires_constexpr.cpp)
target_compile_features(mylib PRIVATE cxx_constexpr)

При обработке требования к функции cxx_constexpr, cmake(1) убедится, что используемый компилятор C++ поддерживает эту функцию, и добавит необходимые флаги, такие как -std=gnu++11, к строкам компиляции файлов C++ в целевом объекте mylib. Если компилятор не поддерживает функцию, выдается FATAL_ERROR.

Точные флаги компиляции и стандарт языка преднамеренно не являются частью пользовательского интерфейса для этого случая использования. CMake вычислит соответствующие флаги компиляции, учитывая указанные для каждого целевого объекта функции.

Такие флаги компиляции добавляются даже если компилятор поддерживает конкретную функцию без флага. Например, GNU компилятор поддерживает вариадические шаблоны (с предупреждением), даже если используется -std=gnu++98. CMake добавляет флаг -std=gnu++11, если cxx_variadic_templates указан как требование.

В приведенном выше примере mylib требует cxx_constexpr при собственном построении, но потребители mylib не обязаны использовать компилятор, поддерживающий cxx_constexpr. Если интерфейс mylib требует функции cxx_constexpr (или любой другой известной функции), это можно указать с помощью подписей PUBLIC или INTERFACE команды target_compile_features():

add_library(mylib requires_constexpr.cpp)
# cxx_constexpr is a usage-requirement
target_compile_features(mylib PUBLIC cxx_constexpr)

# main.cpp will be compiled with -std=gnu++11 on GNU for cxx_constexpr.
add_executable(myexe main.cpp)
target_link_libraries(myexe mylib)

Требования к функциям оцениваются транзитивно, используя реализацию ссылки. См. cmake-buildsystem(7) для получения дополнительной информации о транзитивном поведении свойств сборки и требованиях к использованию.

Требование к стандартам языка

В проектах, которые используют большое количество широко доступных функций из определённого стандарта языка (например, C++ 11), можно указать мета-функцию (например, cxx_std_11), которая требует использования режима компилятора, по крайней мере, знакомого с этим стандартом, но может быть более новым. Это проще, чем указывать все функции по отдельности, но не гарантирует существования какой-либо конкретной функции. Диагностика использования неподдерживаемых функций будет отложена до времени компиляции.

Например, если функции C++ 11 широко используются в заголовочных файлах проекта, клиенты должны использовать режим компилятора не ниже C++ 11. Это можно запросить следующим кодом:

target_compile_features(mylib PUBLIC cxx_std_11)

В этом примере CMake обеспечит вызов компилятора в режиме не ниже C++ 11 (или C++ 14, C++ 17, ...), добавив необходимые флаги, такие как -std=gnu++11. Это относится к исходным файлам в mylib, а также к любым зависимым файлам (которые могут включать заголовки из mylib).

Доступность расширений компилятора

Свойство целевого объекта <LANG>_EXTENSIONS по умолчанию использует значения по умолчанию компилятора (см. CMAKE_<LANG>_EXTENSIONS_DEFAULT). Обратите внимание, что поскольку большинство компиляторов по умолчанию включают расширения, это может привести к проблемам портативности в пользовательском коде или в заголовках зависимых сторонних библиотек.

Свойство <LANG>_EXTENSIONS по умолчанию установлено в ON. См. CMP0128.

Необязательные функции компиляции

Функции компиляции могут быть предпочтительными, если они доступны, без создания жёстких требований. Этого можно достичь, не указывая функции с помощью target_compile_features() и вместо этого проверки возможностей компилятора с помощью условных выражений препроцессора в коде проекта.

В этом случае проект может захотеть установить определённый стандарт языка, если он доступен от компилятора, и использовать условия препроцессора для обнаружения фактически доступных функций. Стандарт языка может быть установлен с помощью Требования к стандартам языка с использованием target_compile_features() с мета-функциями, такими как cxx_std_11, или путём установки свойства целевого объекта CXX_STANDARD или переменной CMAKE_CXX_STANDARD.

См. также политику CMP0120 и устаревшую документацию по Примеры использования устаревшего модуля WriteCompilerDetectionHeader.

Условные параметры компиляции

Библиотеки могут предоставлять совершенно разные заголовочные файлы в зависимости от запрошенных функций компилятора.

Например, заголовок в with_variadics/interface.h может содержать:

template<int I, int... Is>
struct Interface;

template<int I>
struct Interface<I>
{
  static int accumulate()
  {
    return I;
  }
};

template<int I, int... Is>
struct Interface
{
  static int accumulate()
  {
    return I + Interface<Is...>::accumulate();
  }
};

в то время как заголовок в no_variadics/interface.h может содержать:

template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
struct Interface
{
  static int accumulate() { return I1 + I2 + I3 + I4; }
};

Возможно, можно написать абстрактный заголовок interface.h, содержащий что-то вроде:

#ifdef HAVE_CXX_VARIADIC_TEMPLATES
#include "with_variadics/interface.h"
#else
#include "no_variadics/interface.h"
#endif

Однако это может быть не поддерживаемым, если есть много файлов для абстрагирования. Необходимо использовать альтернативные каталоги включения в зависимости от возможностей компилятора.

END_OF_DOCUMENT_MARKER

CMake предоставляет COMPILE_FEATURES generator expression для реализации таких условий. Это можно использовать с командами свойств сборки, такими как target_include_directories() и target_link_libraries(), для установки соответствующих свойств buildsystem:

add_library(foo INTERFACE)
set(with_variadics ${CMAKE_CURRENT_SOURCE_DIR}/with_variadics)
set(no_variadics ${CMAKE_CURRENT_SOURCE_DIR}/no_variadics)
target_include_directories(foo
  INTERFACE
    "$<$<COMPILE_FEATURES:cxx_variadic_templates>:${with_variadics}>"
    "$<$<NOT:$<COMPILE_FEATURES:cxx_variadic_templates>>:${no_variadics}>"
  )

Код, потребляющий данные, затем просто подключается к целевому объекту foo как обычно и использует каталог включения, соответствующий функции.

add_executable(consumer_with consumer_with.cpp)
target_link_libraries(consumer_with foo)
set_property(TARGET consumer_with CXX_STANDARD 11)

add_executable(consumer_no consumer_no.cpp)
target_link_libraries(consumer_no foo)

Поддерживаемые компиляторы

В настоящее время CMake поддерживает C++ standards и compile features, доступные от следующих compiler ids по состоянию на указанные версии:

  • AppleClang: Apple Clang для Xcode версий 4.4+.
  • Clang: Компилятор Clang версии 2.9+.
  • GNU: Компилятор GNU версии 4.4+.
  • MSVC: Microsoft Visual Studio версии 2010+.
  • SunPro: Oracle SolarisStudio версии 12.4+.
  • Intel: Intel компилятор версии 12.1+.

В настоящее время CMake поддерживает C standards и compile features, доступные от следующих compiler ids по состоянию на указанные версии:

  • все компиляторы и версии, перечисленные выше для C++.
  • GNU: Компилятор GNU версии 3.4+

CMake в настоящее время поддерживает C++ standards и их связанные мета-функции (например, cxx_std_11) доступные от следующих compiler ids по состоянию на указанные версии:

  • Cray: Cray Compiler Environment версии 8.1+.
  • Fujitsu: Fujitsu HPC компилятор 4.0+.
  • PGI: PGI версии 12.10+.
  • NVHPC: NVIDIA HPC компиляторы версии 11.0+.
  • TI: Компилятор Texas Instruments.
  • XL: IBM XL версии 10.1+.

CMake в настоящее время поддерживает C standards и их связанные мета-функции (например, c_std_99) доступные от следующих compiler ids по состоянию на указанные версии:

  • все компиляторы и версии, перечисленные выше, только с мета-функциями для C++.

CMake в настоящее время поддерживает CUDA standards и их связанные мета-функции (например, cuda_std_11) доступные от следующих compiler ids по состоянию на указанные версии:

  • Clang: Компилятор Clang 5.0+.
  • NVIDIA: Компилятор NVIDIA nvcc 7.5+.

© 2000–2021 Kitware, Inc. and Contributors
Licensed under the BSD 3-clause License.
https://cmake.org/cmake/help/v3.22/manual/cmake-compile-features.7.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API