将 git 提交散列作为字符串包含到 Rust 程序中
Include git commit hash as string into Rust program
我在 git 存储库中托管了一个 Rust 项目,我想让它在某些命令上打印版本。如何将版本包含到程序中?我认为构建脚本可以设置编译项目本身时可以使用的环境变量,但它不起作用:
build.rs:
use std::env;
fn get_git_hash() -> Option<String> {
use std::process::Command;
let branch = Command::new("git")
.arg("rev-parse")
.arg("--abbrev-ref")
.arg("HEAD")
.output();
if let Ok(branch_output) = branch {
let branch_string = String::from_utf8_lossy(&branch_output.stdout);
let commit = Command::new("git")
.arg("rev-parse")
.arg("--verify")
.arg("HEAD")
.output();
if let Ok(commit_output) = commit {
let commit_string = String::from_utf8_lossy(&commit_output.stdout);
return Some(format!("{}, {}",
branch_string.lines().next().unwrap_or(""),
commit_string.lines().next().unwrap_or("")))
} else {
panic!("Can not get git commit: {}", commit_output.unwrap_err());
}
} else {
panic!("Can not get git branch: {}", branch.unwrap_err());
}
None
}
fn main() {
if let Some(git) = get_git_hash() {
env::set_var("GIT_HASH", git);
}
}
src/main.rs:
pub const GIT_HASH: &'static str = env!("GIT_HASH");
fm main() {
println!("Git hash: {}", GIT_HASH);
}
错误信息:
error: environment variable `GIT_HASH` not defined
--> src/main.rs:10:25
|
10 | pub const GIT_HASH: &'static str = env!("GIT_HASH");
|
^^^^^^^^^^^^^^^^
有没有办法在编译时传递这样的数据?如果不使用环境变量,我如何在构建脚本和源代码之间进行通信?我只能考虑将数据写入某个文件,但我认为这对这种情况来说太过分了。
I can only think about writing data to some file, but I think this is overkill for this case.
这很不幸,因为 是 唯一的方法。环境变量无法工作,因为对环境的更改无法 "leak" 进入其他非子进程。
对于更简单的事情,您 可以 指示 Cargo 定义条件编译标志,但这些标志的功能不足以传达字符串 [1]。
code generation section of the Cargo documentation.
中详细介绍了从构建脚本生成代码的详细信息
[1]:我的意思是,除非您想将散列分解为 160 个配置标志,然后在正在编译的源代码中重新组装它们,但这甚至 more 过大了.
已经描述了一个现有的板条箱vergen
that can calculate the git commit in the build script. As ,构建脚本不能在 Rust 1.19 之前修改环境变量,所以 vergen
仍然可以通过将结果写入 OUT_DIR(即 vergen
仍然无法解决 OP 的问题,但应该更容易使用)。
用法:
# Cargo.toml
...
[build-dependencies]
vergen = "0.1"
// build.rs
extern crate vergen;
use vergen::*;
fn main() {
vergen(SHORT_SHA | COMMIT_DATE).unwrap();
}
mod version {
include!(concat!(env!("OUT_DIR"), "/version.rs"));
}
fn main() {
println!("commit: {} {}", version::commit_date(), version::short_sha());
// output something like:
// commit: 2017-05-03 a29c7e5
}
自 Rust 1.19 (cargo 0.20.0) 以来,感谢 https://github.com/rust-lang/cargo/pull/3929,您现在可以为 rustc
和 [=15 定义编译时环境变量 (env!(…)
) =] 来自:
println!("cargo:rustc-env=KEY=value");
所以OP的程序可以写成:
// build.rs
use std::process::Command;
fn main() {
// note: add error checking yourself.
let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}
// main.rs
fn main() {
println!("{}", env!("GIT_HASH"));
// output something like:
// 7480b50f3c75eeed88323ec6a718d7baac76290d
}
请注意,如果您仍想支持 1.18 或更低版本,则仍然无法使用此选项。
呃。 (我不建议在生产或测试中或在 public 代码中甚至在私有代码中这样做,但我的意思是,它有点工作?)
const REF: &str = include_str!("../.git/HEAD");
const REF_MASTER: &str = include_str!("../.git/refs/heads/master");
// (elsewhere)
if REF == "ref: refs/heads/master" { REF_MASTER } else { REF }
(除非你正在做某种代码高尔夫,否则不要使用它。请注意,这是 100% 未经测试的。)
有一种简单的方法可以做到这一点,不需要任何 build.rs 逻辑或自定义 crate。您只需将当前的 git 散列作为环境变量直接传递给构建命令,然后使用 option_env!("PROJECT_VERSION")
在您的程序中读取它,并使用 env!("CARGO_PKG_VERSION")
回退。这些宏在 构建时间 期间读取环境变量。
下面的示例构建了这个最小的 src/main.rs:
fn main() {
let version = option_env!("PROJECT_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
println!("This binary was built from {}", version);
}
当您构建程序并想要准确的 git 哈希时,例如在您的 CI/CD 配置中,您在 cargo 命令前加上 PROJECT_VERSION=$(git rev-parse --short HEAD)
。像 cargo run
这样的(但也适用于 cargo build
和其他人):
% PROJECT_VERSION=$(git rev-parse --short HEAD) cargo run
This binary was built from 6ca63b2
我个人更喜欢 $(git describe)
而不是 $(git rev-parse)
,因为前者更具描述性(现在使用 cargo build
作为示例只是为了变化):
% PROJECT_VERSION=$(git describe) cargo build
% ./target/debug/your-program
This binary was built from v0.3.0-15-g6ca63b2 # or just 'v0.3.0' if current commit is tagged with that
由于您有 CARGO_PKG_VERSION
回退,您的 IDE 仍然可以为您即时构建文件。同样,对于开发,您可以跳过传递 PROJECT_VERSION
。在这种情况下,将使用您 Cargo.toml
中的版本:
% cargo run
This binary was built from 0.3.0
我在 git 存储库中托管了一个 Rust 项目,我想让它在某些命令上打印版本。如何将版本包含到程序中?我认为构建脚本可以设置编译项目本身时可以使用的环境变量,但它不起作用:
build.rs:
use std::env;
fn get_git_hash() -> Option<String> {
use std::process::Command;
let branch = Command::new("git")
.arg("rev-parse")
.arg("--abbrev-ref")
.arg("HEAD")
.output();
if let Ok(branch_output) = branch {
let branch_string = String::from_utf8_lossy(&branch_output.stdout);
let commit = Command::new("git")
.arg("rev-parse")
.arg("--verify")
.arg("HEAD")
.output();
if let Ok(commit_output) = commit {
let commit_string = String::from_utf8_lossy(&commit_output.stdout);
return Some(format!("{}, {}",
branch_string.lines().next().unwrap_or(""),
commit_string.lines().next().unwrap_or("")))
} else {
panic!("Can not get git commit: {}", commit_output.unwrap_err());
}
} else {
panic!("Can not get git branch: {}", branch.unwrap_err());
}
None
}
fn main() {
if let Some(git) = get_git_hash() {
env::set_var("GIT_HASH", git);
}
}
src/main.rs:
pub const GIT_HASH: &'static str = env!("GIT_HASH");
fm main() {
println!("Git hash: {}", GIT_HASH);
}
错误信息:
error: environment variable `GIT_HASH` not defined
--> src/main.rs:10:25
|
10 | pub const GIT_HASH: &'static str = env!("GIT_HASH");
|
^^^^^^^^^^^^^^^^
有没有办法在编译时传递这样的数据?如果不使用环境变量,我如何在构建脚本和源代码之间进行通信?我只能考虑将数据写入某个文件,但我认为这对这种情况来说太过分了。
I can only think about writing data to some file, but I think this is overkill for this case.
这很不幸,因为 是 唯一的方法。环境变量无法工作,因为对环境的更改无法 "leak" 进入其他非子进程。
对于更简单的事情,您 可以 指示 Cargo 定义条件编译标志,但这些标志的功能不足以传达字符串 [1]。
code generation section of the Cargo documentation.
中详细介绍了从构建脚本生成代码的详细信息[1]:我的意思是,除非您想将散列分解为 160 个配置标志,然后在正在编译的源代码中重新组装它们,但这甚至 more 过大了.
已经描述了一个现有的板条箱vergen
that can calculate the git commit in the build script. As vergen
仍然可以通过将结果写入 OUT_DIR(即 vergen
仍然无法解决 OP 的问题,但应该更容易使用)。
用法:
# Cargo.toml
...
[build-dependencies]
vergen = "0.1"
// build.rs
extern crate vergen;
use vergen::*;
fn main() {
vergen(SHORT_SHA | COMMIT_DATE).unwrap();
}
mod version {
include!(concat!(env!("OUT_DIR"), "/version.rs"));
}
fn main() {
println!("commit: {} {}", version::commit_date(), version::short_sha());
// output something like:
// commit: 2017-05-03 a29c7e5
}
自 Rust 1.19 (cargo 0.20.0) 以来,感谢 https://github.com/rust-lang/cargo/pull/3929,您现在可以为 rustc
和 [=15 定义编译时环境变量 (env!(…)
) =] 来自:
println!("cargo:rustc-env=KEY=value");
所以OP的程序可以写成:
// build.rs
use std::process::Command;
fn main() {
// note: add error checking yourself.
let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
}
// main.rs
fn main() {
println!("{}", env!("GIT_HASH"));
// output something like:
// 7480b50f3c75eeed88323ec6a718d7baac76290d
}
请注意,如果您仍想支持 1.18 或更低版本,则仍然无法使用此选项。
呃。 (我不建议在生产或测试中或在 public 代码中甚至在私有代码中这样做,但我的意思是,它有点工作?)
const REF: &str = include_str!("../.git/HEAD");
const REF_MASTER: &str = include_str!("../.git/refs/heads/master");
// (elsewhere)
if REF == "ref: refs/heads/master" { REF_MASTER } else { REF }
(除非你正在做某种代码高尔夫,否则不要使用它。请注意,这是 100% 未经测试的。)
有一种简单的方法可以做到这一点,不需要任何 build.rs 逻辑或自定义 crate。您只需将当前的 git 散列作为环境变量直接传递给构建命令,然后使用 option_env!("PROJECT_VERSION")
在您的程序中读取它,并使用 env!("CARGO_PKG_VERSION")
回退。这些宏在 构建时间 期间读取环境变量。
下面的示例构建了这个最小的 src/main.rs:
fn main() {
let version = option_env!("PROJECT_VERSION").unwrap_or(env!("CARGO_PKG_VERSION"));
println!("This binary was built from {}", version);
}
当您构建程序并想要准确的 git 哈希时,例如在您的 CI/CD 配置中,您在 cargo 命令前加上 PROJECT_VERSION=$(git rev-parse --short HEAD)
。像 cargo run
这样的(但也适用于 cargo build
和其他人):
% PROJECT_VERSION=$(git rev-parse --short HEAD) cargo run
This binary was built from 6ca63b2
我个人更喜欢 $(git describe)
而不是 $(git rev-parse)
,因为前者更具描述性(现在使用 cargo build
作为示例只是为了变化):
% PROJECT_VERSION=$(git describe) cargo build
% ./target/debug/your-program
This binary was built from v0.3.0-15-g6ca63b2 # or just 'v0.3.0' if current commit is tagged with that
由于您有 CARGO_PKG_VERSION
回退,您的 IDE 仍然可以为您即时构建文件。同样,对于开发,您可以跳过传递 PROJECT_VERSION
。在这种情况下,将使用您 Cargo.toml
中的版本:
% cargo run
This binary was built from 0.3.0