读完这篇,你应该能:
- 知道 什么叫 cfg,它和 feature 有何区别;
- 会用 rustc --print cfg 找到自己目标平台的 "开关";
- 大概记住 什么时候 才需要写 #[cfg(...)]------其余时候就让编译器自动干活。
cfg 是什么?为什么要管它?
cfg = configuration,
Rust 的 条件编译 机制。
编译期根据真假裁剪代码 / 依赖,而 不会 增加运行时代码路径。
语法入口:
- #[cfg(name)] / #[cfg(name = "value")]
- cfg!(name)(编译时求值,返回 bool)
- Cargo 专用:[target.'cfg(...)'.dependencies]
怎么查看自己有哪些内置 cfg?
bash
rustc --print cfg # 当前主机
rustc --print cfg --target x86_64-unknown-linux-musl # 指定目标
全部内置 cfg------按"你可能关心的顺序"分 6 类
类别 | 代表 cfg | 说明 / 典型用途 |
---|---|---|
A. 构建模式 & panic | debug_assertions test panic="unwind" / "abort" | 开 debug 断言?写单元测试?想把 panic 改为 crash? |
B. 平台家族 | unix windows target_family="unix" | 一行判断 "有没有 fork()" 或 "路径分隔符是 \ 还是 /" |
C. 具体 OS / 发行商 / 环境 | target_os="linux" target_vendor="apple" | 区分 Linux-glibc / Linux-musl / macOS / Android... |
D. CPU 架构 & 数据布局 | target_arch="x86_64" target_pointer_width="64" target_endian="little" | 写裸机 / FFI / 内存映射时决定字节序、指针大小 |
E. CPU 指令特性 | target_feature="sse2" target_feature="neon" ... | 写 SIMD、加速 AES/SHA、Run-time feature detection |
F. 原子指令支持 | target_has_atomic="64" "128" "ptr" | 在 no-std/嵌入式里判断能否安全使用 AtomicU64/128 |
想看自己电脑的真实列表?直接跑 rustc --print cfg,结果大概就和你贴的一样。
A. 构建模式 & panic
cfg | 何时为真 | 用来干啥 |
---|---|---|
debug_assertions | cargo build(debug profile | 保留开销较大的检测:debug_assert!() / 额外日志 |
test | cargo test 时 | 在测试代码里启用内部 helper |
panic="unwind" vs "abort" | 由 panic = "..." (Cargo.toml [profile]) 决定 | 依赖栈展开的接口(catch_unwind、C++ FFI) |
B. 平台家族 (最粗粒度)
cfg | 平台 | 常见 if 分支 |
---|---|---|
unix / target_family="unix" | Linux, macOS, *BSD, Android, iOS... | 使用 libc、std::os::unix::fs::PermissionsExt |
windows / target_family="windows" | Windows | 路径分隔 \、WinAPI FFI |
wasm / target_family="wasm"(夜版) | WebAssembly | no-std + wasm-bindgen |
C. OS / vendor / env / abi
cfg | 例子 | 什么时候才需要 |
---|---|---|
target_os | "linux"、"macos"、"android"... | 系统调用号、socket 特性、文件权限 |
target_vendor | "apple" "pc" "unknown" | 很少单独用;偶尔区分 Apple vs. PC BSD |
target_env | "gnu" "musl" "msvc" | 选 glibc / musl / MSVC CRT,或链接方式不同 |
target_abi | "eabi" "gnueabihf" | 裸机 ARM,决定调用约定 & 浮点规则 |
rust
#[cfg(all(target_os = "linux", target_env = "musl"))]
static LIBC_PATH: &str = "/lib/ld-musl-x86_64.so.1";
D. CPU 架构 & 数据布局
cfg | 例子 | 何用 |
---|---|---|
target_arch | "x86_64" "aarch64" "riscv64" | 包含对应 core::arch::* 模块 |
target_pointer_width | "32" "64" | 数据结构 on-disk 格式是否需要固定 64-bit |
target_endian | "little" "big" | 网络协议、读写 mmap 文件 |
target_cpu(nightly) | native / znver4 | 生成汇编时推断微架构 |
E. CPU 指令特性 (target_feature)
这些是 "默认就启用" 的特性;若想手动开关,可用 RUSTFLAGS='-C target-feature=+aes,+neon' cargo build
常见 ARM (aarch64):
-
neon -- SIMD 基础
-
aes / sha2 / sha3 -- 专用加密指令
-
lse -- 更强的原子读改写
-
fp16 -- 半精度浮点
-
rdm -- carry-less multiply 常见 x86_64:
-
sse2, avx, avx2, aes, pclmulqdq, sha, bmi2... 示例
rust
#[cfg(target_feature = "neon")]
pub fn mul_matrix_neon(a: &[f32], b: &[f32]) { ... }
#[cfg(not(target_feature = "neon"))]
pub fn mul_matrix_scalar(a: &[f32], b: &[f32]) { ... }
F. 原子指令宽度
cfg 值 | 意义 |
---|---|
target_has_atomic="8" / "16" / "32" / "64" / "128" | CPU 原生支持该位宽的 Atomic* |
target_has_atomic="ptr" | 保障 AtomicUsize 可用 |
嵌入式裸机经常碰到 没有 64-bit 原子 的情况:
rust
#[cfg(target_has_atomic = "64")]
static CNT: AtomicU64 = AtomicU64::new(0);
#[cfg(not(target_has_atomic = "64"))]
static CNT: core::cell::Cell<u64> = Cell::new(0); // 退化实现
写法小抄
3.1 代码里裁剪
rust
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[cfg(windows)]
use std::os::windows::fs::MetadataExt;
3.2 Cargo 里裁剪依赖
toml
[target.'cfg(target_os = "linux")'.dependencies]
nix = "0.27"
[target.'cfg(target_arch = "aarch64")'.dependencies]
faster-aarch64 = "2"
3.3 批量宏(自定义)
rust
macro_rules! cfg_unix {
($($item:item)*) => {
$(
#[cfg(unix)]
$item
)*
}
}
cfg_unix! {
pub fn only_unix() { /* ... */ }
}
我到底什么时候才需要手写 cfg?
- 跨平台库:同一份源码想在 Windows、Linux、WASM 都编过。
- 性能极限:在支持 AVX2 的机器上走 SIMD,不支持就退纯标量。
- no-std / bare-metal:32-bit MCU 没有 64-bit 原子,必须降级实现。
- 区分 debug / release:调试版打开额外检查。
- 挑 libc:Docker alpine (musl) 静态链接 vs. 普通 glibc。
- 如果你的项目只在 单一 平台运行(比如 WebAssembly + wasm-bindgen),理论上可以一行 cfg 都不写------Rust 会按默认三元组把代码全部编进来。
参考命令 & 资料
bash
rustc --print cfg # 当前 cfg 列表
rustc --print target-spec-json --target ... # 夜ly可用,查看详细 target
RUSTFLAGS='-C target-feature=?' rustc - # 查看可选特性
Rust Reference -- Conditional Compilation
Cargo Book -- Target-specific Dependencies
The Rustonomicon -- Unstable Features & target_feature
结语 cfg 像一把"手术刀": 用它,可以把同一套代码精准切割给不同平台;不用时,也不会带来任何运行时成本。 只要记得这 6 大类常用 cfg,遇到跨平台场景再回来查表就足够了。Pomelo_刘金 ,转载请注明出处,感谢! Happy hacking!