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 Dec 22, 2024
1 parent 87387bb commit c91316e
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 23 deletions.
2 changes: 1 addition & 1 deletion pkgs/development/compilers/rust/1_83.nix
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,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
81 changes: 59 additions & 22 deletions pkgs/development/compilers/rust/rustc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ let
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";
Expand Down Expand Up @@ -93,19 +95,8 @@ 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.
Expand Down Expand Up @@ -199,15 +190,23 @@ 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"
]
++ (
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 [
Expand All @@ -226,9 +225,34 @@ stdenv.mkDerivation (finalAttrs: {
# 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 @@ -311,7 +335,7 @@ stdenv.mkDerivation (finalAttrs: {
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 Down Expand Up @@ -340,6 +364,13 @@ stdenv.mkDerivation (finalAttrs: {
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
Expand All @@ -353,7 +384,8 @@ stdenv.mkDerivation (finalAttrs: {
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 @@ -402,7 +434,12 @@ 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 c91316e

Please sign in to comment.