Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(env): cargo:rerun-if-env-changed doesn't work with env configuration #14058

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

heisen-li
Copy link
Contributor

@heisen-li heisen-li commented Jun 13, 2024

What does this PR try to resolve?

Fixes #10358
Fixes #8693

Additional information

Due to my stupidity, I screwed up the previous PR. I didn't know what to do with it, so I created a new PR.

r?@epage

@rustbot rustbot added A-cfg-expr Area: Platform cfg expressions A-rebuild-detection Area: rebuild detection and fingerprinting S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 13, 2024
@heisen-li heisen-li changed the title Config env changefix(env): cargo:rerun-if-env-changed doesn't work with env configuration fix(env): cargo:rerun-if-env-changed doesn't work with env configuration Jun 13, 2024
@epage
Copy link
Contributor

epage commented Jun 26, 2024

btw I believe this would also fix #8693.

This would likely need to revert #12482.

@heisen-li heisen-li force-pushed the config_env_change branch 4 times, most recently from 08bbb58 to d19af49 Compare July 1, 2024 09:16
@epage epage added the T-cargo Team: Cargo label Jul 5, 2024
@rustbot rustbot added the A-documenting-cargo-itself Area: Cargo's documentation label Jul 18, 2024
Comment on lines +151 to +157
p.change_file(
".cargo/config.toml",
r#"
[env]
OUT_DIR = "somedir"
"#,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention of this test is for detecting changes made by cargo, and not the user. Us manually setting one runs counter to that

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is for #8693 and planning to revert #12482. However Cargo doesn't really respect env vars that are set by Cargo internally. Why this should recompile?
This fixes a confusion with the other new confusion introduced.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too sure what the concern is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting env.OUR_DIR has no effect on build script execution.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, that. The intent of my comment was to say that we should not test this with [env] but making a change that causes the cargo-provided env to change.

"build.rs",
r#"
fn main() {
println!("cargo:rerun-if-env-changed=foo");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double colons syntax is preferrable

Suggested change
println!("cargo:rerun-if-env-changed=foo");
println!("cargo::rerun-if-env-changed=foo");

}
}
"#,
fn main() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This formatting change shouldn't have happened, or should merge into the first commit adding the test.


[COMPILING] foo v0.1.0 ([ROOT]/foo)
[ERROR] failed to run custom build command for `foo v0.1.0 ([ROOT]/foo)`
...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should better check if our assertion actually causes the error message. Perhaps add an assertion message assert!(..., "rerun due to FOO changed") and see if the message contain it.

let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.file(
".cargo/config.toml",
r#"
[env]
FOO = "good"
Foo = "good"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you merge this into the commit that the test first appeared?

Comment on lines +151 to +157
p.change_file(
".cargo/config.toml",
r#"
[env]
OUT_DIR = "somedir"
"#,
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is for #8693 and planning to revert #12482. However Cargo doesn't really respect env vars that are set by Cargo internally. Why this should recompile?
This fixes a confusion with the other new confusion introduced.

} else {
envs.get(key).and_then(|v| v.to_owned())
}
.or(env::var_os(key))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lazy evaluation

Suggested change
.or(env::var_os(key))
.or_else(|| env::var_os(key))

envs: &BTreeMap<String, Option<OsString>>,
) -> Option<OsString> {
let upper_case_key: String = key.to_uppercase();
for (k, v) in envs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conversion seems to be in a deeply nested loop. M rerun_if_env_changed * N [env] keys on Windows. We should probably find a way to do it once and for all.

This doesn't really seem to be a performance issue for general usage though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small fix would be to check the map with the key as-is, and then only check for the case-insensitive if that fails. 99% of the time the case will match. EnvConfig::get_env_os does something similar.

@@ -588,6 +590,10 @@ impl TargetInfo {
.iter()
.any(|sup| sup.as_str() == split.as_str())
}

pub fn get_target_envs(&self) -> &BTreeMap<String, Option<OsString>> {
return self.crate_type_process.get_envs();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing crate_type_process seems like a hacky shortcut to me. The process is for learning target info from rustc, but fingerprint is for actual rustc compilation. One extension point for putting it here is for supporting #10273, though I believe that will need other rounds of env var system overhual in Cargo.

Copy link
Contributor

@ehuss ehuss Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree, the chance of this having unintended consequences seems kinda high since it isn't obvious when looking at TargetInfo that this would also influence build-script environment fingerprinting.

Would it be possible to rewrite apply_env_config so that there is a separate function that yields a map of resolved config values? Then the code in the fingerprint module could call that and collect the results into a map that it could then pass into the closure.

(I also wonder if it ends up creating a new map, if it could pre-normalize it on Windows to avoid the inner case-check loop.)

Comment on lines -772 to -773
// TODO: This is allowed at this moment. Should figure out if it makes
// sense if permitting to read env from the config system.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of removing this, can we have a comment explaining why the allow can't be removed? It's not obvious to me that there is some fundamental problem that is preventing this.

I presume the problem is that the closure cannot access the GlobalContext, and thus is unable to access the env snapshot, and thus must access the raw environment directly? It seems like there are still options we can consider, such as wrapping the environment in Arc or something like that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

such as wrapping the environment in Arc

Agree Arc is the way to resolve this.

envs: &BTreeMap<String, Option<OsString>>,
) -> Option<OsString> {
let upper_case_key: String = key.to_uppercase();
for (k, v) in envs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A small fix would be to check the map with the key as-is, and then only check for the case-insensitive if that fails. 99% of the time the case will match. EnvConfig::get_env_os does something similar.

@ehuss
Copy link
Contributor

ehuss commented Jul 24, 2024

I'm not clear, how does this fix #8693?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-cfg-expr Area: Platform cfg expressions A-documenting-cargo-itself Area: Cargo's documentation A-rebuild-detection Area: rebuild detection and fingerprinting S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-cargo Team: Cargo
Projects
None yet
6 participants