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

Iteratively construct target cfg #11114

Merged
merged 2 commits into from
Sep 27, 2022
Merged

Iteratively construct target cfg #11114

merged 2 commits into from
Sep 27, 2022

Conversation

matklad
Copy link
Member

@matklad matklad commented Sep 20, 2022

When setting target features via rustflags via [build] config key, cargo correctly propagates them to rustc (via -C flag) and to build.rs (via CARGO_CFG_TARGET_FEATURE env var).

However, if [target.cfg] is used instead, build.rs doesn't get the flags (rustc still gets them though).

This changes it so that cargo will call rustc up to two times to collect the cfg values, updating which flags to use on the second call based on the cfg discovered in the first call.

Closes #6858.

When setting target features via rustflags via `[build]` config key,
cargo correctly propagates them to rustc (via -C flag) and to build.rs
(via CARGO_CFG_TARGET_FEATURE env var).

However, if `[target.cfg]` is used instead, build.rs doesn't get the
flags (rustc still gets them though).
@rust-highfive
Copy link

r? @ehuss

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Sep 20, 2022
@matklad
Copy link
Member Author

matklad commented Sep 20, 2022

Ok, I think I've debugged what is happening here. The core of the issue is that we get an inconsistent TargetInfo at some point, which looks like this:

TargetInfo {
  rustflags: ["-Ctarget-feature=+sse4.1,+sse4.2"]
  cfg: debug_assertions,panic = "unwind",target_arch = "x86_64",target_endian = "little",target_env = "gnu",target_family = "unix",target_feature = "fxsr",target_feature = "sse",target_feature = "sse2",target_has_atomic = "16",target_has_atomic = "32",target_has_atomic = "64",target_has_atomic = "8",target_has_atomic = "ptr",target_os = "linux",target_pointer_width = "64",target_vendor = "unknown",unix
}

that is, rusflags says that we have sse4.2, but cfg say we don't. When we run build.rs, we look at the cfg. When we run the actual compiler, we use RUSTFLAGS, hence the discrepancy.

I think the issue lies in this logic:

// recalculate `rustflags` from above now that we have `cfg`
// information
rustflags: env_args(
config,
requested_kinds,
&rustc.host,
Some(&cfg),
kind,
Flags::Rust,
)?,

What happens here is that rustflags and cfgs are mutually dependent: rustflags determine rustc's cfgs, and cfgs determine which config sections apply, which might affect rustflags. The code currently does one-and-a-half iterations of fixed point algorithm.

@matklad
Copy link
Member Author

matklad commented Sep 20, 2022

The last commit adds a fixed-point iteration loop, as a crude hack. That looks somewhat amusing, in not a good way, so I think I'll pause here and wait for feedback from Cargo team on this one!

@ehuss
Copy link
Contributor

ehuss commented Sep 25, 2022

There is some more background on this general problem in #6858. I've been reluctant to run rustc in a loop because it can take hundreds of milliseconds to run each time. I would be a little more comfortable doing that if it could bypass rustup (#10986, rust-lang/rustup#3031, rust-lang/rustup#3035). However, I believe this should only be a problem if rustflags is explicitly set in a target config table, right? And that should only affect the first uncached run, right?

It might be good to also give some careful consideration on the backwards compatibility hazards with this change. Will it change the behavior for existing projects in a meaningful way?

The overall approach seems reasonable to me.

supports_split_debuginfo,
});
}
anyhow::bail!("diverging rustflags")
Copy link
Contributor

Choose a reason for hiding this comment

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

Before merging, I think it would be good to make this error a little more descriptive.

I also wouldn't say it is necessarily diverging. It could just be that it requires more steps to finish.

@matklad
Copy link
Member Author

matklad commented Sep 26, 2022

Yeah, this all sounds reasonable. We indeed should only run this when needed, and it indeed should be cached. Given that the use-case here is essentially "set cfgs based on other cfgs", I don't see a better fundamental solution.

For my specific use-case (setting target_features), I would imagine a more specialized solution (like a dedicated key in the profile or what not) would work, but, even if we had that, it still is very surprising that today's code observes inconsistent information between build.rs and rustc.

Regarding backwards compatibility, yeah.... This definitely would affect some builds, probably not too many, and probably by making them more correct, but "fixing builds" tends annoy people also :) I guess my value judgement is that this is a rather obscure corner case, so few folks would be affected, and it feels like its' worth fixing (in our case, we get a significant but suble perf regression due to sse flags not propagating to our C deps).

Thats why, after sleeping on it, I figured that outright erroring-out is probably not the right call here, so:

  • I restricted us to do only 2 iterations
  • I warn, rather than error, if that's not enough

This, at least, is guaranteed to not outright bork any existing builds. I've also added a test which fixes the current behavior.

@ehuss ehuss changed the title add failing test for CARGO_CFG_TARGET_FEATURE Iteratively construct target cfg Sep 26, 2022
@ehuss
Copy link
Contributor

ehuss commented Sep 26, 2022

Sounds reasonable to me. Thanks!

@bors r+

@bors
Copy link
Collaborator

bors commented Sep 26, 2022

📌 Commit c333b0a has been approved by ehuss

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 26, 2022
@Mark-Simulacrum
Copy link
Member

@bors r- r=ehuss

@bors bors added S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Sep 27, 2022
@bors
Copy link
Collaborator

bors commented Sep 27, 2022

📌 Commit c333b0a has been approved by ehuss

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. labels Sep 27, 2022
@bors
Copy link
Collaborator

bors commented Sep 27, 2022

⌛ Testing commit c333b0a with merge f6de921...

@bors
Copy link
Collaborator

bors commented Sep 27, 2022

☀️ Test successful - checks-actions
Approved by: ehuss
Pushing f6de921 to master...

@bors bors merged commit f6de921 into rust-lang:master Sep 27, 2022
bors pushed a commit to rust-lang-ci/rust that referenced this pull request Sep 27, 2022
22 commits in 73ba3f35e0205844418260722c11602113179c4a..f5fed93ba24607980647962c59863bbabb03ce14
2022-09-18 06:38:16 +0000 to 2022-09-27 12:03:57 +0000

- build-scripts.md: Use em dash consistently. (rust-lang/cargo#11150)
- Indicate how Cargo locates the manifest (rust-lang/cargo#10770)
- Reduce references to `[project]` within cargo (rust-lang/cargo#11135)
- Iteratively construct target cfg (rust-lang/cargo#11114)
- update comment about `CARGO_BIN_EXE_` (rust-lang/cargo#11146)
- Call out that not all config values can be set via env vars (rust-lang/cargo#11139)
- Bump to 0.67.0, update changelog (rust-lang/cargo#11137)
- ci: update toolchain for building api doc (rust-lang/cargo#11134)
- Http publish not noop (rust-lang/cargo#11111)
- Improve errors for TOML fields that support workspace inheritance (rust-lang/cargo#11113)
- switch to `std::task::ready!()` where possible (rust-lang/cargo#11130)
- Report cmd aliasing failure with more contexts (rust-lang/cargo#11087)
- minor: remove unused mut (rust-lang/cargo#11127)
- fix(cli): Forward non-UTF8 arguments to external subcommands (rust-lang/cargo#11118)
- This change adds an example to the authors attribute in the manifest. (rust-lang/cargo#10938)
- Add support for relative git submodule paths (rust-lang/cargo#11106)
- make unknown features on `cargo add` more discoverable (rust-lang/cargo#11098)
- Unlink old final artifacts before compilation (rust-lang/cargo#11122)
- refactor(cli): Prepare for clap v4 (rust-lang/cargo#11116)
- fix(cli): Error trailing args rather than ignore (rust-lang/cargo#11119)
- Add a minor clarification (rust-lang/cargo#11093)
- doc(changelog): mention CVE fixes (rust-lang/cargo#11104)
bors added a commit to rust-lang-ci/rust that referenced this pull request Sep 27, 2022
Update cargo

22 commits in 73ba3f35e0205844418260722c11602113179c4a..f5fed93ba24607980647962c59863bbabb03ce14 2022-09-18 06:38:16 +0000 to 2022-09-27 12:03:57 +0000

- build-scripts.md: Use em dash consistently. (rust-lang/cargo#11150)
- Indicate how Cargo locates the manifest (rust-lang/cargo#10770)
- Reduce references to `[project]` within cargo (rust-lang/cargo#11135)
- Iteratively construct target cfg (rust-lang/cargo#11114)
- update comment about `CARGO_BIN_EXE_` (rust-lang/cargo#11146)
- Call out that not all config values can be set via env vars (rust-lang/cargo#11139)
- Bump to 0.67.0, update changelog (rust-lang/cargo#11137)
- ci: update toolchain for building api doc (rust-lang/cargo#11134)
- Http publish not noop (rust-lang/cargo#11111)
- Improve errors for TOML fields that support workspace inheritance (rust-lang/cargo#11113)
- switch to `std::task::ready!()` where possible (rust-lang/cargo#11130)
- Report cmd aliasing failure with more contexts (rust-lang/cargo#11087)
- minor: remove unused mut (rust-lang/cargo#11127)
- fix(cli): Forward non-UTF8 arguments to external subcommands (rust-lang/cargo#11118)
- This change adds an example to the authors attribute in the manifest. (rust-lang/cargo#10938)
- Add support for relative git submodule paths (rust-lang/cargo#11106)
- make unknown features on `cargo add` more discoverable (rust-lang/cargo#11098)
- Unlink old final artifacts before compilation (rust-lang/cargo#11122)
- refactor(cli): Prepare for clap v4 (rust-lang/cargo#11116)
- fix(cli): Error trailing args rather than ignore (rust-lang/cargo#11119)
- Add a minor clarification (rust-lang/cargo#11093)
- doc(changelog): mention CVE fixes (rust-lang/cargo#11104)
@ehuss ehuss added this to the 1.66.0 milestone Oct 1, 2022
near-bulldozer bot pushed a commit to near/nearcore that referenced this pull request Jan 9, 2023
)

With #8284 we upgraded cargo version to `1.66`, so rust-lang/cargo#11114 is available. This PR is the same as #7130, but we can safely merge it now.

See #7650 for more context.

In order to test it I've used the code from [`librocksdb-sys/build.rs`](https://github.com/rust-rocksdb/rust-rocksdb/blob/master/librocksdb-sys/build.rs#L111) as part of `neard/build.rs`:
```
 fn main() {
-    if let Err(err) = try_main() {
-        eprintln!("{}", err);
-        std::process::exit(1);
+    let target_feature = std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap();
+    let target_features: Vec<_> = target_feature.split(',').collect();
+    if target_features.contains(&"neon") {
+        panic!("FAIL: {target_feature}");
+    } else {
+        panic!("OK: {target_feature}");
     }
 }
```

It was was tested on M1 macbook, so I've changed the feature to `neon` (which is enabled by default), my `.cargo/config.toml` is as follows:
```
-[target.'cfg(target_arch = "x86_64")']
-rustflags = ["-Ctarget-feature=+sse4.1,+sse4.2", "-Cforce-unwind-tables=y"]
+[target.'cfg(target_arch = "aarch64")']
+rustflags = ["-Ctarget-feature=-neon", "-Cforce-unwind-tables=y"]
```

`neon` was successfully removed when using `1.66` toolchain:
```
OK: crc,...,vh
```

while it was still present with `1.65`:
```
FAIL: aes,..,neon,...,vh
```

This proves that rustflags are passed as env variable to `build.rs` in `1.66`, which was not the case in `1.65`
nikurt pushed a commit to nikurt/nearcore that referenced this pull request Jan 15, 2023
…ar#8305)

With near#8284 we upgraded cargo version to `1.66`, so rust-lang/cargo#11114 is available. This PR is the same as near#7130, but we can safely merge it now.

See near#7650 for more context.

In order to test it I've used the code from [`librocksdb-sys/build.rs`](https://github.com/rust-rocksdb/rust-rocksdb/blob/master/librocksdb-sys/build.rs#L111) as part of `neard/build.rs`:
```
 fn main() {
-    if let Err(err) = try_main() {
-        eprintln!("{}", err);
-        std::process::exit(1);
+    let target_feature = std::env::var("CARGO_CFG_TARGET_FEATURE").unwrap();
+    let target_features: Vec<_> = target_feature.split(',').collect();
+    if target_features.contains(&"neon") {
+        panic!("FAIL: {target_feature}");
+    } else {
+        panic!("OK: {target_feature}");
     }
 }
```

It was was tested on M1 macbook, so I've changed the feature to `neon` (which is enabled by default), my `.cargo/config.toml` is as follows:
```
-[target.'cfg(target_arch = "x86_64")']
-rustflags = ["-Ctarget-feature=+sse4.1,+sse4.2", "-Cforce-unwind-tables=y"]
+[target.'cfg(target_arch = "aarch64")']
+rustflags = ["-Ctarget-feature=-neon", "-Cforce-unwind-tables=y"]
```

`neon` was successfully removed when using `1.66` toolchain:
```
OK: crc,...,vh
```

while it was still present with `1.65`:
```
FAIL: aes,..,neon,...,vh
```

This proves that rustflags are passed as env variable to `build.rs` in `1.66`, which was not the case in `1.65`
@matklad matklad deleted the build-falgs branch March 29, 2023 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enabling target features in .cargo/config does not work for cfg statements in Cargo.toml
5 participants