Merge pull request #319153 from Kranzes/buildRustCrate-wasm

buildRustCrate: add support for compiling to wasm32-unknown-unknown
This commit is contained in:
Florian Klink 2024-06-30 14:05:33 +03:00 committed by GitHub
commit 641b2f29b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 78 additions and 32 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 ''

View File

@ -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 = [ ];

View File

@ -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"
];
};

View File

@ -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 { };