Skip to content

Commit

Permalink
rustc: be extremely principled about cross builds
Browse files Browse the repository at this point in the history
There were a lot of collapsed assumptions about the cross build process
in this derivation, especially with the overloaded meanings of useLLVM.
This diff splits useLLVM into a value for each of the build, host, and
target platforms. We also specify more target-specific configure flags,
including passing through the llvm-config-native binary which is built
in some cross configurations. This also allows us to clean up some hacky
NIX_LDFLAGS code.

This commit was tested with the following build configurations:

* x86_64-freebsd -> x86_64-freebsd -> x86_64-freebsd
* x86_64-freebsd -> x86_64-freebsd -> x86_64-linux
* x86_64-freebsd -> x86_64-linux -> x86_64-linux
* x86_64-freebsd -> x86_64-freebsd -> aarch64-linux
* x86_64-freebsd -> aarch64-linux -> aarch64-linux
* x86_64-linux -> x86_64-linux -> x86_64-linux
* x86_64-linux -> x86_64-linux -> aarch64-linux
* x86_64-linux -> aarch64-linux -> aarch64-linux
* x86_64-linux -> x86_64-linux -> x86_64-freebsd
* x86_64-linux -> x86_64-freebsd -> x86_64-freebsd
  • Loading branch information
rhelmot committed Nov 17, 2024
1 parent 597a7ad commit f949222
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 21 deletions.
2 changes: 1 addition & 1 deletion pkgs/development/compilers/rust/1_82.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ let
{
enableSharedLibraries = true;
}
// lib.optionalAttrs (stdenv.targetPlatform.useLLVM or false) {
// lib.optionalAttrs (pkgSet.stdenv.targetPlatform.useLLVM or false) {
# Force LLVM to compile using clang + LLVM libs when targeting pkgsLLVM
stdenv = pkgSet.stdenv.override {
allowedRequisites = null;
Expand Down
46 changes: 26 additions & 20 deletions pkgs/development/compilers/rust/rustc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
let
inherit (lib) optionals optional optionalString concatStringsSep;
inherit (darwin.apple_sdk.frameworks) Security;
useLLVM = stdenv.targetPlatform.useLLVM or false;
useLLVMTarget = stdenv.targetPlatform.useLLVM or false;
useLLVMHost = stdenv.hostPlatform.useLLVM or false;
useLLVMBuild = llvmSharedForBuild.stdenv.cc.libcxx.isLLVM or false;
in stdenv.mkDerivation (finalAttrs: {
pname = "${targetPackages.stdenv.cc.targetPrefix}rustc";
inherit version;
Expand Down Expand Up @@ -65,16 +67,8 @@ in stdenv.mkDerivation (finalAttrs: {
"${pkgsBuildHost.stdenv.cc.targetPrefix}pkg-config";

NIX_LDFLAGS = toString (
# when linking stage1 libstd: cc: undefined reference to `__cxa_begin_catch'
# This doesn't apply to cross-building for FreeBSD because the host
# uses libstdc++, but the target (used for building std) uses libc++
optional (stdenv.hostPlatform.isLinux && !withBundledLLVM && !stdenv.targetPlatform.isFreeBSD && !useLLVM)
"--push-state --as-needed -lstdc++ --pop-state"
++ optional (stdenv.hostPlatform.isLinux && !withBundledLLVM && !stdenv.targetPlatform.isFreeBSD && useLLVM)
"--push-state --as-needed -L${llvmPackages.libcxx}/lib -lc++ -lc++abi -lLLVM-${lib.versions.major llvmPackages.llvm.version} --pop-state"
++ optional (stdenv.hostPlatform.isDarwin && !withBundledLLVM) "-lc++ -lc++abi"
++ optional stdenv.hostPlatform.isFreeBSD "-rpath ${llvmPackages.libunwind}/lib"
++ optional stdenv.hostPlatform.isDarwin "-rpath ${llvmSharedForHost.lib}/lib");
optional (stdenv.buildPlatform.isDarwin && !withBundledLLVM) "-lc++ -lc++abi"
++ optional stdenv.buildPlatform.isDarwin "-rpath ${llvmSharedForHost.lib}/lib");

# Increase codegen units to introduce parallelism within the compiler.
RUSTFLAGS = "-Ccodegen-units=10";
Expand Down Expand Up @@ -153,13 +147,15 @@ in stdenv.mkDerivation (finalAttrs: {
] ++ optionals (!withBundledLLVM) [
"--enable-llvm-link-shared"
"${setBuild}.llvm-config=${llvmSharedForBuild.dev}/bin/llvm-config"
"${setHost}.llvm-config=${llvmSharedForHost.dev}/bin/llvm-config"
"${setTarget}.llvm-config=${llvmSharedForTarget.dev}/bin/llvm-config"
] ++ optionals fastCross [
] ++ (if (llvmShared.stdenv.hostPlatform == llvmShared.stdenv.buildPlatform) then [
"${setHost}.llvm-config=${llvmShared.dev}/bin/llvm-config"
] else [
"${setHost}.llvm-config=${llvmShared.dev}/bin/llvm-config-native"
]) ++ optionals fastCross [
# Since fastCross only builds std, it doesn't make sense (and
# doesn't work) to build a linker.
"--disable-llvm-bitcode-linker"
] ++ optionals (stdenv.targetPlatform.isLinux && !(stdenv.targetPlatform.useLLVM or false)) [
] ++ optionals (stdenv.targetPlatform.isLinux && !useLLVMTarget) [
"--enable-profiler" # build libprofiler_builtins
] ++ optionals stdenv.buildPlatform.isMusl [
"${setBuild}.musl-root=${pkgsBuildBuild.targetPackages.stdenv.cc.libc}"
Expand All @@ -172,9 +168,12 @@ in stdenv.mkDerivation (finalAttrs: {
] ++ optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isx86_64) [
# https://github.com/rust-lang/rust/issues/92173
"--set rust.jemalloc"
] ++ optionals (useLLVM && !stdenv.targetPlatform.isFreeBSD) [
] ++ [
# https://github.com/NixOS/nixpkgs/issues/311930
"--llvm-libunwind=${if withBundledLLVM then "in-tree" else "system"}"
"${setBuild}.llvm-libunwind=${if (!useLLVMBuild || stdenv.buildPlatform.isFreeBSD) then "no" else if withBundledLLVM then "in-tree" else "system"}"
"${setHost}.llvm-libunwind=${if (!useLLVMHost || stdenv.hostPlatform.isFreeBSD) then "no" else if withBundledLLVM then "in-tree" else "system"}"
"${setTarget}.llvm-libunwind=${if (!useLLVMTarget || stdenv.targetPlatform.isFreeBSD) then "no" else if withBundledLLVM then "in-tree" else "system"}"
] ++ optionals (withBundledLLVM && useLLVMHost) [
"--enable-use-libcxx"
];

Expand Down Expand Up @@ -239,7 +238,7 @@ in stdenv.mkDerivation (finalAttrs: {
[source.vendored-sources]
directory = "vendor"
EOF
'' + lib.optionalString (stdenv.hostPlatform.isFreeBSD) ''
'' + lib.optionalString (stdenv.buildPlatform.isFreeBSD) ''
# lzma-sys bundles an old version of xz that doesn't build
# on modern FreeBSD, use the system one instead
substituteInPlace src/bootstrap/src/core/build_steps/tool.rs \
Expand All @@ -257,12 +256,19 @@ in stdenv.mkDerivation (finalAttrs: {
file python3 rustc cmake
which libffi removeReferencesTo pkg-config xz
]
# splicing isn't working here - saying llvmPackages.libcxx here does not give you libcxx for the build platform.
# e.g. if you're doing linux -> freebsd -> freebsd cross, the libcxx here would be linked against freebsd libc.so.7
++ optionals (!withBundledLLVM && useLLVMBuild) [
llvmSharedForBuild.stdenv.cc.libcxx
pkgsBuildBuild.llvmPackages.libunwind
] ++ optional (!withBundledLLVM) llvmSharedForBuild.lib
++ optionals fastCross [ lndir makeWrapper ];

buildInputs = [ openssl ]
++ optionals stdenv.hostPlatform.isDarwin [ libiconv Security zlib ]
++ optional (!withBundledLLVM) llvmShared.lib
++ optional (useLLVM && !withBundledLLVM && !stdenv.targetPlatform.isFreeBSD) [
++ optional (!withBundledLLVM && (useLLVMHost || useLLVMTarget)) llvmPackages.libcxx
++ optionals (useLLVMHost && !withBundledLLVM && !stdenv.hostPlatform.isFreeBSD) [
llvmPackages.libunwind
# Hack which is used upstream https://github.com/gentoo/gentoo/blob/master/dev-lang/rust/rust-1.78.0.ebuild#L284
(runCommandLocal "libunwind-libgcc" {} ''
Expand Down Expand Up @@ -305,7 +311,7 @@ in stdenv.mkDerivation (finalAttrs: {

passthru = {
llvm = llvmShared;
inherit llvmPackages;
inherit llvmPackages llvmSharedForBuild llvmSharedForHost llvmSharedForTarget;
inherit (rustc) tier1TargetPlatforms targetPlatforms badTargetPlatforms;
tests = {
inherit fd ripgrep wezterm;
Expand Down

0 comments on commit f949222

Please sign in to comment.