bigywater.tech
Rust · 156

Cargo Build Script

前一篇讲了 build.rs 的基本指令。这一篇看真实世界里 build.rs 最常见的用途:编译并链接 C 代码、在 -sys crate 与下游之间传递元数据、让环境变量变化触发重编、区分构建期与运行期依赖。

43 行
cc 自动加到 build.rs 输出里的 rerun-if-env-changed 行数
DEP_VEC2_INCLUDE
下游 build.rs 读到的上游元数据变量
1 → 2
设置 VEC2_SCALE=10 前后 build.rs 的累计运行次数

用 cc 编译 C 并链接(与 cc 输出的指令)

实测 · 本机执行输出
  vec2_dot = 11
  vec2 compiled by cc crate, scale=1
  build.rs 的输出共 88 行,其中 cc 自动加的 rerun-if-env-changed 有 43 行(CC、CFLAGS、AR 等);其余关键指令:
    cargo:rerun-if-changed=vendor/vec2.c
    cargo:rustc-link-lib=static=vec2
    cargo:rustc-link-search=native=<实验目录>/target/debug/build/vec2-sys-6065868c1f4f8245/out
    cargo:include=<实验目录>/proj/u156/vec2-sys/vendor
    cargo:scale=1
  生成的静态库:[('libvec2.a', 3032)]

build.rs 的基础指令见Build Script build.rs;手工链接 C 库见FFI 调用 C 函数。cc 1.x 从 crates.io 下载。

links 与 DEP_ 变量

实测 · 本机执行输出
  下游 app 的 build.rs 打印(DEP_VEC2_*):
    warning: app@0.1.0: app 的 build.rs 收到 DEP_VEC2_INCLUDE=<实验目录>/proj/u156/vec2-sys/vendor  DEP_VEC2_SCALE=1

环境变量触发重编

实测 · 本机执行输出
  build.rs 累计运行次数:起始 1;没改动再 build 1;设置无关变量 UNRELATED 1;VEC2_SCALE=10 后 2;再次相同环境 2
  VEC2_SCALE=10 时的程序输出: vec2_dot = 110 | vec2 compiled by cc crate, scale=10

构建期依赖

实测 · 本机执行输出
  cargo tree -e normal(运行时依赖): ['app v0.1.0 (<实验目录>/proj/u156/app)', '└── vec2-sys v0.1.0 (<实验目录>/proj/u156/vec2-sys)']
  cargo tree -e normal,build(运行时 + 构建期依赖): ['app v0.1.0 (<实验目录>/proj/u156/app)', '└── vec2-sys v0.1.0 (<实验目录>/proj/u156/vec2-sys)', '    [build-dependencies]', '    └── cc v1.5.1', '        ├── find-msvc-tools v0.1.14', '        └── shlex v2.0.1']

feature 与依赖图见Feature Flag 条件编译。

分步演示

Cargo Build Script
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。cc 1.x
    • 没有验证:交叉编译时 cc 选择的编译器与 TARGET_CC 变量、pkg-config 与 vcpkg 探测系统库、bindgen 生成声明、links 键导致的「同一个原生库只能被一个 crate 链接」的冲突、动态库的 rpath、build.rs 并行执行的顺序
    京ICP备2026067502号-1京公网安备11010502063487号