about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2024-06-30 14:05:33 +0300
committerGitHub <noreply@github.com>2024-06-30 14:05:33 +0300
commit641b2f29b62ef1e809e9d3d4cfd4cb419fac2275 (patch)
tree58fd619e9765f62d5a2228365270af289251f207
parent3a1c0f02db82b5d7857337baf24233b6c1837e04 (diff)
parentcc379b60f0af632aeb8c4e0f42820a03d90d673a (diff)
Merge pull request #319153 from Kranzes/buildRustCrate-wasm
buildRustCrate: add support for compiling to wasm32-unknown-unknown
-rw-r--r--lib/systems/default.nix35
-rw-r--r--lib/systems/examples.nix6
-rw-r--r--lib/systems/parse.nix5
-rw-r--r--pkgs/build-support/rust/build-rust-crate/build-crate.nix11
-rw-r--r--pkgs/build-support/rust/build-rust-crate/default.nix16
-rw-r--r--pkgs/build-support/rust/build-rust-crate/test/default.nix33
-rw-r--r--pkgs/top-level/all-packages.nix4
7 files changed, 78 insertions, 32 deletions
diff --git a/lib/systems/default.nix b/lib/systems/default.nix
index 0981122388bb1..074239b3fb6f1 100644
--- a/lib/systems/default.nix
+++ b/lib/systems/default.nix
@@ -84,20 +84,21 @@ let
       useLLVM = final.isFreeBSD || final.isOpenBSD;
 
       libc =
-        /**/ if final.isDarwin              then "libSystem"
-        else if final.isMinGW               then "msvcrt"
-        else if final.isWasi                then "wasilibc"
-        else if final.isRedox               then "relibc"
-        else if final.isMusl                then "musl"
-        else if final.isUClibc              then "uclibc"
-        else if final.isAndroid             then "bionic"
-        else if final.isLinux /* default */ then "glibc"
-        else if final.isFreeBSD             then "fblibc"
-        else if final.isOpenBSD             then "oblibc"
-        else if final.isNetBSD              then "nblibc"
-        else if final.isAvr                 then "avrlibc"
-        else if final.isGhcjs               then null
-        else if final.isNone                then "newlib"
+        /**/ if final.isDarwin                then "libSystem"
+        else if final.isMinGW                 then "msvcrt"
+        else if final.isWasi                  then "wasilibc"
+        else if final.isWasm && !final.isWasi then null
+        else if final.isRedox                 then "relibc"
+        else if final.isMusl                  then "musl"
+        else if final.isUClibc                then "uclibc"
+        else if final.isAndroid               then "bionic"
+        else if final.isLinux  /* default */  then "glibc"
+        else if final.isFreeBSD               then "fblibc"
+        else if final.isOpenBSD               then "oblibc"
+        else if final.isNetBSD                then "nblibc"
+        else if final.isAvr                   then "avrlibc"
+        else if final.isGhcjs                 then null
+        else if final.isNone                  then "newlib"
         # TODO(@Ericson2314) think more about other operating systems
         else                                     "native/impure";
       # Choose what linker we wish to use by default. Someday we might also
@@ -179,6 +180,7 @@ let
         (isAndroid || isGnu || isMusl                                  # Linux (allows multiple libcs)
          || isDarwin || isSunOS || isOpenBSD || isFreeBSD || isNetBSD  # BSDs
          || isCygwin || isMinGW                                        # Windows
+         || isWasm                                                     # WASM
         ) && !isStatic;
 
       # The difference between `isStatic` and `hasSharedLibraries` is mainly the
@@ -187,7 +189,7 @@ let
       # don't support dynamic linking, but don't get the `staticMarker`.
       # `pkgsStatic` sets `isStatic=true`, so `pkgsStatic.hostPlatform` always
       # has the `staticMarker`.
-      isStatic = final.isWasm || final.isRedox;
+      isStatic = final.isWasi || final.isRedox;
 
       # Just a guess, based on `system`
       inherit
@@ -337,7 +339,8 @@ let
                     if isList f then f else [ f ]
                 )
               else optional final.isUnix "unix"
-                   ++ optional final.isWindows "windows";
+                   ++ optional final.isWindows "windows"
+                   ++ optional final.isWasm "wasm";
 
             # https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor
             vendor = let
diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix
index 7e50266748434..178536efb0091 100644
--- a/lib/systems/examples.nix
+++ b/lib/systems/examples.nix
@@ -356,6 +356,12 @@ rec {
     useLLVM = true;
   };
 
+  wasm32-unknown-none = {
+    config = "wasm32-unknown-none";
+    rust.rustcTarget = "wasm32-unknown-unknown";
+    useLLVM = true;
+  };
+
   # Ghcjs
   ghcjs = {
     # This triple is special to GHC/Cabal/GHCJS and not recognized by autotools
diff --git a/lib/systems/parse.nix b/lib/systems/parse.nix
index 1d7c95943a794..a2ee288f2c1f8 100644
--- a/lib/systems/parse.nix
+++ b/lib/systems/parse.nix
@@ -466,11 +466,12 @@ rec {
       }
       # cpu-vendor-os
       else if elemAt l 1 == "apple" ||
-              elem (elemAt l 2) [ "wasi" "redox" "mmixware" "ghcjs" "mingw32" ] ||
+              elem (elemAt l 2) [ "redox" "mmixware" "ghcjs" "mingw32" ] ||
               hasPrefix "freebsd" (elemAt l 2) ||
               hasPrefix "netbsd" (elemAt l 2) ||
               hasPrefix "openbsd" (elemAt l 2) ||
-              hasPrefix "genode" (elemAt l 2)
+              hasPrefix "genode" (elemAt l 2) ||
+              hasPrefix "wasm32" (elemAt l 0)
       then {
         cpu    = elemAt l 0;
         vendor = elemAt l 1;
diff --git a/pkgs/build-support/rust/build-rust-crate/build-crate.nix b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
index 7484b3ad0290e..3af13fe70a7de 100644
--- a/pkgs/build-support/rust/build-rust-crate/build-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate/build-crate.nix
@@ -1,5 +1,5 @@
 { lib, stdenv
-, mkRustcDepArgs, mkRustcFeatureArgs, needUnstableCLI
+, mkRustcDepArgs, mkRustcFeatureArgs, needUnstableCLI, rustc
 }:
 
 { crateName,
@@ -27,6 +27,10 @@
       # since rustc 1.42 the "proc_macro" crate is part of the default crate prelude
       # https://github.com/rust-lang/cargo/commit/4d64eb99a4#diff-7f98585dbf9d30aa100c8318e2c77e79R1021-R1022
       ++ lib.optional (lib.elem "proc-macro" crateType) "--extern proc_macro"
+      ++ lib.optional (stdenv.hostPlatform.linker == "lld") # Needed when building for targets that use lld. e.g. 'wasm32-unknown-unknown'
+        "-C linker=${rustc.llvmPackages.lld}/bin/lld"
+      ++ lib.optional (stdenv.hasCC && stdenv.hostPlatform.linker != "lld")
+        "-C linker=${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc"
     ;
     rustcMeta = "-C metadata=${metadata} -C extra-filename=-${metadata}";
 
@@ -39,10 +43,7 @@
       ++ (map (x: "--crate-type ${x}") crateType)
     );
 
-    binRustcOpts = lib.concatStringsSep " " (
-      [ "-C linker=${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc" ] ++
-      baseRustcOpts
-    );
+    binRustcOpts = lib.concatStringsSep " " baseRustcOpts;
 
     build_bin = if buildTests then "build_bin_test" else "build_bin";
   in ''
diff --git a/pkgs/build-support/rust/build-rust-crate/default.nix b/pkgs/build-support/rust/build-rust-crate/default.nix
index dfe28cc334b5e..d6369055cc53b 100644
--- a/pkgs/build-support/rust/build-rust-crate/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/default.nix
@@ -16,6 +16,16 @@
 }:
 
 let
+  # Returns a true if the builder's rustc was built with support for the target.
+  targetAlreadyIncluded = lib.elem stdenv.hostPlatform.rust.rustcTarget
+    (lib.splitString "," (lib.removePrefix "--target=" (
+      lib.elemAt (lib.filter (f: lib.hasPrefix "--target=" f) pkgsBuildBuild.rustc.unwrapped.configureFlags) 0)
+    ));
+
+  # If the build's rustc was built with support for the target then reuse it. (Avoids uneeded compilation for targets like `wasm32-unknown-unknown`)
+  rustc' = if targetAlreadyIncluded then pkgsBuildBuild.rustc else rustc;
+  cargo' = if targetAlreadyIncluded then pkgsBuildBuild.cargo else cargo;
+
   # Create rustc arguments to link against the given list of dependencies
   # and renames.
   #
@@ -77,6 +87,7 @@ let
 
   buildCrate = import ./build-crate.nix {
     inherit lib stdenv mkRustcDepArgs mkRustcFeatureArgs needUnstableCLI;
+    rustc = rustc';
   };
 
   installCrate = import ./install-crate.nix { inherit stdenv; };
@@ -274,7 +285,8 @@ crate_: lib.makeOverridable
       name = "rust_${crate.crateName}-${crate.version}${lib.optionalString buildTests_ "-test"}";
       version = crate.version;
       depsBuildBuild = [ pkgsBuildBuild.stdenv.cc ];
-      nativeBuildInputs = [ rust stdenv.cc cargo jq ]
+      nativeBuildInputs = [ rustc' cargo' jq ]
+        ++ lib.optionals stdenv.hasCC [ stdenv.cc ]
         ++ lib.optionals stdenv.buildPlatform.isDarwin [ libiconv ]
         ++ (crate.nativeBuildInputs or [ ]) ++ nativeBuildInputs_;
       buildInputs = lib.optionals stdenv.isDarwin [ libiconv ] ++ (crate.buildInputs or [ ]) ++ buildInputs_;
@@ -380,7 +392,7 @@ crate_: lib.makeOverridable
     )
   )
 {
-  rust = rustc;
+  rust = rustc';
   release = crate_.release or true;
   verbose = crate_.verbose or true;
   extraRustcOpts = [ ];
diff --git a/pkgs/build-support/rust/build-rust-crate/test/default.nix b/pkgs/build-support/rust/build-rust-crate/test/default.nix
index d020031a92f93..dd135af919654 100644
--- a/pkgs/build-support/rust/build-rust-crate/test/default.nix
+++ b/pkgs/build-support/rust/build-rust-crate/test/default.nix
@@ -8,6 +8,7 @@
 , stdenv
 , symlinkJoin
 , writeTextFile
+, pkgsCross
 }:
 
 let
@@ -120,7 +121,10 @@ let
 
        `name` is used as part of the derivation name that performs the checking.
 
-       `crateArgs` is passed to `mkHostCrate` to build the crate with `buildRustCrate`.
+       `mkCrate` can be used to override the `mkCrate` call/implementation to use to
+       override the `buildRustCrate`, useful for cross compilation. Uses `mkHostCrate` by default.
+
+       `crateArgs` is passed to `mkCrate` to build the crate with `buildRustCrate`
 
        `expectedFiles` contains a list of expected file paths in the output. E.g.
        `[ "./bin/my_binary" ]`.
@@ -129,13 +133,13 @@ let
        output is used but e.g. `output = "lib";` will cause the lib output
        to be checked instead. You do not need to specify any directories.
      */
-    assertOutputs = { name, crateArgs, expectedFiles, output? null }:
+    assertOutputs = { name, mkCrate ? mkHostCrate, crateArgs, expectedFiles, output? null, }:
       assert (builtins.isString name);
       assert (builtins.isAttrs crateArgs);
       assert (builtins.isList expectedFiles);
 
       let
-        crate = mkHostCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
+        crate = mkCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
         crateOutput = if output == null then crate else crate."${output}";
         expectedFilesFile = writeTextFile {
           name = "expected-files-${name}";
@@ -155,7 +159,7 @@ let
       ''
       # sed out the hash because it differs per platform
       + ''
-        | sed -E -e 's/-[0-9a-fA-F]{10}\.rlib/-HASH.rlib/g' \
+        | sed 's/-${crate.metadata}//g' \
         > "$actualFiles"
       diff -q ${expectedFilesFile} "$actualFiles" > /dev/null || {
         echo -e "\033[0;1;31mERROR: Difference in expected output files in ${crateOutput} \033[0m" >&2
@@ -651,7 +655,7 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-HASH.rlib"
+        "./lib/libtest_lib.rlib"
         "./lib/link"
       ];
     };
@@ -668,7 +672,24 @@ let
       };
       expectedFiles = [
         "./nix-support/propagated-build-inputs"
-        "./lib/libtest_lib-HASH.rlib"
+        "./lib/libtest_lib.rlib"
+        "./lib/link"
+      ];
+    };
+
+    crateLibOutputsWasm32 = assertOutputs {
+      name = "wasm32-crate-lib";
+      output = "lib";
+      mkCrate = mkCrate pkgsCross.wasm32-unknown-none.buildRustCrate;
+      crateArgs = {
+        libName = "test_lib";
+        type = [ "cdylib" ];
+        libPath = "src/lib.rs";
+        src = mkLib "src/lib.rs";
+      };
+      expectedFiles = [
+        "./nix-support/propagated-build-inputs"
+        "./lib/test_lib.wasm"
         "./lib/link"
       ];
     };
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index d9ad333fae540..ebe4c42c358cd 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -16443,7 +16443,9 @@ with pkgs;
 
   makeRustPlatform = callPackage ../development/compilers/rust/make-rust-platform.nix { };
 
-  buildRustCrate = callPackage ../build-support/rust/build-rust-crate { };
+  buildRustCrate = callPackage ../build-support/rust/build-rust-crate ({ } // lib.optionalAttrs (stdenv.hostPlatform.libc == null) {
+    stdenv = stdenvNoCC; # Some build targets without libc will fail to evaluate with a normal stdenv.
+  });
   buildRustCrateHelpers = callPackage ../build-support/rust/build-rust-crate/helpers.nix { };
 
   cargo2junit = callPackage ../development/tools/rust/cargo2junit { };