From 3ff0cd726331b8b4b01606e1fb87e3609d9be72a Mon Sep 17 00:00:00 2001 From: Gustavo Coutinho de Souza Date: Fri, 15 Dec 2023 17:31:09 -0300 Subject: [PATCH] hare: embedd paths for cross-compilation toolchains Also strip the `HAREPATH` make variable embedded in the binary from empty `$(SRCDIR)/hare/third-party`, since since nix does not follows the FHS and relies on the `HAREPATH` environment variable to find third party libraries. --- .../ha/hare/cross-compilation-tests.nix | 31 +++++++++ pkgs/by-name/ha/hare/package.nix | 63 ++++++++++++++++++- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 pkgs/by-name/ha/hare/cross-compilation-tests.nix diff --git a/pkgs/by-name/ha/hare/cross-compilation-tests.nix b/pkgs/by-name/ha/hare/cross-compilation-tests.nix new file mode 100644 index 000000000000..26611fea9d65 --- /dev/null +++ b/pkgs/by-name/ha/hare/cross-compilation-tests.nix @@ -0,0 +1,31 @@ +{ lib +, buildPackages +, hare +, runCommandNoCC +, stdenv +, writeText +}: +let + inherit (stdenv.hostPlatform.uname) processor; + inherit (stdenv.hostPlatform) emulator; + mainDotHare = writeText "main.ha" '' + use fmt; + use os; + export fn main() void = { + const machine = os::machine(); + if (machine == "${processor}") { + fmt::println("os::machine() matches ${processor}")!; + } else { + fmt::fatalf("os::machine() does not match ${processor}: {}", machine); + }; + }; + ''; +in +runCommandNoCC "${hare.pname}-cross-compilation-test" { meta.timeout = 60; } '' + HARECACHE="$(mktemp -d --tmpdir harecache.XXXXXXXX)" + export HARECACHE + outbin="test-${processor}" + ${lib.getExe hare} build -q -a "${processor}" -o "$outbin" ${mainDotHare} + ${emulator buildPackages} "./$outbin" + : 1>$out +'' diff --git a/pkgs/by-name/ha/hare/package.nix b/pkgs/by-name/ha/hare/package.nix index c509955c6f09..a41bcb90a513 100644 --- a/pkgs/by-name/ha/hare/package.nix +++ b/pkgs/by-name/ha/hare/package.nix @@ -8,15 +8,55 @@ , scdoc , tzdata , substituteAll +, callPackage +, enableCrossCompilation ? (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.is64bit) +, pkgsCross +, x86_64PkgsCrossToolchain ? pkgsCross.gnu64 +, aarch64PkgsCrossToolchain ? pkgsCross.aarch64-multiplatform +, riscv64PkgsCrossToolchain ? pkgsCross.riscv64 }: +# There's no support for `aarch64-freebsd` or `riscv64-freebsd` on nix. +# See `lib.systems.doubles.aarch64` and `lib.systems.doubles.riscv64`. +assert let + inherit (stdenv.hostPlatform) isLinux is64bit; + inherit (lib) intersectLists platforms concatStringsSep; + workingPlatforms = intersectLists platforms.linux (with platforms; x86_64 ++ aarch64 ++ riscv64); +in +(enableCrossCompilation -> !(isLinux && is64bit)) + -> builtins.throw '' + The cross-compilation toolchains may only be enabled on the following platforms: + ${concatStringsSep "\n" workingPlatforms} +''; + let # We use harec's override of qbe until 1.2 is released, but the `qbe` argument # is kept to avoid breakage. qbe = harec.qbeUnstable; # https://harelang.org/platforms/ arch = stdenv.hostPlatform.uname.processor; - platform = lib.strings.toLower stdenv.hostPlatform.uname.system; + platform = lib.toLower stdenv.hostPlatform.uname.system; + embeddedOnBinaryTools = + let + genToolsFromToolchain = toolchain: + let + crossTargetPrefix = toolchain.stdenv.cc.targetPrefix; + toolchainArch = toolchain.stdenv.hostPlatform.uname.processor; + absOrRelPath = toolDrv: toolBasename: + if arch == toolchainArch then toolBasename + else lib.getExe' toolDrv "${crossTargetPrefix}${toolBasename}"; + in + { + "ld" = absOrRelPath toolchain.buildPackages.binutils "ld"; + "as" = absOrRelPath toolchain.buildPackages.binutils "as"; + "cc" = absOrRelPath toolchain.stdenv.cc "cc"; + }; + in + { + x86_64 = genToolsFromToolchain x86_64PkgsCrossToolchain; + aarch64 = genToolsFromToolchain aarch64PkgsCrossToolchain; + riscv64 = genToolsFromToolchain riscv64PkgsCrossToolchain; + }; in stdenv.mkDerivation (finalAttrs: { pname = "hare"; @@ -58,6 +98,19 @@ stdenv.mkDerivation (finalAttrs: { "PREFIX=${builtins.placeholder "out"}" "PLATFORM=${platform}" "ARCH=${arch}" + # Strip the variable of an empty $(SRCDIR)/hare/third-party, since nix does + # not follow the FHS. + "HAREPATH=$(SRCDIR)/hare/stdlib" + ] ++ lib.optionals enableCrossCompilation [ + "RISCV64_AS=${embeddedOnBinaryTools.riscv64.as}" + "RISCV64_CC=${embeddedOnBinaryTools.riscv64.cc}" + "RISCV64_LD=${embeddedOnBinaryTools.riscv64.ld}" + "AARCH64_AS=${embeddedOnBinaryTools.aarch64.as}" + "AARCH64_CC=${embeddedOnBinaryTools.aarch64.cc}" + "AARCH64_LD=${embeddedOnBinaryTools.aarch64.ld}" + "x86_64_AS=${embeddedOnBinaryTools.x86_64.as}" + "x86_64_CC=${embeddedOnBinaryTools.x86_64.cc}" + "x86_64_LD=${embeddedOnBinaryTools.x86_64.ld}" ]; enableParallelBuilding = true; @@ -80,6 +133,14 @@ stdenv.mkDerivation (finalAttrs: { setupHook = ./setup-hook.sh; + passthru = { + tests = lib.optionalAttrs enableCrossCompilation { + crossCompilation = callPackage ./cross-compilation-tests.nix { + hare = finalAttrs.finalPackage; + }; + }; + }; + meta = { homepage = "https://harelang.org/"; description = "Systems programming language designed to be simple, stable, and robust";