
cargo build 完全指南Cargo 编译命令的包选择、目标筛选、特性控制与优化实践【免费下载链接】cargoThe Rust package manager项目地址: https://gitcode.com/gh_mirrors/car/cargo导读cargo build是 CargoThe Rust package manager中最核心、最常用的编译命令负责将当前包及其全部依赖编译为可执行文件或库。本文以 Cargo 官方手册的 cargo-build(1) 文档为骨架完整覆盖从包选择-p/--workspace、目标筛选--lib/--bin/--tests、特性开关--features、编译选项--release/--profile/--target到输出控制--target-dir/--message-format的全部命令行参数并结合本仓库的源码实现如 build.rs 与 cargo_compile/mod.rs剖析其底层编译流水线帮助读者掌握可复用的构建脚本与 CI 配置技巧。命令概览与基本原理语法与职责cargo build [_options_]cargo build的职责是编译本地包以及它们的所有依赖。执行该命令时Cargo 会先解析工作区workspace再解析依赖图、下载缺失的依赖包最后生成一棵编译单元Unit图并驱动rustc逐单元编译。从源码看命令入口位于 src/bin/cargo/commands/build.rs它通过subcommand(build)注册命令并依次挂载了包选择参数arg_package_spec、目标筛选参数arg_targets_all、特性参数arg_features、编译参数arg_release、arg_profile、arg_target_triple、输出参数arg_target_dir、arg_artifact_dir等。真正干活的是exec函数build.rs 第 48-69 行它构造CompileOptions后调用ops::compile(ws, compile_opts)?完成编译。底层编译流水线在 src/ops/cargo_compile/mod.rs 的模块级文档中官方明确给出了编译流程的七个阶段解析依赖图ops::resolve下载所需包PackageSet为用户在命令行上请求的目标生成顶层“单元”Unit每个Unit对应一次编译器调用UnitGenerator::generate_root_units从根Unit出发沿着解析器得到的依赖图生成完整的UnitGraph见unit_dependencies构造BuildContext结束编译的“前端”阶段创建BuildRunner协调编译过程准备target目录Layout、创建JobQueue通过指纹fingerprint判断每个Unit是否需要重新编译可跳过未变更的单元、执行队列drain_the_queue依赖图的叶子节点被并行执行直到队列清空——这是 Cargo 中唯一使用多线程的地方编译结果存入Compilation结构体供后续阶段如测试运行使用。理解了这条流水线就能明白为什么cargo build第二次执行会快很多未变化的Unit被指纹机制跳过无需重新调用rustc。包选择Package Selection默认选择规则当不给出任何包选择选项时选中的包取决于所选的 manifest 文件若未指定--manifest-path则依据当前工作目录向上查找。规则如下若 manifest 是某个工作区的根则选择工作区的default members默认成员否则只选择该 manifest 定义的包。工作区的默认成员可以在根 manifest 中用workspace.default-members键显式指定。若未设置虚拟工作区virtual workspace根目录本身不是包将包含所有工作区成员等价于传入--workspace非虚拟工作区根目录本身是一个包只包含根 crate 自身。相关选项选项说明-pspec… /--packagespec…只构建指定的包。SPEC 格式参见 cargo-pkgid(1)。该标志可多次指定并支持常见 Unix glob 模式*、?、[]。为避免 shell 在 Cargo 处理前误展开通配符每个模式必须用单引号或双引号包裹--workspace构建工作区中的所有成员--all--workspace的已废弃别名--excludeSPEC…排除指定的包。必须与--workspace一起使用。可多次指定同样支持 glob 模式也需引号包裹示例# 只构建名为 mylib 的包 cargo build -p mylib # 构建工作区全部成员但排除 test-utils cargo build --workspace --exclude test-utils # 使用 glob 模式注意引号防止 shell 展开 cargo build -p serde-*目标筛选Target Selection默认行为当不给出任何目标筛选选项时cargo build会构建选中包的所有二进制binary和库library目标。带有required-features且其特性未启用的二进制会被跳过。一个值得注意的行为当选中了集成测试或基准测试目标时相关的二进制目标会被自动构建。这样集成测试就可以执行该二进制来检验其行为——此时 Cargo 会为集成测试设置环境变量CARGO_BIN_EXE_name参见环境变量参考测试代码可通过标准库的env!宏或var函数定位可执行文件。// 集成测试中通过 CARGO_BIN_EXE_ 定位被测二进制 let bin_path std::env::var(CARGO_BIN_EXE_myapp).unwrap();相关选项选项说明--lib只构建包的库目标--binname…构建指定的二进制目标可多次指定支持 glob--bins构建全部二进制目标--examplename…构建指定的示例目标可多次指定支持 glob--examples构建全部示例目标--testname…构建指定的集成测试目标可多次指定支持 glob--tests构建所有设置了test true的目标。默认包含以单测形式构建的库与二进制以及集成测试。注意这会连带构建所需依赖因此库目标可能被构建两次一次作为单测一次作为二进制/集成测试的依赖。目标可通过 manifest 中的test标志启用或禁用--benchname…构建指定的基准测试目标可多次指定支持 glob--benches构建所有设置了bench true的目标。默认包含以基准形式构建的库与二进制以及 bench 目标同理库目标可能被构建两次可通过 manifest 的bench标志控制--all-targets构建所有目标等价于同时指定--lib --bins --tests --benches --examples与包选择一样--bin、--example、--test、--bench的 glob 模式也必须在 shell 中加引号避免被提前展开# 构建 lib 和所有二进制 cargo build --lib --bins # 只构建名为 tests/ui 的集成测试glob cargo build --test tests/* # 为发布版基准测试构建全部目标 cargo build --release --all-targets目标路径校验从源码看Cargo 在生成根单元后还会校验每个目标的源文件路径cargo_compile/mod.rs 第 621-640 行若目标路径不存在会报错cant find kind name at path path若路径指向目录而非源文件会提示path path for kind name is a directory, but a source file was expected并智能地建议main.rs或lib.rs作为候选入口点见validate_target_path_as_source_file函数。若解析出的目标路径错误数大于 0构建会以could not compile due to N previous target resolution error(s)中止。特性选择Feature Selection默认行为与三个选项当不给出任何特性选项时每个选中包的default特性都会被激活。详细的特性机制见特性参考文档。选项说明-Ffeatures/--featuresfeatures激活指定特性。可用空格或逗号分隔多个特性若在 shell 中用空格分隔必须加引号如--features foo bar。工作区成员的特性可用package-name/feature-name语法指定。该标志可多次指定最终启用全部被列出的特性--all-features激活所有选中包的全部可用特性--no-default-features不激活选中包的default特性# 启用 foo 和 bar 两个特性 cargo build --features foo bar cargo build -F foo,bar # 为工作区中特定成员启用特性 cargo build --features mylib/extra # 关闭默认特性只启用自定义特性 cargo build --no-default-features --features minimal特性是相加的additive特性参考文档features.md强调特性只对定义它的包生效同名特性不会跨包联动当某个依赖被多个包共同使用时Cargo 会取其被启用特性的并集来构建以保证依赖只被编译一份。这要求特性应当是相加式的——启用某个特性不应关闭其他功能。若确实存在互斥特性建议用compile_error!在编译期报错而不是依赖运行时行为#[cfg(all(feature foo, feature bar))] compile_error!(feature \foo\ and feature \bar\ cannot be enabled at the same time);编译选项Compilation Options--targettuple为指定目标架构构建可多次指定默认为宿主host架构。tuple 的通用格式为archsub-vendor-sys-abi。可选值rustc --print target-list中列出的任意受支持目标字符串host-tuple内部会被替换为宿主目标——这在交叉编译部分 crate、且不想把宿主机器写死为目标时非常有用例如一个可能被多种宿主共同开发的项目中的xtask指向自定义目标规格文件的路径参见自定义目标查找路径说明。该选项也可通过build.target配置值见配置参考指定。注意指定该标志会让 Cargo 进入不同模式——目标产物被放置到单独的目录中详见构建缓存文档。# 为 ARM 架构交叉编译 cargo build --target aarch64-unknown-linux-gnu # 显式指定宿主目标 cargo build --target host-tuple # 使用自定义目标规格 cargo build --target /path/to/my-target.json-r/--release使用releaseprofile 构建优化后的产物。如需按名字选择特定 profile可结合--profile使用。--profilename使用指定的 profile 构建。关于 profile 的完整说明见profiles 参考文档。Cargo 内置了dev、debug、release、test、bench五个标准 profile也允许用户在Cargo.toml中定义自定义 profile如--profilefoo。--timings输出每次编译的耗时信息并随时间跟踪并发情况。构建结束后会在target/cargo-timings目录写入一个cargo-timing.html文件若想回看历史运行还会额外写入一个带时间戳的报告。这些报告仅供人阅读不提供机器可读的计时数据。cargo build --timings # 结束后打开 target/cargo-timings/cargo-timing.html输出选项Output Options--target-dirdirectory所有生成产物与中间文件的存放目录。同样可以通过CARGO_TARGET_DIR环境变量或build.target-dir配置值见配置参考指定。默认为工作区根目录下的target目录。# 把构建产物放到独立目录便于多分支并行缓存 cargo build --target-dir /tmp/my-target # 等价的环境变量方式 CARGO_TARGET_DIR/tmp/my-target cargo build--artifact-dirdirectory将最终产物复制到指定目录。该选项不稳定仅在 nightly 通道可用且需要-Z unstable-options标志启用。在源码中build.rs 第 53-66 行--artifact-dir会优先覆盖构建配置中的artifact-dir值并将compile_opts.build_config.export_dir设置为该目录一旦设置就会通过gctx.cli_unstable().fail_if_stable_opt(--artifact-dir, 6790)检查是否在稳定通道误用。# nightly 通道下将产物集中导出 cargo build -Z unstable-options --artifact-dir ./dist构建缓存目录布局参考构建缓存文档target目录的布局取决于是否使用--target目录说明target/debug/devprofile 的输出target/release/releaseprofile 的输出使用--release时target/foo/名为foo的自定义 profile 的输出使用--profilefoo时target/tuple/debug/交叉编译时的输出如target/thumbv7em-none-eabihf/debug/target/debug/examples/示例目标的输出target/doc/cargo doc生成的 rustdoc 文档出于历史原因dev与testprofile 存放在debug目录release与benchprofile 存放在release目录用户自定义 profile 使用与 profile 同名的目录。此外build-dir/debug/incremental/存放rustc增量编译缓存用于加速后续构建build-dir/debug/build/存放构建脚本build script的结果。值得注意的细节不使用--target时Cargo 会让依赖与构建脚本、过程宏共享编译RUSTFLAGS也会传递给每一次rustc调用而使用--target后构建脚本与过程宏会为宿主架构单独构建且不与目标共享RUSTFLAGS。每个编译产物旁还会生成.d后缀的 dep-info 文件Makefile 语法供外部构建系统判断是否需要重新执行 Cargo默认使用绝对路径可通过build.dep-info-basedir配置改为相对路径。显示选项Display Options选项说明-v/--verbose使用详细输出。指定两次为“非常详细”输出包含依赖警告与构建脚本输出等额外信息。也可用term.verbose配置值指定-q/--quiet不打印 Cargo 日志消息。也可用term.quiet配置值指定--colorwhen控制彩色输出的时机。合法值auto默认自动检测终端是否支持颜色、always总是显示、never从不显示。也可用term.color配置值指定--message-formatfmt诊断消息的输出格式可多次指定值以逗号分隔。合法值见下表--message-format的取值值说明human默认人类可读的文本格式。与short、json互斥short更短的人类可读文本。与human、json互斥json向 stdout 输出 JSON 消息详见外部工具参考。与human、short互斥json-diagnostic-short确保 JSON 消息的rendered字段包含 rustc 的 “short” 渲染。不能与human、short共用json-diagnostic-rendered-ansi确保 JSON 消息的rendered字段包含 ANSI 颜色码以尊重 rustc 默认配色。不能与human、short共用json-render-diagnostics指示 Cargo 不在打印的 JSON 消息中内嵌 rustc 诊断而由 Cargo 自己渲染来自 rustc 的 JSON 诊断。不能与human、short共用# 供 IDE / 工具消费的机器可读输出 cargo build --message-formatjson # 既有 JSON 又强制 ANSI 着色 cargo build --message-formatjson,json-diagnostic-rendered-ansiManifest 选项Manifest Options选项说明--manifest-pathpath指定Cargo.toml文件路径。默认情况下 Cargo 在当前目录或任意父目录中查找Cargo.toml--ignore-rust-version忽略包中的rust-version声明--locked断言使用与现有Cargo.lock生成时完全相同的依赖和版本。当 lock 文件缺失或 Cargo 因依赖解析结果不同而试图修改 lock 文件时Cargo 会报错退出。适合需要确定性构建的环境如 CI 流水线--offline阻止 Cargo 以任何理由访问网络。不带该标志时若 Cargo 需要网络而网络不可用会报错带该标志时 Cargo 会尽量离线继续。注意这可能导致依赖解析结果与在线模式不同——Cargo 会把自己限制在本地已下载的 crate 中即使本地 index 副本显示存在更新版本也不会使用。可先通过 cargo-fetch(1) 预先下载依赖。也可用net.offline配置值指定--frozen等价于同时指定--locked和--offline# CI 中保证可重复构建 cargo build --locked # 完全离线构建需先 cargo fetch cargo fetch cargo build --offline # 最严格模式 cargo build --frozen关于 MSRV 检查源码中cargo_compile/mod.rs 第 642-683 行展示了rust-versionMSRV的检查逻辑当honor_rust_version为真时Cargo 会遍历单元图中所有包将每个包的rust_version与当前rustc版本比对若存在不兼容包会报告rustc X is not supported by the following package(s)并给出cargo update namecurrent-ver --precise compatible-ver的修复建议。--ignore-rust-version正是用来跳过该检查的。通用选项Common Options选项说明toolchain若 Cargo 由 rustup 安装且cargo的第一个参数以开头则会被解释为 rustup 工具链名如stable、nightly--configKEYVALUE或PATH覆盖 Cargo 配置值。参数应为KEYVALUE的 TOML 语法或指向额外配置文件的路径。可多次指定。详见命令行覆盖配置-CPATH在执行任何操作前切换当前工作目录。这会影响 Cargo 默认查找Cargo.toml的位置以及发现.cargo/config.toml时搜索的目录。该选项必须出现在命令名之前如cargo -C path/to/my-project build。仅 nightly 通道可用需-Z unstable-options启用-h/--help打印帮助信息-ZflagCargo 的不稳定仅 nightly标志。运行cargo -Z help查看详情# 使用特定工具链 cargo nightly build # 命令行临时覆盖配置 cargo build --config build.jobs4 # nightly 下指定工作目录 cargo -Z unstable-options -C path/to/project build其他选项Miscellaneous Options-jN/--jobsN并行运行的作业数。也可用build.jobs配置值见配置参考指定默认为逻辑 CPU 数量。规则若为负数则并行作业上限为“逻辑 CPU 数 该值”若为字符串default则恢复默认值不能为 0。# 限制为 4 个并行作业 cargo build -j 4 # 比逻辑 CPU 数少 2 个 cargo build --jobs -2--keep-going尽量多地构建依赖图中可构建的 crate而不是在第一个构建失败的 crate 处中止。文档给出了典型例子若当前包依赖fails和works两个 crate其中fails构建失败cargo build -j1可能构建也可能不构建works取决于 Cargo 先挑选哪个执行而cargo build -j1 --keep-going则保证两个都会尝试构建即使先运行的失败。# 收集尽可能多的错误便于一次性修复 cargo build --keep-going--future-incompat-report显示本次命令执行期间产生的未来不兼容future-incompatible警告报告。详见 cargo-report(1)。Profile 与优化从 debug 到 release理解 profile 才能用好cargo build的编译选项。根据 profiles 参考文档标准 profile 的默认设置如下dev普通开发默认即不带--release时[profile.dev] opt-level 0 debug true split-debuginfo ... # 平台相关 strip none debug-assertions true overflow-checks true lto false panic unwind incremental true codegen-units 256 rpath falserelease--release时使用适合发布与生产[profile.release] opt-level 3 debug false split-debuginfo ... # 平台相关 strip none debug-assertions false overflow-checks false lto false panic unwind incremental false codegen-units 16 rpath false此外debugprofile 继承自dev用于调试器testprofile 继承自devcargo test默认benchprofile 继承自releasecargo bench默认。为了编译速度所有 profile 默认都不优化构建依赖构建脚本、过程宏及其依赖并尽量避免为不作为运行时依赖的构建依赖生成调试信息参见[profile.dev.build-override]等配置。从源码还能看到更深层的优化rebuild_unit_graph_sharedcargo_compile/mod.rs 第 836-872 行会尽力将宿主依赖单元合并共享避免同一依赖在普通/构建/artifact 依赖图中重复编译同时会对构建依赖的调试信息做“弱化”weaken处理以加快构建若错误发生在构建依赖中开启完整调试信息可获得更好的回溯。环境变量、退出码与示例环境变量Cargo 读取的环境变量详见环境变量参考。与cargo build强相关的包括CARGO_TARGET_DIR等价于--target-dirRUSTFLAGS传递给每次rustc调用的标志注意错误的RUST_FLAGS会被 Cargo 忽略并告警源码中 cargo_compile/mod.rs 第 271-294 行 会明确提示“rust flags are passed viaRUSTFLAGS”CARGO_BIN_EXE_name集成测试/基准测试构建时指向对应二进制的路径。退出状态状态含义0Cargo 成功完成101Cargo 未能完成构建失败标准示例构建本地包及其全部依赖cargo build带优化构建cargo build --release构建指定包、指定目标并启用特性综合运用cargo build -p myapp --bin myapp --release --features serde/derive --timingsCI 中确定性构建cargo build --locked --release相关命令cargo(1)Cargo 总入口cargo-rustc(1)向rustc传递额外参数的低层编译命令cargo-check(1)只做类型检查、不生成产物的快速替代cargo-run(1)编译后立即运行cargo-fetch(1)预先下载依赖以支持离线构建。【免费下载链接】cargoThe Rust package manager项目地址: https://gitcode.com/gh_mirrors/car/cargo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考