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

rust: fix overriding rust flags on musl #221413

Merged
merged 1 commit into from
Mar 17, 2023
Merged

Conversation

alyssais
Copy link
Member

@alyssais alyssais commented Mar 16, 2023

Description of changes

If RUSTFLAGS is set in the environment, Cargo will ignore rustflags settings in its TOML configuration. So setting RUSTFLAGS=-g (like separateDebugInfo does) to generate debug info breaks dynamically-linked Rust packages on musl. This breakage is visible for any packages that call into C dynamic libraries. If the binary is linked directly to a C dynamic library, it will fail to build, and if it depends on a Rust library which links a C dynamic library, it will segfault at runtime when it tries to call a function from the C library. I noticed this because pkgsMusl.crosvm is broken for this reason, since it sets separateDebugInfo = true.

It shouldn't be possible to end up with broken binaries just by using RUSTFLAGS to do something innocuous like enable debug info, so I think that, even though we liked the approach of modifying .cargo/config better at the time, it's become clear that it's too brittle, and we should bite the bullet and patch the compiler instead when targeting musl. It does not appear to be necessary to modify the compiler at all when cross-compiling from dynamically-linked musl to another target, so I'm only checking whether the target system is dynamically-linked musl when deciding whether to make the modification to the compiler.

This reverts commit c2eaaae ("cargoSetupHook: pass host config flags") (#198311), and implements the compiler patching approach instead, as originally proposed in #190796.

Things done
  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 23.05 Release Notes (or backporting 22.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

@alyssais alyssais added 6.topic: rust 6.topic: musl Running or building packages with musl libc labels Mar 16, 2023
@alyssais alyssais requested review from symphorien and yu-re-ka March 16, 2023 01:51
@figsoda
Copy link
Member

figsoda commented Mar 16, 2023

also see #220660, as they will run into merge conflicts

If RUSTFLAGS is set in the environment, Cargo will ignore rustflags
settings in its TOML configuration.  So setting RUSTFLAGS=-g (like
separateDebugInfo does) to generate debug info breaks
dynamically-linked Rust packages on musl.  This breakage is visible
for any packages that call into C dynamic libraries.  If the binary is
linked directly to a C dynamic library, it will fail to build, and if
it depends on a Rust library which links a C dynamic library, it will
segfault at runtime when it tries to call a function from the C
library.  I noticed this because pkgsMusl.crosvm is broken for this
reason, since it sets separateDebugInfo = true.

It shouldn't be possible to end up with broken binaries just by using
RUSTFLAGS to do something innocuous like enable debug info, so I think
that, even though we liked the approach of modiyfing .cargo/config
better at the time, it's become clear that it's too brittle, and we
should bite the bullet and patch the compiler instead when targetting
musl.  It does not appear to be necessary to modify the compiler at
all when cross-compiling /from/ dynamically-linked Musl to another
target, so I'm only checking whether the target system is
dynamically-linked Musl when deciding whether to make the modification
to the compiler.

This reverts commit c2eaaae
("cargoSetupHook: pass host config flags"), and implements the
compiler patching approach instead.
Copy link
Contributor

@yu-re-ka yu-re-ka left a comment

Choose a reason for hiding this comment

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

Sounds reasonable. Let's do this first, and then I re-do #220660?
Though it is technically not needed anymore, at least to fix the musl firefox build

@yu-re-ka
Copy link
Contributor

yu-re-ka commented Mar 16, 2023

In the future we might want to consider creating a proper wrapper for rustc, since this would avoid building two different rustcs to produce dynamically vs statically linked binaries in pkgsCross.musl64 vs pkgsStatic.

Also see #211254 #176694 related to reducing the number of different rustc variants we have

@alyssais
Copy link
Member Author

Sounds reasonable. Let's do this first, and then I re-do #220660?
Though it is technically not needed anymore, at least to fix the musl firefox build

SGTM. I still think your PR is a good idea, even if it just ends up setting the linker.

@lovesegfault
Copy link
Member

Alternatively, couldn't you just set CARGO_BUILD_RUSTFLAGS instead of RUSTFLAGS? IIRC the former gets merged with rustflags from config files, whether the latter does not.

@alyssais
Copy link
Member Author

alyssais commented Mar 16, 2023

IIRC the former gets merged with rustflags from config files, whether the latter does not.

I don't think so — "Environment variables will take precedence over TOML configuration files."

@weihanglo
Copy link

weihanglo commented Mar 16, 2023

Cargo tries its best to merge TOML lists. Here is a super dirty one-liner to check.

CARGO_BUILD_RUSTFLAGS="--cfg foo" cargo +nightly -Zunstable-options config get build.rustflags --config 'build.rustflags=["--cfg", "bar"]'

Or you can cargo new a project to verify what I say.

Look into the source code. During the deserialization of CARGO_ prefixed environment variables, it calls a method Config::get_env_list, which gets env as a list if the config value from .config.toml file is also a list.

Thus, I think @lovesegfault is correct.

@alyssais
Copy link
Member Author

Okay. I still think it shouldn't be possible for users to break their executables at runtime by setting innocuous RUSTFLAGS, so I still think we should make this change.

@yu-re-ka
Copy link
Contributor

yu-re-ka commented Mar 17, 2023

I do think that long-term we should find a way to pass the correct crt-static and linker for both host and target (in cargo terms), when the target-applies-to-host feature in cargo is stabilized etc.
I agree with Alyssa that unforseen breakages like with RUSTFLAGS and also other problems like mentioned here are not good, and thus the solution implemented by this PR is currently the best option we have for making musl dynamically linked and statically linked work while not breaking too many other things.
Does anyone not want this PR to get merged as-is?

@figsoda figsoda merged commit 7d23bdd into NixOS:staging Mar 17, 2023
@alyssais alyssais deleted the rustc-musl branch March 17, 2023 21:54
@ghost

This comment was marked as outdated.

@ghost
Copy link

ghost commented Apr 9, 2023

Hi, it's awesome that this PR fixed the musl-is-always-static assumption. But...

This reverts commit c2eaaae ("cargoSetupHook: pass host config flags") (#198311), and implements the compiler patching approach instead, as originally proposed in #190796.

It looks like this PR reverted c2eaaae on all platforms but only "implement(ed) the compiler patching approach instead" on isMusl && !isStatic.

Specifically, I'm having a hard time figuring out how to rebase #211868 past this commit. Where is rustFlagsFor stdenv.buildPlatform supposed to go?

For the time being I've put a partial revert of 470e613 into #211868 but hopefully there is a less radical way to get things done there.

@yu-re-ka
Copy link
Contributor

yu-re-ka commented Apr 9, 2023

Where is rustFlagsFor stdenv.buildPlatform supposed to go?

The issue is that Cargo does not have a proper way of specifying this, without breaking the RUSTFLAGS environment variable.
Honestly we should eventually wrap the rustc or something, so that our flags are used even for other build systems than cargo, and "just work" transparently.
But nobody has figured this out yet.

@ghost
Copy link

ghost commented Apr 13, 2023

> The issue is that Cargo does not have a proper way of specifying this, without breaking the RUSTFLAGS environment variable.

But then doesn't this PR therefore break RUSTFLAGS on musl? That's why I'm confused: why can't all the platforms do what musl does?

Nevermind, I misread this as affecting things built by cargo rather than the build of cargo itself.

Honestly we should eventually wrap the rustc or something, so that our flags are used even for other build systems than cargo, and "just work" transparently.
But nobody has figured this out yet.

I might be interested in taking this up.

Is there a reason why this is any more difficult than NIX_CFLAGS_COMPILE? It looks like cargo (thankfully) interfaces with rustc via ordinary exec() rather than some private API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants