Skip to content

Commit

Permalink
feat: Add CARGO_RUSTC_CURRENT_DIR
Browse files Browse the repository at this point in the history
This is an alternative to rust-lang#12158's `CARGO_WORKSPACE_DIR` that was
implementing the solution to rust-lang#3946 that previously discussed in the
cargo team meeting.

`CARGO_WORKSPACE_DIR` is a bit awkward to document / describe because
its the effective workspace directory of the thing being built.
If the thing being built doesn't have a workspace, it falls back to
`CARGO_MANIFEST_DIR`.

It would also be hard to take into account what the
`CARGO_WORKSPACE_DIR` would be for path dependencies into foreign
workspaces *and* it wouldn't solve the problem the user is having.

What the user really wants is the CWD of rustc when it is invoked.
This is much simpler to describe and is accurate when using a path
dependency to a foreign package.

Because the CWD is a much simpler mechanism to talk about, I figured we
could diverge from our prior consensus and make it always present,
rather than limiting it to tests.

Remaining work for rust-lang#3946: get this stabilized
  • Loading branch information
yerke authored and epage committed Nov 17, 2023
1 parent 0361ff5 commit fd2ef54
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,16 @@ fn prepare_rustc(cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilde
let tmp = cx.files().layout(unit.kind).prepare_tmp()?;
base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string());
}
if cx.bcx.config.nightly_features_allowed {
// This must come after `build_base_args` (which calls `add_path_args`) so that the `cwd`
// is set correctly.
base.env(
"CARGO_RUSTC_CURRENT_DIR",
base.get_cwd()
.map(|c| c.display().to_string())
.unwrap_or(String::new()),
);
}

Ok(base)
}
Expand Down
1 change: 1 addition & 0 deletions src/doc/src/reference/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ corresponding environment variable is set to the empty string, `""`.
where integration tests or benchmarks are free to put any data needed by
the tests/benches. Cargo initially creates this directory but doesn't
manage its content in any way, this is the responsibility of the test code.
* `CARGO_RUSTC_CURRENT_DIR` --- This is a path that `rustc` is invoked from.

[Cargo target]: cargo-targets.md
[binaries]: cargo-targets.md#binaries
Expand Down
206 changes: 202 additions & 4 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,11 @@ fn crate_env_vars() {
// Verify CARGO_TARGET_TMPDIR isn't set for bins
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
// Verify CARGO_RUSTC_CURRENT_DIR is set for examples
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
)
Expand Down Expand Up @@ -1581,6 +1586,11 @@ fn crate_env_vars() {
// Check that CARGO_TARGET_TMPDIR isn't set for lib code
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
env::var("CARGO_TARGET_TMPDIR").unwrap_err();
// Verify CARGO_RUSTC_CURRENT_DIR is set for examples
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
#[test]
Expand All @@ -1589,6 +1599,13 @@ fn crate_env_vars() {
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
env::var("CARGO_TARGET_TMPDIR").unwrap_err();
}
#[test]
fn unit_env_cargo_rustc_current_dir() {
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
)
.file(
Expand All @@ -1605,6 +1622,11 @@ fn crate_env_vars() {
// Verify CARGO_TARGET_TMPDIR isn't set for examples
assert!(option_env!("CARGO_TARGET_TMPDIR").is_none());
// Verify CARGO_RUSTC_CURRENT_DIR is set for examples
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
)
Expand All @@ -1615,6 +1637,13 @@ fn crate_env_vars() {
fn integration_env_cargo_target_tmpdir() {
foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR"));
}
#[test]
fn integration_env_cargo_rustc_current_dir() {
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
);

Expand All @@ -1630,6 +1659,13 @@ fn crate_env_vars() {
fn bench_env_cargo_target_tmpdir(_: &mut Bencher) {
foo::check_tmpdir(option_env!("CARGO_TARGET_TMPDIR"));
}
#[test]
fn bench_env_cargo_rustc_current_dir() {
let workspace_dir = std::path::Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
)
.build()
Expand All @@ -1638,23 +1674,185 @@ fn crate_env_vars() {
};

println!("build");
p.cargo("build -v").run();
p.cargo("build -v")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.run();

println!("bin");
p.process(&p.bin("foo-bar"))
.with_stdout("0-5-1 @ alpha.1 in [CWD]")
.run();

println!("example");
p.cargo("run --example ex-env-vars -v").run();
p.cargo("run --example ex-env-vars -v")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.run();

println!("test");
p.cargo("test -v").run();
p.cargo("test -v")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.run();

if is_nightly() {
println!("bench");
p.cargo("bench -v").run();
p.cargo("bench -v")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.run();
}
}

#[cargo_test]
fn cargo_rustc_current_dir_foreign_workspace_dep() {
let foo = project()
.file(
"Cargo.toml",
r#"
[workspace]
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
baz.path = "../baz"
baz_member.path = "../baz/baz_member"
"#,
)
.file("src/lib.rs", "")
.build();
let _baz = project()
.at("baz")
.file(
"Cargo.toml",
r#"
[workspace]
members = ["baz_member"]
[package]
name = "baz"
version = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"tests/env.rs",
r#"
use std::path::Path;
#[test]
fn baz_env() {
let workspace_dir = Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let manifest_dir = Path::new(option_env!("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let current_dir = std::env::current_dir().expect("current_dir");
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
let workspace_dir = std::fs::canonicalize(current_dir.join(workspace_dir)).expect("CARGO_RUSTC_CURRENT_DIR");
let manifest_dir = std::fs::canonicalize(current_dir.join(manifest_dir)).expect("CARGO_MANIFEST_DIR");
assert_eq!(workspace_dir, manifest_dir);
}
"#,
)
.file(
"baz_member/Cargo.toml",
r#"
[package]
name = "baz_member"
version = "0.1.0"
authors = []
"#,
)
.file("baz_member/src/lib.rs", "")
.file(
"baz_member/tests/env.rs",
r#"
use std::path::Path;
#[test]
fn baz_member_env() {
let workspace_dir = Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
}
"#,
)
.build();

// Verify it works from a different workspace
foo.cargo("test -p baz")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.with_stdout_contains("running 1 test\ntest baz_env ... ok")
.run();
foo.cargo("test -p baz_member")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.with_stdout_contains("running 1 test\ntest baz_member_env ... ok")
.run();
}

#[cargo_test]
fn cargo_rustc_current_dir_non_local_dep() {
Package::new("bar", "0.1.0")
.file(
"tests/bar_env.rs",
r#"
use std::path::Path;
#[test]
fn bar_env() {
let workspace_dir = Path::new(option_env!("CARGO_RUSTC_CURRENT_DIR").expect("CARGO_RUSTC_CURRENT_DIR"));
let manifest_dir = Path::new(option_env!("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
let current_dir = std::env::current_dir().expect("current_dir");
let file_path = workspace_dir.join(file!());
assert!(file_path.exists(), "{}", file_path.display());
let workspace_dir = std::fs::canonicalize(current_dir.join(workspace_dir)).expect("CARGO_RUSTC_CURRENT_DIR");
let manifest_dir = std::fs::canonicalize(current_dir.join(manifest_dir)).expect("CARGO_MANIFEST_DIR");
assert_eq!(workspace_dir, manifest_dir);
}
"#,
)
.publish();

let p = project()
.file("src/lib.rs", "")
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
[dependencies]
bar = "0.1.0"
"#,
)
.build();

p.cargo("test -p bar")
.masquerade_as_nightly_cargo(&["CARGO_RUSTC_CURRENT_DIR"])
.with_stdout_contains("running 1 test\ntest bar_env ... ok")
.run();
}

#[cargo_test]
fn cargo_rustc_current_dir_is_not_stable() {
if is_nightly() {
return;
}
let p = project()
.file(
"tests/env.rs",
r#"
use std::path::Path;
#[test]
fn env() {
assert_eq!(option_env!("CARGO_RUSTC_CURRENT_DIR"), None);
}
"#,
)
.build();

p.cargo("test").run();
}

#[cargo_test]
Expand Down

0 comments on commit fd2ef54

Please sign in to comment.