ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Rerun 构建工具链 re_build_tools 指南:在 build.rs 中注入 Git 与编译时构建信息

Rerun 构建工具链 re_build_tools 指南:在 build.rs 中注入 Git 与编译时构建信息 Rerun 构建工具链 re_build_tools 指南在 build.rs 中注入 Git 与编译时构建信息【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun导读re_build_tools是 Rerun 多模态机器人数据可视化平台rerun中专门用于build.rs构建脚本的工具库它的职责是在编译阶段采集 Git 提交哈希、分支名、构建时间、Rust/LLVM 版本与 Feature 列表等信息并通过 Cargo 环境变量注入到二进制中供re_build_infocrate 在编译期读取。本文将基于 crates/build/re_build_tools/README.md 及其源码完整讲解其环境变量协议、环境感知策略、Git 信息采集、内容哈希与增量重编译机制读完你可以在自己的 Rust 项目中复刻这套可复现、可追溯、不引发多余重编译的构建信息方案。一、它解决什么问题构建信息的可追溯性当你运行rerun --version、查看 Viewer 的 About 菜单或收集遥测分析数据时程序需要知道自己是从哪个提交、哪个分支、哪个时间点、用哪个工具链构建出来的。re_build_tools正是为此而生它是一个要在build.rs文件中使用的库用于构建re_build_info中定义的构建信息通过设置环境变量来实现crates/build/re_build_tools/README.md。它的整体工作方式是一条闭合链路build.rs ──调用── re_build_tools::export_build_info_vars_for_crate(xxx) │ ├─ 采集 Git 哈希 / 分支 / 构建时间 / 工具链版本 / Features ├─ 输出 cargo:rustc-envRE_BUILD_* ... ▼ re_build_info::build_info!() 宏在编译期 读取 RE_BUILD_* 环境变量生成 BuildInfo 结构其中 re_build_info 中的build_info!宏通过env!在编译期强制读取这些变量git_hash: env!(RE_BUILD_GIT_HASH).into(), git_branch: env!(RE_BUILD_GIT_BRANCH).into(), features: env!(RE_BUILD_FEATURES).into(), rustc_version: env!(RE_BUILD_RUSTC_VERSION).into(), llvm_version: env!(RE_BUILD_LLVM_VERSION).into(), datetime: env!(RE_BUILD_DATETIME).into(),这意味着任何直接依赖re_系列 crate 的二进制只要调用了export_build_info_vars_for_crate都会在编译期获得一份完整的构建档案。二、环境变量协议三个输入变量文档明确指出re_build_info中的部分信息可以通过环境变量由外部提供crates/build/re_build_tools/README.md环境变量含义示例值GIT_HASH完整的 Git 提交哈希full shae264b9decab9257ae79100a006bb69c0d289e20cGIT_BRANCH当前分支名symbolic-ref --short的结果asdf/my-branchDATETIMEISO8601 格式的构建时间2025-12-10T15:49:52.089915278Z优先级规则如果这三个变量中某个必需但未提供则由工具库自动采集GIT_HASH执行git rev-parse HEADGIT_BRANCH执行git symbolic-ref --short HEADDATETIME在构建过程中读取系统时间如果你出于某种原因想避免这些自动采集行为比如在无 Git 环境的 CI 上构建、或想实现完全可复现构建文档给出的官方建议是在外部显式设置这些变量。三、源码级原理export_build_info_vars_for_crate 的完整流程仓库中实际被各 crate 的build.rs调用的入口是export_build_info_vars_for_crate(crate_name)crates/build/re_build_tools/src/lib.rs。以 crates/top/rerun/build.rs 为例整个build.rs只有一行fn main() { re_build_tools::export_build_info_vars_for_crate(rerun); }同类的调用还出现在 crates/top/re_sdk/build.rs、crates/top/rerun-cli/build.rs、crates/top/rerun_c/build.rs、crates/store/re_server/build.rs、crates/viewer/re_viewer/build.rs 中。1. 先判断构建环境export_build_info_vars_for_crate的第一步是调用Environment::detect()识别当前处于哪一种构建环境crates/build/re_build_tools/src/lib.rs环境枚举值判定依据环境变量典型场景PublishingCrates设置了RERUN_IS_PUBLISHING_CRATES由scripts/ci/crates.py设置cargo publish发布流程RerunCI设置了IS_IN_RERUN_WORKSPACE且设置了CIRerun 工作区在 GitHub Actions 上的 CI 构建CondaBuild设置了CONDA_BUILDconda-forge 的rerun-sdk-feedstock构建源码来自 GitHub 托管 tgz 包Git 环境来自 conda 本身DeveloperInWorkspace设置了IS_IN_RERUN_WORKSPACE由.cargo/config.toml和.vscode/settings.json中的 rust-analyzer 设置开发者在本仓库工作区内本地编译UsedAsDependency以上均不满足最终用户因依赖某个re_crate 而间接编译它或执行cargo install rerun-cli --locked源码注释给出了设计初衷在这些情况下指UsedAsDependency我们应该在build.rs中尽可能少做手脚。2. 按环境决定导出哪些信息export_build_info_vars_for_crate会为不同的环境组合选择不同的导出策略构建时间RE_BUILD_DATETIMEPublishingCrates、RerunCI、CondaBuild三种环境总是导出DeveloperInWorkspace与UsedAsDependency默认不导出只有显式设置RERUN_ADD_BUILD_TIME_TO_BUILD_INFO时才导出——因为除非每次依赖变化就立刻重编译否则时间戳不会准确而我们不想给用户增加这种负担。Git 信息RE_BUILD_GIT_HASH/RE_BUILD_GIT_BRANCHPublishingCrates、RerunCI总是导出DeveloperInWorkspace受常量EXPORT_GIT_FOR_DEVELOPERS控制该常量在源码中默认值为false注释说明精确导出 Git 信息可能导致不必要的重编译只有确实需要时才打开crates/build/re_build_tools/src/lib.rsUsedAsDependency与CondaBuild不导出——我们不应该在用户的 Rerun Viewer 里展示他们的 Git 哈希/分支。3. 外部变量优先内部采集兜底当决定导出后逻辑遵循外部优先if export_git_info is_tracked_env_var_set(GIT_HASH) is_tracked_env_var_set(GIT_BRANCH) { // 外部已设置直接使用 set_env(RE_BUILD_GIT_HASH, std::env::var(GIT_HASH).unwrap_or_default()); set_env(RE_BUILD_GIT_BRANCH, std::env::var(GIT_BRANCH).unwrap_or_default()); } else if export_git_info { // 未设置则现场采集 set_env(RE_BUILD_GIT_HASH, git::git_commit_hash().unwrap_or_default()); set_env(RE_BUILD_GIT_BRANCH, git::git_branch().unwrap_or_default()); // 并注册重编译监听保证信息始终最新 git::rebuild_if_branch_or_commit_changes(); }这就是 README 中如果必需但未提供则由工具库采集这一规则的精确实现。4. 导出的完整变量清单综合源码export_build_info_vars_for_crate最终可能导出一组RE_BUILD_*前缀的cargo:rustc-env变量输出变量内容来源说明RE_BUILD_DATETIME外部DATETIME或jiff::Timestamp::now()ISO8601/RFC3339 格式不可用时为空串RE_BUILD_GIT_HASH外部GIT_HASH或git rev-parse HEAD完整 40 位哈希RE_BUILD_GIT_BRANCH外部GIT_BRANCH或git symbolic-ref --short HEAD分支短名RE_BUILD_TARGET_TRIPLECargo 的TARGET环境变量如x86_64-unknown-linux-gnuRE_BUILD_RUSTC_VERSION解析rustc -vV输出如1.67.0 (fc594f156 2023-01-24)RE_BUILD_LLVM_VERSION解析rustc -vV输出如15.0.6RE_BUILD_IS_IN_RERUN_WORKSPACEIS_IN_RERUN_WORKSPACE或 CI 特殊处理值为yes/noRE_BUILD_FEATUREScargo metadataCARGO_FEATURE_*空格分隔的已启用 Feature 列表发布时写unknown源码注释强调这些不会变化的内容不需要触发重编译因此被放在一个独立代码块中一次性导出crates/build/re_build_tools/src/lib.rs。5. 工具链版本的解析方式rust_llvm_versions()通过运行rustc -vVRUSTC环境变量可覆盖默认的rustc命令并逐行解析rustc 1.67.0 (...)与LLVM version: 15.0.6两行来获取版本。源码特别做了容错如果输出格式变化或解析失败返回unknown而不是让构建失败——因为要区分rustc 调用失败和输出格式变了两种情况。Feature 列表的采集则依赖cargo_metadata以--frozen与no_deps运行保证 docs.rs 这类离线环境也能工作再对照CARGO_FEATURE_FEATURE形式的环境变量逐一判断哪些 Feature 被启用。值得注意的是当以依赖身份被用户构建时如果 Feature 采集失败例如 Bazel、Buck 等没有cargo的构建系统代码不会让整个构建失败而是写入error占位符继续编译。四、Git 信息采集三种场景的处理策略git.rs 的文档注释列出了三种 Git 使用场景及对应策略使用已发布的 cratecrate 自带版本号版本号反过来对应 Git tag提交哈希变得无关紧要但仍需计算某个值才能编译最终用户构建时该值会被忽略。直接在工作区内开发直接调用git命令即可。使用未发布的 crate如path …、git …或[patch.crates-io]可能拿得到也可能拿不到工作区策略是试一下看看能拿到什么——能算到提交哈希就用算不到还有 crate 版本兜底。具体实现上git_commit_hash()执行git rev-parse HEAD并拒绝空结果git_commit_short_hash()取完整哈希的前 7 个字符git_branch()优先解析 GitHub Actions 的GITHUB_REF环境变量格式为refs/heads/branch_namepull request 为refs/pull/pr_number/mergetag 为refs/tags/tag_name解析失败再回退到git symbolic-ref --short HEAD——这是对 README 中 symbolic-ref --short 描述的完整补充rebuild_if_branch_or_commit_changes()通过git rev-parse --git-path HEAD定位.git/HEAD及实际引用文件并对它们注册cargo:rerun-if-changed监听。若引用文件不存在比如某些 checkout 形态宁可错过哈希变化也不监听不存在的文件——否则会导致每次构建都全量重编crates/build/re_build_tools/src/git.rs。五、内容哈希工具为构建脚本做增量缓存hashing.rs 提供了一套基于 SHA-256 的内容哈希工具用于让昂贵的构建脚本只在源码变化时重跑compute_file_hash(path)计算单个文件的 SHA-256自动为该文件发出rerun-if-changed指令文件不存在会 panic。compute_dir_hash(path, extensions)按文件名排序递归计算目录下所有文件可限定扩展名如只统计rs而不带点的累计哈希同样自动发出监听指令。compute_dir_filtered_hash(path, filter)带自定义过滤器的目录哈希版本。compute_crate_hash(pkg_name)借助cargo metadata递归收集该 crate 及其全部直接/间接依赖的源文件含Cargo.toml与*.wgsl排序后逐文件哈希再对哈希列表做最终聚合哈希。compute_strings_hash(strs)按传入顺序对一组字符串做 SHA-256 聚合。write_versioning_hash/read_versioning_hash把哈希写入版本文件写入前用unindent清理缩进文件头带注释说明可以随时删除该文件以强制重跑构建脚本读取时注册rerun-if-changed-or-doesnt-exist——因为用户手动删除版本文件本身就意味着想强制重编译。这套机制让build.rs可以算出依赖内容的哈希、写进版本文件、下次构建先比对从而在不牺牲正确性的前提下大幅减少重复计算。六、智能重编译检测rerun-if-changed 的封装rebuild_detector.rs 把 Cargo 的cargo:rerun-if-changed指令封装成一组易用 APIrerun_if_changed(path)要求文件存在否则assert!失败源码注释解释文件不存在会导致每次构建都重编。rerun_if_changed_or_doesnt_exist(path)用于文件可能出现也可能消失的场景如版本哈希文件。rerun_if_changed_glob(path, files)按 glob 匹配一组文件加入监听集合内部对 Windows verbatim 路径做了\\?\前缀裁剪以绕过 glob 库的已知问题。get_and_track_env_var(name)/is_tracked_env_var_set(name)读取环境变量并同时注册cargo:rerun-if-env-changed布尔值解析支持1/yes/true与0/no/false遇到无法识别的值会 panic。rebuild_if_crate_changed(pkg_name)递归跟踪某个包及其所有直接/间接依赖的源文件即使依赖来自path …指向的工作区外路径也能覆盖并批量发出监听指令。这是让build.rs在依赖一变化就重跑的核心函数但源码注释也坦诚这是个复杂的怪兽可能有 bug甚至可能引发多余重编crates/build/re_build_tools/src/rebuild_detector.rs。write_file_if_necessary(path, content)仅在内容与磁盘现状不同时才写入。它用于打破build.rs生成源文件 → 触发 Cargo 隐式的rerun-if-changedsrc/**→ 再次重编的递归反馈环。这些 API 的启用与否同样受should_run()控制发布与 conda 环境不运行会生成不必要的Cargo.lockCI 与开发者环境运行作为依赖被用户构建时坚决不运行。七、附带工具rustfmt 格式化字符串rustfmt.rs 提供了一个小工具rustfmt_str(source)把一段 Rust 源码字符串通过管道送入rustfmt可用RUSTFMT环境变量指定可执行文件默认rustfmt固定--edition2024并返回格式化结果。它连续运行两次因为rustfmt不是幂等的源码注释引用了 rust-lang/rustfmt#5824 这个已知问题。典型的用途是在build.rs中生成 Rust 代码后立即格式化保证落盘产物风格统一。八、在 Rerun 工作区中的实际落地re_build_tools在 Rerun 仓库中的依赖情况Cargo.toml运行时依赖anyhow错误处理、cargo_metadata读取 Cargo 元数据、globglob 匹配、jiffISO8601 时间戳、sha2SHA-256、unindent缩进清理、walkdir目录遍历开发依赖regex-lite用于时间戳格式的单测断言。库内自带一个单元测试test_date_time_formatcrates/build/re_build_tools/src/lib.rs用正则^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d)?Z$校验date_time()输出符合 ISO8601 / RFC3339 格式——这直接印证了 README 中DATETIME示例值2025-12-10T15:49:52.089915278Z的格式约定。最终消费端在 crates/utils/re_build_info/src/lib.rsbuild_info!()宏把RE_BUILD_*系列变量组装成BuildInfo其中的crate_name、version直接取自CARGO_PKG_NAME、CARGO_PKG_VERSIONis_debug_build取自cfg!(debug_assertions)is_in_rerun_workspace则把RE_BUILD_IS_IN_RERUN_WORKSPACE yes转为布尔值。这些信息最终流向rerun --version输出、Viewer 的 About 菜单与遥测数据。九、使用建议与注意事项结合 README 与源码可以提炼出几条工程实践建议外部变量优先在 CI 等受控环境中优先通过GIT_HASH、GIT_BRANCH、DATETIME显式注入既避免在构建时调用git子进程也让构建产物可复现。按环境收敛开销把导出构建时间/Git 信息的行为与环境绑定避免给下游用户引入每次依赖变化都重编的负担普通用户编译时应当拿到空串或占位值而不是被强制采集。善用哈希缓存对昂贵的build.rs计算使用compute_crate_hashwrite_versioning_hash/read_versioning_hash组合并通过write_file_if_necessary防止生成文件触发无限重编。监听粒度要克制rerun_if_changed要求文件必须存在glob 监听会自动展开rebuild_if_crate_changed功能强大但源码自述可能引发多余重编使用时需权衡。这套环境感知 外部注入优先 Git/工具链采集 哈希缓存 rerun-if-changed 封装的构建信息方案不依赖运行时文件读取全部在编译期完成兼顾了信息完整性与增量构建效率是 Rust 大型工作区中构建信息治理的一个完整参考实现。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表