From 470e6130b347c5aabc63cd6600ba78fa909e8e2a Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Thu, 16 Mar 2023 00:09:35 +0000 Subject: [PATCH] rust: fix overriding rust flags on musl 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 c2eaaae50d66a933e38256bdf5a3ae43430592a3 ("cargoSetupHook: pass host config flags"), and implements the compiler patching approach instead. --- pkgs/build-support/rust/hooks/default.nix | 33 +++----------------- pkgs/development/compilers/rust/cargo.nix | 38 ++++++++++++++++++++++- pkgs/development/compilers/rust/rustc.nix | 12 +++++++ 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/pkgs/build-support/rust/hooks/default.nix b/pkgs/build-support/rust/hooks/default.nix index 168224e39b359..2eb388fe07ba8 100644 --- a/pkgs/build-support/rust/hooks/default.nix +++ b/pkgs/build-support/rust/hooks/default.nix @@ -76,37 +76,14 @@ in { # inputs do not cause us to find the wrong `diff`. diff = "${lib.getBin buildPackages.diffutils}/bin/diff"; - # We want to specify the correct crt-static flag for both - # the build and host platforms. This is important when the wanted - # value for crt-static does not match the defaults in the rustc target, - # like for pkgsMusl or pkgsCross.musl64; Upstream rustc still assumes - # that musl = static[1]. - # - # By default, Cargo doesn't apply RUSTFLAGS when building build.rs - # if --target is passed, so the only good way to set crt-static for - # build.rs files is to use the unstable -Zhost-config Cargo feature. - # This allows us to specify flags that should be passed to rustc - # when building for the build platform. We also need to use - # -Ztarget-applies-to-host, because using -Zhost-config requires it. - # - # When doing this, we also have to specify the linker, or cargo - # won't pass a -C linker= argument to rustc. This will make rustc - # try to use its default value of "cc", which won't be available - # when cross-compiling. - # - # [1]: https://github.com/rust-lang/compiler-team/issues/422 cargoConfig = '' - [host] + [target."${rust.toRustTarget stdenv.buildPlatform}"] "linker" = "${ccForBuild}" - "rustflags" = [ "-C", "target-feature=${if stdenv.buildPlatform.isStatic then "+" else "-"}crt-static" ] - - [target."${shortTarget}"] - "linker" = "${ccForHost}" + ${lib.optionalString (stdenv.buildPlatform.config != stdenv.hostPlatform.config) '' + [target."${shortTarget}"] + "linker" = "${ccForHost}" + ''} "rustflags" = [ "-C", "target-feature=${if stdenv.hostPlatform.isStatic then "+" else "-"}crt-static" ] - - [unstable] - host-config = true - target-applies-to-host = true ''; }; } ./cargo-setup-hook.sh) {}; diff --git a/pkgs/development/compilers/rust/cargo.nix b/pkgs/development/compilers/rust/cargo.nix index 481b4195891ca..eb3dc238a9abc 100644 --- a/pkgs/development/compilers/rust/cargo.nix +++ b/pkgs/development/compilers/rust/cargo.nix @@ -1,4 +1,4 @@ -{ lib, stdenv, pkgsHostHost +{ lib, stdenv, pkgsBuildHost, pkgsHostHost , file, curl, pkg-config, python3, openssl, cmake, zlib , installShellFiles, makeWrapper, rustPlatform, rustc , CoreFoundation, Security @@ -20,6 +20,42 @@ rustPlatform.buildRustPackage { inherit (rustc) tests; }; + # Upstream rustc still assumes that musl = static[1]. The fix for + # this is to disable crt-static by default for non-static musl + # targets. + # + # For every package apart from Cargo, we can fix this by just + # patching rustc to not have crt-static by default. But Cargo is + # built with the upstream bootstrap binary for rustc, which we can't + # easily patch. This means we need to find another way to make sure + # crt-static is not used during the build of pkgsMusl.cargo. + # + # By default, Cargo doesn't apply RUSTFLAGS when building build.rs + # if --target is passed, so the only good way to set -crt-static for + # build.rs files used in the Cargo build is to use the unstable + # -Zhost-config Cargo feature. This allows us to specify flags that + # should be passed to rustc when building for the build platform. + # We also need to use -Ztarget-applies-to-host, because using + # -Zhost-config requires it. + # + # When doing this, we also have to specify the linker, or cargo + # won't pass a -C linker= argument to rustc. This will make rustc + # try to use its default value of "cc", which won't be available + # when cross-compiling. + # + # [1]: https://github.com/rust-lang/compiler-team/issues/422 + postPatch = lib.optionalString (with stdenv.buildPlatform; isMusl && !isStatic) '' + mkdir -p .cargo + cat <> .cargo/config + [host] + rustflags = "-C target-feature=-crt-static" + linker = "${pkgsBuildHost.stdenv.cc}/bin/${pkgsBuildHost.stdenv.cc.targetPrefix}cc" + [unstable] + host-config = true + target-applies-to-host = true + EOF + ''; + # changes hash of vendor directory otherwise dontUpdateAutotoolsGnuConfigScripts = true; diff --git a/pkgs/development/compilers/rust/rustc.nix b/pkgs/development/compilers/rust/rustc.nix index 7cb6f22c949b4..f9068a7999a20 100644 --- a/pkgs/development/compilers/rust/rustc.nix +++ b/pkgs/development/compilers/rust/rustc.nix @@ -147,6 +147,18 @@ in stdenv.mkDerivation rec { # Useful debugging parameter # export VERBOSE=1 + '' + lib.optionalString (stdenv.targetPlatform.isMusl && !stdenv.targetPlatform.isStatic) '' + # Upstream rustc still assumes that musl = static[1]. The fix for + # this is to disable crt-static by default for non-static musl + # targets. + # + # Even though Cargo will build build.rs files for the build platform, + # cross-compiling _from_ musl appears to work fine, so we only need + # to do this when rustc's target platform is dynamically linked musl. + # + # [1]: https://github.com/rust-lang/compiler-team/issues/422 + substituteInPlace compiler/rustc_target/src/spec/linux_musl_base.rs \ + --replace "base.crt_static_default = true" "base.crt_static_default = false" '' + lib.optionalString (stdenv.isDarwin && stdenv.isx86_64) '' # See https://github.com/jemalloc/jemalloc/issues/1997 # Using a value of 48 should work on both emulated and native x86_64-darwin.