Spec-Zone.ru › CMake 3.13

cmake-compile-features(7)

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

Введение

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

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

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

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

Требования к компиляторам

Требования к возможностям компиляции могут быть указаны с помощью команды 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 (или выше), добавляя такие флаги, как -std=gnu++11, если необходимо. Это относится как к исходным файлам внутри mylib, так и к любым зависимостям (которые могут включать заголовки из mylib).

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

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

Необязательные возможности компиляции

Возможности компиляции могут быть предпочтительными, если доступны, без создания жёсткого требования. Например, библиотека может предоставить альтернативные реализации в зависимости от того, доступна ли возможность cxx_variadic_templates.

#if Foo_COMPILER_CXX_VARIADIC_TEMPLATES
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();
  }
};
#else
template<int I1, int I2 = 0, int I3 = 0, int I4 = 0>
struct Interface
{
  static int accumulate() { return I1 + I2 + I3 + I4; }
};
#endif

Такой интерфейс зависит от использования правильных предопределённых макросов препроцессора для возможностей компилятора. CMake может сгенерировать заголовочный файл, содержащий такие определения, используя модуль WriteCompilerDetectionHeader. Модуль содержит функцию write_compiler_detection_header, которая принимает параметры для управления содержимым сгенерированного заголовочного файла:

write_compiler_detection_header(
  FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
  PREFIX Foo
  COMPILERS GNU
  FEATURES
    cxx_variadic_templates
)

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

Для каждой возможности, перечисленной в FEATURES, в заголовочном файле создаётся определение препроцессора, определённое как 1 или 0.

Кроме того, некоторые возможности требуют дополнительных определений, таких как cxx_final и cxx_override возможности. Вместо использования в коде #ifdef, ключевое слово final абстрагируется символом, который определяется как final, эквивалентом компилятора или пустым. Таким образом, код C++ может быть написан для безусловного использования символа, а поддержка компилятора определяет, к чему он развернётся:

struct Interface {
  virtual void Execute() = 0;
};

struct Concrete Foo_FINAL {
  void Execute() Foo_OVERRIDE;
};

В этом случае Foo_FINAL будет расширено до final, если компилятор поддерживает ключевое слово, или до пустого значения в противном случае.

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

write_compiler_detection_header(
  FILE "${CMAKE_CURRENT_BINARY_DIR}/foo_compiler_detection.h"
  PREFIX Foo
  COMPILERS GNU
  FEATURES
    cxx_final cxx_override
)

# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the requested
# CXX_STANDARD.
add_library(foo foo.cpp)
set_property(TARGET foo PROPERTY CXX_STANDARD 11)

# Includes foo_compiler_detection.h and uses the Foo_FINAL symbol
# which will expand to 'final' if the compiler supports the feature,
# even though CXX_STANDARD is not set explicitly.  The requirement of
# cxx_constexpr causes CMake to set CXX_STANDARD internally, which
# affects the compile flags.
add_library(foo_impl foo_impl.cpp)
target_compile_features(foo_impl PRIVATE cxx_constexpr)

Функция write_compiler_detection_header также создаёт совместимый код для других возможностей, которые имеют стандартные эквиваленты. Например, возможность cxx_static_assert эмулируется с помощью шаблона и абстрагируется с помощью функции-макросов <PREFIX>_STATIC_ASSERT и <PREFIX>_STATIC_ASSERT_MSG.

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

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

Например, заголовок по адресу 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, содержащий что-то вроде:

#include "foo_compiler_detection.h"
#if Foo_COMPILER_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 как обычно и использует каталог заголовков, соответствующий возможности.

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 до 9.2.
  • Clang: Компилятор Clang версии 2.9 до 6.0.
  • GNU: Компилятор GNU версии 4.4 до 8.0.
  • MSVC: Microsoft Visual Studio версии 2010 до 2017.
  • SunPro: Oracle SolarisStudio версии 12.4 до 12.6.
  • Intel: Intel компилятор версии 12.1 до 17.0.

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

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

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

  • Cray: Cray Compiler Environment версии 8.1 до 8.5.8.
  • PGI: PGI версии 12.10 до 17.5.
  • XL: IBM XL версии 10.1 до 13.1.5.

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

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

CMake в настоящее время знает о CUDA standards от следующих compiler ids по состоянию на указанные версии:

  • NVIDIA: Компилятор NVIDIA nvcc версии 7.5 до 9.1.

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

Spec-Zone.ru

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