Best way to implement `--version` option?

What is the best way to gather contents for a --version string command line option in a Rust app that:

  • Always updates whenever anything needs rebuilding
  • Includes build timestamp
  • Includes some kind of version information, such as git commit hash, Cargo version string, etc.
  • Does not require any runtime dependencies (does not add to runtime footprint).

I have found various crates that might help with this, such as build_details, compile_time, shadow_rs, and even compile_time_run. But I don't know how to determine how often these run and what their runtime dependencies are.

The general approach is to use a build script (build.rs) that determines the timestamp, Git info, etc. and provides that information to your actual binary crate by either (a) emitting cargo::rustc-env instructions to set environment variables when the crate is compiled, at which point the envvars can be accessed with env!() or (b) writing Rust code or other structured data to a file in OUT_DIR, which can then be incorporated into the crate with include!() or similar. By default, build.rs is rerun if any files in your package changed, but this can be modified.

This is the approach taken by two of the packages you mentioned — build_details and shadow_rs — and so "how often these run" becomes just "how often is build.rs (re)run." As for runtime dependencies, you need to see whether each package's documentation tells you to add anything to [dependencies] (not to be confused with [build-dependencies], which is only for build.rs dependencies). build_details' README states that it requires a runtime dependency on phf, and shadow-rs requires both a runtime and build-time dependency on shadow-rs.

The compile_time and compile_time_run packages, in contrast, use proc macros that run arbitrary Rust code when the invoking code is compiled. I don't feel qualified to answer your questions when it comes to this approach, though the use of proc macros for this strikes me as a bit of an anti-pattern.

Use vergen. It's designed to collect and update build-time information.

Most importantly it's a de-facto standard, so for example when package maintainers need to make builds reproducible, they only need to configure vergen, and not patch crates individually.

vergen_gitcl looks like exactly what I want in terms of output and lack of runtime footprint! Thanks for pointing it out!

I added CARGO_PKG_VERSION to the option_env!'s, which Cargo sets itself.

And I have build.rs emit cargo::rerun-if-changed=src to get it to update on every build.