cargo icon indicating copy to clipboard operation
cargo copied to clipboard

docs about cargo-provided environment variables could be clearer that they're compile-time only

Open davepacheco opened this issue 5 years ago • 6 comments

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 run and cargo test as 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.

davepacheco avatar Aug 06 '20 19:08 davepacheco

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")

ehuss avatar Aug 06 '20 20:08 ehuss

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

davepacheco avatar Aug 06 '20 21:08 davepacheco

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?

ehuss avatar Aug 06 '20 21:08 ehuss

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?)

davepacheco avatar Aug 06 '20 21:08 davepacheco

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.

davepacheco avatar Aug 06 '20 22:08 davepacheco

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

yds12 avatar Dec 20 '23 11:12 yds12