302

How do you access a Cargo package's metadata (e.g. version) from the Rust code in the package? In my case, I am building a command line tool that I'd like to have a standard --version flag, and I'd like the implementation to read the version of the package from Cargo.toml so I don't have to maintain it in two places. I can imagine there are other reasons someone might want to access Cargo metadata from the program as well.

1

4 Answers 4

446

Cargo passes some metadata to the compiler through environment variables, a list of which can be found in the Cargo documentation pages.

The compiler environment is populated by fill_env in Cargo's code. This code has become more complex since earlier versions, and the entire list of variables is no longer obvious from it because it can be dynamic. However, at least the following variables are set there (from the list in the docs):

CARGO_MANIFEST_DIR
CARGO_PKG_AUTHORS
CARGO_PKG_DESCRIPTION
CARGO_PKG_HOMEPAGE
CARGO_PKG_NAME
CARGO_PKG_REPOSITORY
CARGO_PKG_VERSION
CARGO_PKG_VERSION_MAJOR
CARGO_PKG_VERSION_MINOR
CARGO_PKG_VERSION_PATCH
CARGO_PKG_VERSION_PRE

You can access environment variables using the env!() macro. To insert the version number of your program you can do this:

const VERSION: &str = env!("CARGO_PKG_VERSION");

// ...

println!("MyProgram v{}", VERSION);

If you want your program to compile even without Cargo, you can use option_env!():

const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");

// ...

println!("MyProgram v{}", VERSION.unwrap_or("unknown"));
Sign up to request clarification or add additional context in comments.

4 Comments

Is this runtime or compile time?
@debuti compile time, as stated in the documentation
Just to say to searchers, since this is a compile-time solution and uses environment variables, this will not resolve to subcrate's metadata for workspace members.
@debuti for future reference, if you see const then it is compile-time.
35

The built-crate helps with serializing a lot of Cargo's environment without all the boilerplate.

2 Comments

built also adds the git sha-1 (and lots of other useful things)
Note that built performs code generation; this property may not be desired due to the potential for supply chain attacks. Ensure that you pin built to a single version if you're worried about this, or just use the core::env! macro and Cargo's crate env variables for something that's available at the time of const evaluation
10

At build-time (as in build.rs), cargo_metadata may be useful. For example:

let path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let meta = MetadataCommand::new()
    .manifest_path("./Cargo.toml")
    .current_dir(&path)
    .exec()
    .unwrap();

let root = meta.root_package().unwrap();
let option = root.metadata["my"]["option"].as_str().unwrap();
let version = &root.version;
...

Comments

5

Other more recent alternatives:

// ...
let version = env!("CARGO_PKG_VERSION");
let name = env!("CARGO_PKG_NAME");
let author = env!("CARGO_PKG_AUTHORS");

println!("Program Name: {}", name);
println!("Program Version: {}", version);
println!("Program Author: {}", author);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.