Spec-Zone.ru › CMake 3.9

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–6.2.
  • Clang: Компилятор Clang версий 2.9–3.4.
  • GNU: GNU компилятор версий 4.4–5.0.
  • MSVC: Microsoft Visual Studio версий 2010–2017.
  • SunPro: Oracle SolarisStudio версий 12.4–12.5.
  • Intel: Intel компилятор версий 12.1–17.0.

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

  • все компиляторы и версии, перечисленные выше, для C++.
  • GNU: GNU компилятор версий 3.4–5.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++.

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

  • NVIDIA: Компилятор NVIDIA nvcc 7.5–8.0.

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

Spec-Zone.ru

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