cargo
cargo copied to clipboard
docs about cargo-provided environment variables could be clearer that they're compile-time only
This section of the docs: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates (https://github.com/ehuss/cargo/blob/master/src/doc/src/reference/environment-variables.md#environment-variables-cargo-sets-for-crates)
says:
Cargo exposes these environment variables to your crate when it is compiled. Note that this applies for running binaries with
cargo runandcargo testas well.
I think what this means to say is something like: "Cargo exposes these environment variables to your crate when any of its targets is compiled, including when compiling binaries that you might later run with cargo run and cargo test. [These environment variables are not provided at runtime.]"
It's easy to misread what's there as: "Cargo exposes these environment variables to your crate when it is compiled, and when running binaries with cargo run and cargo test as well."
The difference is whether the variables are available at runtime, which as far as I can tell they aren't.
The difference is whether the variables are available at runtime, which as far as I can tell they aren't.
Can you say more about why it does not appear to be set at runtime?
In a project with:
fn main() {
println!("{:?}", std::env::var("CARGO_MANIFEST_DIR"));
}
Then:
> cargo run
Compiling foo v0.1.0 (/Users/eric/Temp/foo)
Finished dev [unoptimized + debuginfo] target(s) in 0.65s
Running `target/debug/foo`
Ok("/Users/eric/Temp/foo")
Interesting. Here's a project I created to test this. It's got an executable and an example:
$ cargo version
cargo 1.45.1 (f242df6ed 2020-07-22)
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/cargo-env`
Hello, world!
$ cargo run --example=example
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/examples/example`
Hello, world! from example
$
It's also got a test that prints CARGO_BIN_EXE_cargo-env at compile-time and prints all environment variables starting with CARGO_ at runtime. Here's what it prints:
$ cargo test -- --nocapture
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running target/debug/deps/cargo_env-85de79b58ac22ba9
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Running target/debug/deps/foo-940845794b78bbcb
running 1 test
compile-time: CARGO_BIN_EXE_cargo-env: /Users/dap/oxide/experiments/cargo-env/target/debug/cargo-env
runtime: CARGO_HOME: /Users/dap/.cargo
runtime: CARGO_MANIFEST_DIR: /Users/dap/oxide/experiments/cargo-env
runtime: CARGO_PKG_AUTHORS: David Pacheco <[email protected]>
runtime: CARGO_PKG_DESCRIPTION:
runtime: CARGO_PKG_HOMEPAGE:
runtime: CARGO_PKG_NAME: cargo-env
runtime: CARGO_PKG_REPOSITORY:
runtime: CARGO_PKG_VERSION: 0.1.0
runtime: CARGO_PKG_VERSION_MAJOR: 0
runtime: CARGO_PKG_VERSION_MINOR: 1
runtime: CARGO_PKG_VERSION_PATCH: 0
runtime: CARGO_PKG_VERSION_PRE:
test the_test ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
$
So indeed: many of these are present at runtime as well, but the CARGO_BIN_EXE one isn't. (I was doing this to determine if there were CARGO_BIN_EXE variables for the examples. I'm not sure if there are or not.)
Ah, I see. CARGO_BIN_EXE is only set at build time. It does say "only set when building", but I imagine that could be made clearer somehow. Maybe that and OUT_DIR could be moved to a subsection of build-time-only env vars?
That makes sense, though you're right -- I see that it says "when building". Relatedly, I wasn't clear on whether CARGO_BIN_EXE variables are set for all binaries in the crate (at once), and whether that includes examples, or if only one is set at any given time for the integration test itself. Do you know? (Or is there some way to iterate the env vars at compile time to explore this?)
I figured out how to enumerate the compile-time environment variables from outside the process to answer my question. It looks like CARGO_BIN_EXE_... is set for the one binary target in the crate (i.e., not the test itself, and not the example).
I used this DTrace script:
dtrace -w -n 'proc:::exec-success/progenyof(96201)/{ trace(pid); stop(); system("ps eww %d; kill -CONT %d", pid, pid); }' -n BEGIN'{ printf("starting"); }'
(where pid 96201 is the shell I ran cargo build --tests from). I also added a second binary target to see what would happen. Here are the CARGO_ env vars that were set when the integration test was built:
CARGO=/Users/dap/.rustup/toolchains/stable-x86_64-apple-darwin/bin/cargo
CARGO_BIN_EXE_cargo-env=/Users/dap/oxide/experiments/cargo-env/target/debug/cargo-env
CARGO_HOME=/Users/dap/.cargo
CARGO_MAKEFLAGS=--jobserver-fds=3,4
CARGO_MANIFEST_DIR=/Users/dap/oxide/experiments/cargo-env
CARGO_PKG_AUTHORS=David
CARGO_PKG_NAME=cargo-env
CARGO_PKG_VERSION=0.1.0
CARGO_PKG_VERSION_MAJOR=0
CARGO_PKG_VERSION_MINOR=1
CARGO_PKG_VERSION_PATCH=0
This makes sense. While I do think it would help to separate the build-time variables as you suggested, I think I was confused by something else, not the text.
I might suggest adding one sentence after:
The absolute path to a binary target's executable. This is only set when building an integration test or benchmark.
to specify more precisely which binaries will have this set:
One
CARGO_BIN_EXE_<name>variable will be set for each binary target in the package.
For context, I got here looking for how to find the path to one of the examples in my package so that I could write an integration test that runs the example program. It seemed like this would work, but I see now that it won't.
I had the same confusion. It seems that if you run with cargo run you will get most of those variables, but not if you run your executable directly. For example, when running the compiled binary directly, this: std::env::var("CARGO_PKG_VERSION") returns Err(VarError::NotPresent).