Code example#
use std::{borrow::Cow, process::Command};
fn main() {
// Make git hash available via GIT_HASH build-time env var:
output_git_short_hash();
}
fn output_git_short_hash() {
let output = Command::new("git").args(["rev-parse", "HEAD"]).output();
let git_hash = match output {
Ok(o) if o.status.success() => {
let sha = String::from_utf8_lossy(&o.stdout).trim().to_owned();
Cow::from(sha)
},
Ok(o) => {
println!("cargo:warning=Git command failed with status: {}", o.status);
Cow::from("unknown")
},
Err(err) => {
println!("cargo:warning=Failed to execute git command: {}", err);
Cow::from("unknown")
},
};
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
println!("cargo:rerun-if-changed=../.git/HEAD");
println!("cargo:rerun-if-changed=../.git/refs");
println!("cargo:rerun-if-changed=build.rs");
}
Code Explanation#
The purpose of this code is to use the Rust std::process::Command
module to execute a Git command, retrieve the Git hash of the current code repository, and set it as the value of the GIT_HASH environment variable. This code is implemented by creating a build.rs file in the root directory of a Rust project.
Here's how this code works:
- In the build.rs file, a function
output_git_short_hash()
is defined. It uses the Ruststd::process::Command
module to execute a Git command and assigns the result to theoutput
variable. - If the Git command is executed successfully, the function retrieves the Git hash from
output.stdout
and stores it in thegit_hash
variable.
Cow
is a string type in Rust that allows choosing betweenString
and&str
representation of a string at runtime. - If the Git command fails to execute, the function outputs a warning message and sets
git_hash
to "unknown". - Finally, the function sets the GIT_HASH environment variable to the value of
git_hash
and uses thecargo:rerun-if-changed
directive to inform Cargo when to rerun the build script.
In this example, Cargo will rerun the build script when../.git/HEAD
,../.git/refs
, or build.rs files are changed. - In main.rs or other Rust files, you can access the Git hash value by using
std::env::var("GIT_HASH")
.
In summary, this code allows retrieving the Git hash of a Rust project by executing a Git command and setting it as an environment variable, making it accessible to other Rust files.
In the fourth step, the cargo:rerun-if-changed
directive is used to inform Cargo when to rerun the build script.
This directive is a special comment provided by Cargo, the Rust compiler, to control the build and rebuild behavior of a project.
Specifically, the cargo:rerun-if-changed
directive tells Cargo that certain file changes require the project to be rebuilt, allowing Cargo to automatically rerun the build script when those files change. The syntax of the directive is as follows:
cargo:rerun-if-changed=<filename>;
where <filename>
represents the name of the file or directory to monitor, and can be specified using relative or absolute paths.
In this example, the cargo:rerun-if-changed
directive tells Cargo to rerun the build script when:
- The
../.git/HEAD
file changes. - Any file in the
../.git/refs
directory changes. - The
build.rs
file changes. - These file changes typically indicate changes in the Git code repository, requiring the retrieval of the Git hash and recompilation of the project.
Note that the cargo:rerun-if-changed
directive can only be used in the build.rs file and must be placed on a separate line, not mixed with other code. This is because the directive is actually a comment, not Rust code, and cannot be included within functions, structs, or other Rust language constructs.