Spec-Zone.ru › CMake 3.21

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).

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

Поскольку свойство целевого объекта CXX_EXTENSIONS по умолчанию ON, CMake по умолчанию использует расширенные варианты диалектов языка, такие как -std=gnu++11 вместо -std=c++11. Это свойство целевого объекта можно установить в значение OFF для использования нерасширенной версии диалекта. Обратите внимание, что поскольку большинство компиляторов по умолчанию включают расширения, это может привести к появлению ошибок в пользовательском коде или заголовках сторонних библиотек.

Дополнительные функции компиляции

Функции компиляции могут быть предпочтительными, если они доступны, без создания жесткого требования. Это можно сделать, не указывая функции с 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

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

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 целевой объект как обычно и использует соответствующий include-каталог.

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.21/manual/cmake-compile-features.7.html

Spec-Zone.ru

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