Cargo 高级特性 #

概述 #

除了基本的项目管理和依赖管理功能外,Cargo 还提供了许多高级特性,用于定制构建流程、条件编译和跨平台开发。本节将深入介绍这些高级功能。

构建脚本 #

什么是构建脚本? #

构建脚本(build script)是在编译项目之前运行的 Rust 程序,用于:

  • 生成代码
  • 编译本地库
  • 设置环境变量
  • 检测系统配置

创建构建脚本 #

在项目根目录创建 build.rs 文件:

rust
// build.rs
fn main() {
    // 构建脚本代码
    println!("cargo:rerun-if-changed=build.rs");
    
    // 设置环境变量
    println!("cargo:rustc-env=MY_VAR=value");
    
    // 添加编译器标志
    println!("cargo:rustc-link-lib=static=mylib");
}

构建脚本输出 #

构建脚本通过 println! 输出指令:

rust
fn main() {
    // 重新运行条件
    println!("cargo:rerun-if-changed=src/template.txt");
    println!("cargo:rerun-if-changed=build.rs");
    
    // 设置环境变量
    println!("cargo:rustc-env=VERSION=1.0.0");
    println!("cargo:rustc-env=BUILD_TIME={}", chrono::Local::now());
    
    // 添加库搜索路径
    println!("cargo:rustc-link-search=native=/path/to/lib");
    
    // 链接库
    println!("cargo:rustc-link-lib=static=mylib");
    println!("cargo:rustc-link-lib=dylib=mylib");
    
    // 编译器标志
    println!("cargo:rustc-flags=-L /path/to/lib");
    
    // 警告
    println!("cargo:warning=This is a warning");
}

构建脚本依赖 #

toml
# Cargo.toml
[build-dependencies]
cc = "1.0"
bindgen = "0.69"
rust
// build.rs
use cc::Build;

fn main() {
    // 编译 C 代码
    Build::new()
        .file("src/native.c")
        .compile("native");
    
    println!("cargo:rerun-if-changed=src/native.c");
}

代码生成 #

rust
// build.rs
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("generated.rs");
    let mut f = File::create(&dest_path).unwrap();
    
    f.write_all(b"
        pub fn generated_function() -> &'static str {
            \"Generated code\"
        }
    ").unwrap();
    
    println!("cargo:rerun-if-changed=build.rs");
}
rust
// src/main.rs
include!(concat!(env!("OUT_DIR"), "/generated.rs"));

fn main() {
    println!("{}", generated_function());
}

构建脚本环境变量 #

变量 描述
OUT_DIR 输出目录
TARGET 目标三元组
HOST 主机三元组
NUM_JOBS 并行任务数
OPT_LEVEL 优化级别
DEBUG 是否调试构建
PROFILE 构建配置名
CARGO_MANIFEST_DIR 项目根目录
CARGO_PKG_VERSION 包版本
CARGO_PKG_NAME 包名

特性标志 #

定义特性 #

toml
[features]
default = ["std"]
std = []
alloc = []
serde = ["dep:serde"]
json = ["serde", "dep:serde_json"]
full = ["std", "serde", "json"]

使用特性 #

rust
// 条件编译
#[cfg(feature = "std")]
pub fn std_function() {
    // 需要 std 特性
}

#[cfg(feature = "serde")]
pub fn with_serde() {
    // 需要 serde 特性
}

#[cfg(all(feature = "std", feature = "serde"))]
pub fn std_with_serde() {
    // 同时需要两个特性
}

#[cfg(not(feature = "std"))]
pub fn no_std_function() {
    // 不需要 std 特性
}

可选依赖 #

toml
[dependencies]
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
tokio = { version = "1.0", optional = true }

[features]
default = []
serde-support = ["dep:serde"]
json = ["serde-support", "dep:serde_json"]
async = ["dep:tokio"]

依赖特性 #

toml
[features]
# 启用依赖的特性
full-tokio = ["tokio/full"]
derive = ["serde/derive"]

特性组合 #

toml
[features]
default = ["std"]
std = []
async = ["tokio/rt", "tokio/net"]
json = ["serde", "serde_json"]
full = ["std", "async", "json"]

条件编译 #

rust
// 基本条件
#[cfg(feature = "feature1")]
fn function1() {}

// 组合条件
#[cfg(all(feature = "feature1", feature = "feature2"))]
fn function_both() {}

#[cfg(any(feature = "feature1", feature = "feature2"))]
fn function_either() {}

#[cfg(not(feature = "feature1"))]
fn function_not() {}

// 平台条件
#[cfg(target_os = "linux")]
fn linux_only() {}

#[cfg(target_os = "windows")]
fn windows_only() {}

#[cfg(target_os = "macos")]
fn macos_only() {}

// 架构条件
#[cfg(target_arch = "x86_64")]
fn x86_64_only() {}

#[cfg(target_arch = "aarch64")]
fn aarch64_only() {}

// 组合平台条件
#[cfg(all(unix, not(target_os = "macos")))]
fn unix_not_macos() {}

cfg_attr #

rust
// 条件属性
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct MyStruct {
    pub field: i32,
}

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

条件编译 #

目标条件 #

rust
// 操作系统
#[cfg(target_os = "linux")]
#[cfg(target_os = "windows")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "android")]
#[cfg(target_os = "ios")]

// 架构
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
#[cfg(target_arch = "arm")]
#[cfg(target_arch = "aarch64")]

// 指针宽度
#[cfg(target_pointer_width = "32")]
#[cfg(target_pointer_width = "64")]

// 字节序
#[cfg(target_endian = "little")]
#[cfg(target_endian = "big")]

// 家族
#[cfg(unix)]
#[cfg(windows)]
#[cfg(target_family = "unix")]
#[cfg(target_family = "windows")]

特性条件 #

rust
#[cfg(feature = "my_feature")]
#[cfg(not(feature = "my_feature"))]
#[cfg(all(feature = "a", feature = "b"))]
#[cfg(any(feature = "a", feature = "b"))]

调试条件 #

rust
#[cfg(debug_assertions)]
fn debug_only() {}

#[cfg(not(debug_assertions))]
fn release_only() {}

自定义条件 #

toml
# .cargo/config.toml
[build]
rustflags = ["--cfg", "my_custom_condition"]
rust
#[cfg(my_custom_condition)]
fn custom() {}

跨平台编译 #

添加目标 #

bash
# 添加编译目标
rustup target add x86_64-pc-windows-gnu
rustup target add aarch64-unknown-linux-gnu
rustup target add wasm32-unknown-unknown

编译命令 #

bash
# 编译到特定目标
cargo build --target x86_64-pc-windows-gnu
cargo build --target aarch64-unknown-linux-gnu
cargo build --target wasm32-unknown-unknown

平台特定依赖 #

toml
[target.'cfg(windows)'.dependencies]
winapi = "0.3"

[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.x86_64-pc-windows-gnu.dependencies]
winapi = "0.3"

[target.aarch64-unknown-linux-gnu.dependencies]
openssl = "0.10"

平台特定代码 #

rust
#[cfg(target_os = "linux")]
mod platform {
    pub fn init() {
        // Linux 初始化
    }
}

#[cfg(target_os = "windows")]
mod platform {
    pub fn init() {
        // Windows 初始化
    }
}

#[cfg(target_os = "macos")]
mod platform {
    pub fn init() {
        // macOS 初始化
    }
}

pub use platform::init;

自定义构建配置 #

配置文件 #

toml
# .cargo/config.toml

[build]
jobs = 4
target-dir = "target"
rustflags = ["-C", "target-cpu=native"]

[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=lld"]

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"

[env]
RUST_LOG = "debug"
MY_VAR = "value"

[alias]
b = "build"
c = "check"
r = "run"
t = "test"
br = "build --release"

环境变量 #

bash
# 编译器标志
RUSTFLAGS="-C target-cpu=native" cargo build

# 目标目录
CARGO_TARGET_DIR=/tmp/target cargo build

# 离线模式
CARGO_NET_OFFLINE=true cargo build

# 增量编译
CARGO_INCREMENTAL=1 cargo build

链接配置 #

链接本地库 #

rust
// build.rs
fn main() {
    // 添加搜索路径
    println!("cargo:rustc-link-search=native=/usr/local/lib");
    
    // 链接静态库
    println!("cargo:rustc-link-lib=static=mylib");
    
    // 链接动态库
    println!("cargo:rustc-link-lib=dylib=mylib");
    
    // 链接框架(macOS)
    println!("cargo:rustc-link-lib=framework=CoreFoundation");
}

链接系统库 #

rust
// build.rs
fn main() {
    // pkg-config
    let library = pkg_config::find_library("openssl").unwrap();
    
    for path in library.link_paths {
        println!("cargo:rustc-link-search=native={}", path.display());
    }
    
    for lib in library.libs {
        println!("cargo:rustc-link-lib={}", lib);
    }
}

编译优化 #

Profile 配置 #

toml
[profile.dev]
opt-level = 0
debug = true
split-debuginfo = "packed"
debug-assertions = true
overflow-checks = true
lto = false
panic = "unwind"
incremental = true
codegen-units = 256

[profile.release]
opt-level = 3
debug = false
split-debuginfo = "..."
debug-assertions = false
overflow-checks = false
lto = false
panic = "unwind"
incremental = false
codegen-units = 16
strip = false

[profile.release-with-debug]
inherits = "release"
debug = true

[profile.release-lto]
inherits = "release"
lto = true
codegen-units = 1

LTO 配置 #

toml
[profile.release]
lto = false      # 禁用
lto = true       # 完全 LTO
lto = "thin"     # Thin LTO(更快)
lto = "fat"      # 完全 LTO

优化大小 #

toml
[profile.release]
opt-level = "s"  # 优化大小
opt-level = "z"  # 更小的大小
strip = true     # 移除符号
lto = true       # 链接时优化
codegen-units = 1  # 单个代码生成单元

常见用例 #

生成版本信息 #

rust
// build.rs
fn main() {
    let version = env::var("CARGO_PKG_VERSION").unwrap();
    let git_hash = get_git_hash();
    
    println!("cargo:rustc-env=VERSION={}", version);
    println!("cargo:rustc-env=GIT_HASH={}", git_hash);
    println!("cargo:rerun-if-changed=build.rs");
}

fn get_git_hash() -> String {
    use std::process::Command;
    let output = Command::new("git")
        .args(["rev-parse", "--short", "HEAD"])
        .output()
        .unwrap();
    String::from_utf8_lossy(&output.stdout).trim().to_string()
}
rust
// src/main.rs
fn main() {
    println!("Version: {}", env!("VERSION"));
    println!("Git Hash: {}", env!("GIT_HASH"));
}

编译 C 代码 #

rust
// build.rs
use cc::Build;

fn main() {
    Build::new()
        .file("src/native.c")
        .include("src/include")
        .flag("-O2")
        .compile("native");
    
    println!("cargo:rerun-if-changed=src/native.c");
    println!("cargo:rerun-if-changed=src/include/native.h");
}

生成绑定 #

rust
// build.rs
use bindgen::Builder;

fn main() {
    let bindings = Builder::default()
        .header("src/wrapper.h")
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");
    
    let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
    
    println!("cargo:rerun-if-changed=src/wrapper.h");
}

下一步 #

掌握高级特性后,继续学习 最佳实践 了解 Cargo 使用的最佳实践!

最后更新:2026-03-28