Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Условная компиляция

Условно компилируемый исходный код — это исходный код, который компилируется только при определённых условиях.

Исходный код может быть сделан условно компилируемым с помощью атрибутов cfg и cfg_attr, а также встроенного макроса cfg.

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

Каждая форма условной компиляции принимает предикат конфигурации, который вычисляется в true или false. Предикат может быть одним из следующих:

  • Опция конфигурации. Предикат истинен, если опция установлена, и ложен, если она не установлена.
  • all() со списком предикатов конфигурации, разделённых запятыми. Истинен, если все заданные предикаты истинны, или если список пуст.
  • any() со списком предикатов конфигурации, разделённых запятыми. Истинен, если хотя бы один из заданных предикатов истинен. Если предикатов нет, он ложен.
  • not() с предикатом конфигурации. Истинен, если его предикат ложен, и ложен, если его предикат истинен.
  • Литералы true или false, которые всегда истинны или ложны соответственно.

Опции конфигурации — это либо имена, либо пары “ключ-значение”, и они либо установлены, либо не установлены.

Имена записываются как одиночный идентификатор, например, unix.

Пары “ключ-значение” записываются как идентификатор, =, а затем строка, например, target_arch = "x86_64".

Note

Пробелы вокруг = игнорируются, поэтому foo="bar" и foo = "bar" эквивалентны.

Ключи не должны быть уникальными. Например, feature = "std" и feature = "serde" могут быть установлены одновременно.

Установленные опции конфигурации

Какие опции конфигурации установлены, определяется статически во время компиляции крейта.

Некоторые опции устанавливаются компилятором на основе данных о компиляции.

Другие опции устанавливаются произвольно на основе входных данных, переданных компилятору вне кода.

Невозможно установить опцию конфигурации из исходного кода компилируемого крейта.

Note

Для rustc произвольно устанавливаемые опции конфигурации задаются с помощью флага --cfg. Значения конфигурации для указанной цели можно просмотреть с помощью rustc --print cfg --target $TARGET.

Note

Опции конфигурации с ключом feature — это соглашение, используемое Cargo cargo_feature для указания опций времени компиляции и опциональных зависимостей.

target_arch

Опция “ключ-значение”, устанавливаемая один раз с указанием архитектуры ЦП цели. Значение похоже на первый элемент целевого тройника (target triple) платформы, но не идентично ему.

Примеры значений:

  • "x86"
  • "x86_64"
  • "mips"
  • "powerpc"
  • "powerpc64"
  • "arm"
  • "aarch64"

target_feature

Опция “ключ-значение”, устанавливаемая для каждой доступной особенности платформы для текущей цели компиляции.

Примеры значений:

  • "avx"
  • "avx2"
  • "crt-static"
  • "rdrand"
  • "sse"
  • "sse2"
  • "sse4.1"

Смотрите атрибут target_feature для получения более подробной информации о доступных особенностях.

Дополнительная особенность crt-static доступна для опции target_feature, чтобы указать, что доступна статическая C-среда выполнения.

target_os

Опция “ключ-значение”, устанавливаемая один раз с указанием операционной системы цели. Это значение похоже на второй и третий элемент целевого тройника платформы.

Примеры значений:

  • "windows"
  • "macos"
  • "ios"
  • "linux"
  • "android"
  • "freebsd"
  • "dragonfly"
  • "openbsd"
  • "netbsd"
  • "none" (типично для встраиваемых (embedded) целей)

target_family

Опция “ключ-значение”, предоставляющая более общее описание цели, такое как семейство операционных систем или архитектур, к которым цель обычно относится. Любое количество пар “ключ-значение” target_family может быть установлено.

Примеры значений:

  • "unix"
  • "windows"
  • "wasm"
  • Одновременно "unix" и "wasm"

unix и windows

unix устанавливается, если установлено target_family = "unix".

windows устанавливается, если установлено target_family = "windows".

target_env

Опция “ключ-значение”, устанавливаемая с дополнительной уточняющей информацией о целевой платформе, касающейся используемого ABI или libc. По историческим причинам, это значение определено только как не пустая строка, когда это действительно необходимо для различения. Таким образом, например, на многих платформах GNU это значение будет пустым. Это значение похоже на четвёртый элемент целевого тройника платформы. Одно различие заключается в том, что встраиваемые ABI, такие как gnueabihf, просто определяют target_env как "gnu".

Примеры значений:

  • ""
  • "gnu"
  • "msvc"
  • "musl"
  • "sgx"
  • "sim"
  • "macabi"

target_abi

Опция “ключ-значение”, устанавливаемая для дальнейшего различения цели с информацией о целевом ABI.

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

Примеры значений:

  • ""
  • "llvm"
  • "eabihf"
  • "abi64"

target_endian

Опция “ключ-значение”, устанавливаемая один раз со значением “little” или “big” в зависимости от порядка байт (endianness) ЦП цели.

target_pointer_width

Опция “ключ-значение”, устанавливаемая один раз с указанием разрядности указателя цели в битах.

Примеры значений:

  • "16"
  • "32"
  • "64"

target_vendor

Опция “ключ-значение”, устанавливаемая один раз с указанием производителя цели.

Примеры значений:

  • "apple"
  • "fortanix"
  • "pc"
  • "unknown"

target_has_atomic

Опция “ключ-значение”, устанавливаемая для каждой разрядности (в битах), которую цель поддерживает для атомарных загрузок, сохранений и операций compare-and-swap.

Когда этот cfg присутствует, все стабильные API core::sync::atomic доступны для соответствующей атомарной разрядности.

Возможные значения:

  • "8"
  • "16"
  • "32"
  • "64"
  • "128"
  • "ptr"

test

Включается при компиляции тестовой обёртки (harness). Выполняется в rustc с помощью флага --test. Смотрите Тестирование для получения дополнительной информации о поддержке тестирования.

debug_assertions

Включено по умолчанию при компиляции без оптимизаций. Это может быть использовано для включения дополнительного отладочного кода в разработке, но не в продакшене. Например, это управляет поведением макроса debug_assert! в стандартной библиотеке.

proc_macro

Устанавливается, когда компилируемый крейт компилируется с типом крейта proc_macro.

panic

Опция “ключ-значение”, устанавливаемая в зависимости от стратегии паники. Обратите внимание, что в будущем могут быть добавлены другие значения.

Примеры значений:

  • "abort"
  • "unwind"

Формы условной компиляции

Атрибут cfg

Атрибут cfg условно включает форму, к которой он прикреплён, на основе предиката конфигурации.

Example

#![allow(unused)]
fn main() {
// Функция включается в сборку только при компиляции для macOS
#[cfg(target_os = "macos")]
fn macos_only() {
  // ...
}

// Эта функция включается только когда определён foo или bar
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// Эта функция включается только при компиляции для UNIX-подобной ОС с 32-битной
// архитектурой
#[cfg(all(unix, target_pointer_width = "32"))]
fn on_32bit_unix() {
  // ...
}

// Эта функция включается только когда foo не определён
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}

// Эта функция включается только когда стратегия паники установлена в unwind
#[cfg(panic = "unwind")]
fn when_unwinding() {
  // ...
}
}

Синтаксис атрибута cfg:

Syntax
CfgAttributecfg ( ConfigurationPredicate )

Атрибут cfg может использоваться везде, где разрешены атрибуты.

Атрибут cfg может использоваться любое количество раз для одной формы. Форма, к которой прикреплены атрибуты, не будет включена, если любой из предикатов cfg ложен, за исключением случая, описанного в cfg.attr.crate-level-attrs.

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

Когда крейт-уровневый cfg имеет ложный предикат, сам крейт всё равно существует. Любые атрибуты уровня крейта, предшествующие cfg, сохраняются, а любые атрибуты уровня крейта, следующие за cfg, удаляются, так же как и всё последующее содержимое крейта.

Example

Поведение, при котором предшествующие атрибуты не удаляются, позволяет делать такие вещи, как включать #![no_std], чтобы избежать линковки std, даже если #![cfg(...)] в противном случае удалило содержимое крейта. Например:

// Этот атрибут `no_std` сохраняется, даже хотя крейт-уровневый атрибут `cfg`
// ложен.
#![no_std]
#![cfg(false)]

// Эта функция не включается.
pub fn example() {}

Атрибут cfg_attr

Атрибут cfg_attr условно включает атрибуты на основе предиката конфигурации.

Example

Следующий модуль будет найден либо в linux.rs, либо в windows.rs в зависимости от цели.

#[cfg_attr(target_os = "linux", path = "linux.rs")]
#[cfg_attr(windows, path = "windows.rs")]
mod os;

Синтаксис атрибута cfg_attr:

Syntax
CfgAttrAttributecfg_attr ( ConfigurationPredicate , CfgAttrs? )

CfgAttrsAttr ( , Attr )* ,?

Атрибут cfg_attr может использоваться везде, где разрешены атрибуты.

Атрибут cfg_attr может использоваться любое количество раз на одной форме.

Атрибуты crate_type и crate_name нельзя использовать с cfg_attr.

Когда предикат конфигурации истинен, cfg_attr раскрывается в атрибуты, перечисленные после предиката.

Может быть перечислено ноль, один или более атрибутов. Несколько атрибутов будут раскрыты в отдельные атрибуты.

Example

#[cfg_attr(feature = "magic", sparkles, crackles)]
fn bewitched() {}

// Когда флаг функциональности `magic` включен, вышеуказанное раскроется в:
#[sparkles]
#[crackles]
fn bewitched() {}

Note

cfg_attr может раскрываться в другой cfg_attr. Например, #[cfg_attr(target_os = "linux", cfg_attr(feature = "multithreaded", some_other_attribute))] является допустимым. Этот пример был бы эквивалентен #[cfg_attr(all(target_os = "linux", feature ="multithreaded"), some_other_attribute)].

Макрос cfg

Встроенный макрос cfg принимает единственный предикат конфигурации и вычисляется в литерал true, когда предикат истинен, и в литерал false, когда он ложен.

Например:

#![allow(unused)]
fn main() {
let machine_kind = if cfg!(unix) {
  "unix"
} else if cfg!(windows) {
  "windows"
} else {
  "unknown"
};

println!("Я работаю на машине типа {}!", machine_kind);
}