Rust 程序如何从其 Cargo 包中访问元数据?

How can a Rust program access metadata from its Cargo package?

如何从包中的 Rust 代码访问 Cargo 包的元数据(例如版本)?就我而言,我正在构建一个命令行工具,我希望它有一个标准的 --version 标志,并且我希望实现从 Cargo.toml 读取包的版本,所以我不不必在两个地方维护它。我可以想象还有其他原因可能有人想从程序中访问 Cargo 元数据。

Cargo 通过环境变量将一些元数据传递给编译器,其中的列表可以在 Cargo documentation pages.

中找到

编译器环境由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

您可以使用 env!() 宏访问环境变量。要插入程序的版本号,您可以这样做:

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

// ...

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

如果你想让你的程序在没有 Cargo 的情况下也能编译,你可以使用 option_env!():

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

// ...

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

built-crate 有助于在没有所有样板的情况下序列化大量 Cargo 环境。

在构建时(如 build.rs),cargo_metadata 可能会有用。例如:

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;
...