diff --git a/pkgs/development/compilers/emscripten/default.nix b/pkgs/development/compilers/emscripten/default.nix index be74615823038..7575ee833c2a2 100644 --- a/pkgs/development/compilers/emscripten/default.nix +++ b/pkgs/development/compilers/emscripten/default.nix @@ -123,7 +123,12 @@ stdenv.mkDerivation rec { # HACK: Make emscripten look more like a cc-wrapper to GHC # when building the javascript backend. targetPrefix = "em"; - bintools = emscripten; + bintools = emscripten.overrideAttrs (old: { + passthru = old.passthru // { + # emscripten wraps LLVM bintools, GHC checks for this fact + isLLVM = true; + }; + }); }; meta = with lib; { diff --git a/pkgs/development/compilers/ghc/common-hadrian.nix b/pkgs/development/compilers/ghc/common-hadrian.nix index b90a4934fdbad..eaac895cb628b 100644 --- a/pkgs/development/compilers/ghc/common-hadrian.nix +++ b/pkgs/development/compilers/ghc/common-hadrian.nix @@ -10,6 +10,7 @@ { lib , stdenv +, pkgsBuildBuild , pkgsBuildTarget , pkgsHostTarget , targetPackages @@ -36,11 +37,15 @@ , # GHC can be built with system libffi or a bundled one. libffi ? null +, # TODO(@sternenseemann): this is ugly as hell + libffiAttr ? "libffi" + , useLLVM ? !(stdenv.targetPlatform.isx86 || stdenv.targetPlatform.isPower || stdenv.targetPlatform.isSparc || (stdenv.targetPlatform.isAarch64 && stdenv.targetPlatform.isDarwin) - || stdenv.targetPlatform.isGhcjs) + || stdenv.targetPlatform.isGhcjs + || stdenv.targetPlatform.isWasm) , # LLVM is conceptually a run-time-only dependency, but for # non-x86, we need LLVM to bootstrap later stages, so it becomes a # build-time dependency too. @@ -52,6 +57,7 @@ enableNativeBignum ? !(lib.meta.availableOn stdenv.hostPlatform gmp && lib.meta.availableOn stdenv.targetPlatform gmp) || stdenv.targetPlatform.isGhcjs + || stdenv.targetPlatform.isWasm , gmp , # If enabled, use -fPIC when compiling static libs. @@ -62,11 +68,12 @@ , # Whether to build dynamic libs for the standard library (on the target # platform). Static libs are always built. - enableShared ? with stdenv.targetPlatform; !isWindows && !useiOSPrebuilt && !isStatic && !isGhcjs + enableShared ? with stdenv.targetPlatform; !isWindows && !useiOSPrebuilt && !isStatic && !isGhcjs && !isWasm , # Whether to build terminfo. enableTerminfo ? !(stdenv.targetPlatform.isWindows - || stdenv.targetPlatform.isGhcjs) + || stdenv.targetPlatform.isGhcjs + || stdenv.targetPlatform.isWasm) , # Libdw.c only supports x86_64, i686 and s390x as of 2022-08-04 enableDwarf ? (stdenv.targetPlatform.isx86 || @@ -203,7 +210,7 @@ let # https://gitlab.haskell.org/ghc/ghc/-/issues/22081 ++ lib.optional enableDwarf elfutils ++ lib.optional (!enableNativeBignum) gmp - ++ lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows && !targetPlatform.isGhcjs) libiconv; + ++ lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows && !targetPlatform.isGhcjs && !targetPlatform.isWasm) libiconv; # TODO(@sternenseemann): is buildTarget LLVM unnecessary? # GHC doesn't seem to have {LLC,OPT}_HOST @@ -226,9 +233,11 @@ let then targetCC.bintools else targetCC.bintools.bintools; # Same goes for strip. + # Additionally, if we are using LLVM bintools, they will be always wrapped. strip = # TODO(@sternenseemann): also use wrapper if linker == "bfd" or "gold" - if stdenv.targetPlatform.isAarch64 && stdenv.targetPlatform.isDarwin + if (stdenv.targetPlatform.isAarch64 && stdenv.targetPlatform.isDarwin) + || targetCC.bintools.isLLVM then targetCC.bintools else targetCC.bintools.bintools; }; @@ -287,6 +296,10 @@ stdenv.mkDerivation ({ export RANLIB="${targetCC.bintools.bintools}/bin/${targetCC.bintools.targetPrefix}ranlib" export READELF="${targetCC.bintools.bintools}/bin/${targetCC.bintools.targetPrefix}readelf" export STRIP="${bintoolsFor.strip}/bin/${bintoolsFor.strip.targetPrefix}strip" + # CC_FOR_BUILD etc. become CC_STAGE0 + export CC_STAGE0="$CC_FOR_BUILD" + export AR_STAGE0="$AR_FOR_BUILD" + export LD_STAGE0="$LD_FOR_BUILD" '' + lib.optionalString (stdenv.targetPlatform.linker == "cctools") '' export OTOOL="${targetCC.bintools.bintools}/bin/${targetCC.bintools.targetPrefix}otool" export INSTALL_NAME_TOOL="${bintoolsFor.install_name_tool}/bin/${bintoolsFor.install_name_tool.targetPrefix}install_name_tool" @@ -365,8 +378,8 @@ stdenv.mkDerivation ({ "--with-curses-includes=${ncurses.dev}/include" "--with-curses-libraries=${ncurses.out}/lib" ] ++ lib.optionals (libffi != null && !targetPlatform.isGhcjs) [ "--with-system-libffi" - "--with-ffi-includes=${targetPackages.libffi.dev}/include" - "--with-ffi-libraries=${targetPackages.libffi.out}/lib" + "--with-ffi-includes=${targetPackages.${libffiAttr}.dev}/include" + "--with-ffi-libraries=${targetPackages.${libffiAttr}.out}/lib" ] ++ lib.optionals (targetPlatform == hostPlatform && !enableNativeBignum) [ "--with-gmp-includes=${targetPackages.gmp.dev}/include" "--with-gmp-libraries=${targetPackages.gmp.out}/lib" @@ -408,6 +421,10 @@ stdenv.mkDerivation ({ # For building runtime libs depsBuildTarget = toolsForTarget; + depsBuildBuild = [ + pkgsBuildBuild.targetPackages.stdenv.cc + ]; + buildInputs = [ perl bash ] ++ (libDeps hostPlatform); depsTargetTarget = map lib.getDev (libDeps targetPlatform); diff --git a/pkgs/development/compilers/llvm/16/libcxx/default.nix b/pkgs/development/compilers/llvm/16/libcxx/default.nix index 94374c8a312df..de1a9aabf5c2b 100644 --- a/pkgs/development/compilers/llvm/16/libcxx/default.nix +++ b/pkgs/development/compilers/llvm/16/libcxx/default.nix @@ -41,8 +41,10 @@ stdenv.mkDerivation rec { outputs = [ "out" ] ++ lib.optional (!headersOnly) "dev"; prePatch = '' - cd ../${basename} + cd ../ chmod -R u+w . + cd ${basename} + patch -d ../llvm -p1 -i "${../libcxxabi/wasm.patch}" ''; patches = [ @@ -77,7 +79,7 @@ stdenv.mkDerivation rec { ++ lib.optional (stdenv.hostPlatform.isMusl || stdenv.hostPlatform.isWasi) "-DLIBCXX_HAS_MUSL_LIBC=1" ++ lib.optional (stdenv.hostPlatform.useLLVM or false) "-DLIBCXX_USE_COMPILER_RT=ON" ++ lib.optionals stdenv.hostPlatform.isWasm [ - "-DLIBCXX_ENABLE_THREADS=OFF" + "-DLIBCXX_ENABLE_THREADS=${if stdenv.cc.libc.hasThreads then "ON" else "OFF"}" "-DLIBCXX_ENABLE_FILESYSTEM=OFF" "-DLIBCXX_ENABLE_EXCEPTIONS=OFF" ] ++ lib.optional (!enableShared) "-DLIBCXX_ENABLE_SHARED=OFF" diff --git a/pkgs/development/compilers/llvm/16/libcxxabi/default.nix b/pkgs/development/compilers/llvm/16/libcxxabi/default.nix index cb5fa44f07009..a0e3c805f899e 100644 --- a/pkgs/development/compilers/llvm/16/libcxxabi/default.nix +++ b/pkgs/development/compilers/llvm/16/libcxxabi/default.nix @@ -28,13 +28,13 @@ stdenv.mkDerivation rec { postUnpack = lib.optionalString stdenv.isDarwin '' export TRIPLE=x86_64-apple-darwin - '' + lib.optionalString stdenv.hostPlatform.isWasm '' - patch -p1 -d llvm -i ${./wasm.patch} ''; prePatch = '' - cd ../${pname} + cd ../ chmod -R u+w . + cd ${pname} + patch -p1 -d ../llvm -i ${./wasm.patch} ''; patches = [ @@ -65,13 +65,30 @@ stdenv.mkDerivation rec { # CMake however checks for this anyways; this flag tells it not to. See: # https://github.com/llvm/llvm-project/blob/4bd3f3759259548e159aeba5c76efb9a0864e6fa/llvm/runtimes/CMakeLists.txt#L243 "-DCMAKE_CXX_COMPILER_WORKS=ON" + "-DCMAKE_C_COMPILER_WORKS=ON" ] ++ lib.optionals (stdenv.hostPlatform.useLLVM or false) [ "-DLLVM_ENABLE_LIBCXX=ON" "-DLIBCXXABI_USE_LLVM_UNWINDER=ON" - ] ++ lib.optionals stdenv.hostPlatform.isWasm [ - "-DLIBCXXABI_ENABLE_THREADS=OFF" - "-DLIBCXXABI_ENABLE_EXCEPTIONS=OFF" - ] ++ lib.optionals (!enableShared) [ + ] ++ lib.optionals stdenv.hostPlatform.isWasm ( + [ + "-DLIBCXXABI_ENABLE_EXCEPTIONS=OFF" + # CMake tests for -fno-exceptions together with -lc++ -lc++abi which fails + # here, without -fno-exceptions, libc++abi is unusable later. + # See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=260005 + # TODO(@sternenseemann): make this unconditional? + "-DCXX_SUPPORTS_FNO_EXCEPTIONS_FLAG=ON" + ] + ++ (if stdenv.cc.libc.hasThreads then [ + "-DLIBCXXABI_ENABLE_THREADS=ON" + "-DLIBCXXABI_HAS_PTHREAD_API=ON" + "-DLIBCXXABI_HAS_EXTERNAL_THREAD_API=OFF" + "-DLIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY=OFF" + "-DLIBCXXABI_HAS_WIN32_THREAD_API=OFF" + ] else [ + "-DLIBCXXABI_ENABLE_THREADS=OFF" + ]) + ) + ++ lib.optionals (!enableShared) [ "-DLIBCXXABI_ENABLE_SHARED=OFF" ]; diff --git a/pkgs/development/haskell-modules/non-hackage-packages.nix b/pkgs/development/haskell-modules/non-hackage-packages.nix index beb81a58d8638..e805546bb3f5d 100644 --- a/pkgs/development/haskell-modules/non-hackage-packages.nix +++ b/pkgs/development/haskell-modules/non-hackage-packages.nix @@ -38,4 +38,7 @@ self: super: { # Unofficial fork until PRs are merged https://github.com/pcapriotti/optparse-applicative/pulls/roberth # cabal2nix --maintainer roberth https://github.com/hercules-ci/optparse-applicative.git > pkgs/development/misc/haskell/hercules-ci-optparse-applicative.nix hercules-ci-optparse-applicative = self.callPackage ../misc/haskell/hercules-ci-optparse-applicative.nix {}; + + # Codegen tool used by GHC for wasm FFI support + libffi-wasm = self.callPackage ../libraries/libffi-wasm-ghc/codegen.nix { }; } diff --git a/pkgs/development/libraries/libffi-wasm-ghc/codegen.nix b/pkgs/development/libraries/libffi-wasm-ghc/codegen.nix new file mode 100644 index 0000000000000..3147cda8c475f --- /dev/null +++ b/pkgs/development/libraries/libffi-wasm-ghc/codegen.nix @@ -0,0 +1,32 @@ +{ mkDerivation +, fetchFromGitLab +, base +, bytestring +, language-c +, lib +, pretty +, tasty +, unliftio +}: +mkDerivation { + pname = "libffi-wasm"; + version = "unstable-2022-11-10"; + src = fetchFromGitLab { + domain = "gitlab.haskell.org"; + owner = "ghc"; + repo = "libffi-wasm"; + rev = "4914da7d7b8b68abf575a47bf88f64b8e1c47ca7"; + sha256 = "0x06bp1mr977g7w4pinp010rfipg3r4l0h92dc9jplbw2lxswhnm"; + }; + isLibrary = false; + isExecutable = true; + libraryHaskellDepends = [ base bytestring language-c pretty ]; + executableHaskellDepends = [ base bytestring unliftio ]; + testHaskellDepends = [ base tasty ]; + doHaddock = false; + doCheck = true; + license = lib.licenses.bsd3; + maintainers = [ lib.maintainers.sternenseemann ]; + mainProgram = "libffi-wasm"; + homepage = "https://gitlab.haskell.org/ghc/libffi-wasm/"; +} diff --git a/pkgs/development/libraries/libffi-wasm-ghc/default.nix b/pkgs/development/libraries/libffi-wasm-ghc/default.nix new file mode 100644 index 0000000000000..b237d35e8d312 --- /dev/null +++ b/pkgs/development/libraries/libffi-wasm-ghc/default.nix @@ -0,0 +1,62 @@ +{ lib +, stdenv +, buildPackages +}: + +let + # Codegen tool written by GHC upstream to generate the source for their port of + # libffi for wasm + libffi-wasm = buildPackages.haskellPackages.libffi-wasm; +in + +stdenv.mkDerivation (finalAttrs: { + inherit (libffi-wasm) pname version src; + + nativeBuildInputs = [ + libffi-wasm + ]; + + dontConfigure = true; + + CFLAGS = [ + "-Wall" + "-Wextra" + "-DNDEBUG" + "-O3" + "-Icbits" + ]; + + # Based on https://gitlab.haskell.org/ghc/libffi-wasm/-/blob/master/.gitlab-ci.yml + buildPhase = '' + runHook preBuild + + set -x + + libffi-wasm + + for f in cbits/ffi cbits/ffi_call cbits/ffi_closure; do + $CC $CFLAGS -c "$f.c" -o "$f.o" + done + + $AR -rc libffi.a cbits/*.o + + set +x + + runHook postBuild + ''; + + outputs = [ "out" "dev" ]; + installPhase = '' + runHook preInstall + + install -Dm644 -t "$dev/include" cbits/*.h + install -Dm755 -t "$out/lib" libffi.a + + runHook postInstall + ''; + + meta = { + inherit (libffi-wasm.meta) maintainers license homepage; + platforms = lib.platforms.wasi; + }; +}) diff --git a/pkgs/development/libraries/wasilibc/default.nix b/pkgs/development/libraries/wasilibc/default.nix index 0dce309ef5c7c..3ac8c7dc5f754 100644 --- a/pkgs/development/libraries/wasilibc/default.nix +++ b/pkgs/development/libraries/wasilibc/default.nix @@ -2,13 +2,18 @@ , buildPackages , fetchFromGitHub , lib +# Enable experimental wasilibc pthread support +, enableThreads ? false +# For tests , firefox-unwrapped , firefox-esr-unwrapped +, pkgsCross +, wasmtime }: let pname = "wasilibc"; - version = "19"; + version = "20"; in stdenv.mkDerivation { inherit pname version; @@ -17,7 +22,7 @@ stdenv.mkDerivation { owner = "WebAssembly"; repo = "wasi-libc"; rev = "refs/tags/wasi-sdk-${version}"; - hash = "sha256-yQSKoSil/C/1lIHwEO9eQKC/ye3PJIFGYjHyNDn61y4="; + sha256 = "0knm5ch499dksmv1k0kh7356pjd9n1gjn0p3vp9bw57mn478zp8z"; fetchSubmodules = true; }; @@ -38,8 +43,7 @@ stdenv.mkDerivation { "SYSROOT_LIB:=$SYSROOT_LIB" "SYSROOT_INC:=$SYSROOT_INC" "SYSROOT_SHARE:=$SYSROOT_SHARE" - # https://bugzilla.mozilla.org/show_bug.cgi?id=1773200 - "BULK_MEMORY_SOURCES:=" + "THREAD_MODEL=${if enableThreads then "posix" else "single"}" ) ''; @@ -53,8 +57,46 @@ stdenv.mkDerivation { ln -s $share/share/undefined-symbols.txt $out/lib/wasi.imports ''; - passthru.tests = { - inherit firefox-unwrapped firefox-esr-unwrapped; + passthru = { + tests = { + inherit firefox-unwrapped firefox-esr-unwrapped; + simple-c-cxx-binaries = pkgsCross.wasi32.runCommandCC "simple-c-cxx-binaries" { + nativeBuildInputs = [ + wasmtime + ]; + } '' + cat > test.c < + int main(void) { + puts("Hello from C"); + return 0; + } + EOF + cat > test.cpp < + int main(void) { + std::cout<<"Hello from C++\n"; + return 0; + } + EOF + + mkdir -p "$out/bin" + # TODO(@sternenseemann): compile with -pthread if enableThreads + $CC -o "$out/bin/test-c" test.c + $CXX -o "$out/bin/test-cxx" test.cpp -lc++ -lc++abi + + export HOME=$TMPDIR + export WASMTIME_FLAGS=(${ + lib.escapeShellArgs (lib.optionals enableThreads [ + "--wasm-features=threads" + "--wasi-modules=experimental-wasi-threads" + ]) + }) + wasmtime run "''${WASMTIME_FLAGS[@]}" "$out/bin/test-c" + wasmtime run "''${WASMTIME_FLAGS[@]}" "$out/bin/test-cxx" + ''; + }; + hasThreads = enableThreads; }; meta = with lib; { diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index cb773146d539f..f9e69a0b361aa 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -15740,8 +15740,8 @@ with pkgs; haskell = callPackage ./haskell-packages.nix { }; haskellPackages = dontRecurseIntoAttrs - # JS backend is only available for GHC >= 9.6 - (if stdenv.hostPlatform.isGhcjs + # JS and wasm backends are only available for GHC >= 9.6 + (if stdenv.hostPlatform.isGhcjs || stdenv.hostPlatform.isWasm then haskell.packages.native-bignum.ghc96 # Prefer native-bignum to avoid linking issues with gmp else if stdenv.hostPlatform.isStatic @@ -16125,7 +16125,7 @@ with pkgs; else if platform.isFreeBSD then 12 else if platform.isAndroid then 12 else if platform.isLinux then 11 - else if platform.isWasm then 12 + else if platform.isWasm then 16 else 14; # We take the "max of the mins". Why? Since those are lower bounds of the # supported version set, this is like intersecting those sets and then @@ -22328,6 +22328,8 @@ with pkgs; doCheck = false; }; + libffi-wasm-ghc = callPackage ../development/libraries/libffi-wasm-ghc { }; + libfreeaptx = callPackage ../development/libraries/libfreeaptx { }; libfreefare = callPackage ../development/libraries/libfreefare { diff --git a/pkgs/top-level/haskell-packages.nix b/pkgs/top-level/haskell-packages.nix index 42867afef83d8..1f94b80b1c9fe 100644 --- a/pkgs/top-level/haskell-packages.nix +++ b/pkgs/top-level/haskell-packages.nix @@ -347,7 +347,7 @@ in { llvmPackages = pkgs.llvmPackages_12; }; ghc94 = compiler.ghc945; - ghc962 = callPackage ../development/compilers/ghc/9.6.2.nix { + ghc962 = callPackage ../development/compilers/ghc/9.6.2.nix ({ bootPkgs = # For GHC 9.2 no armv7l bindists are available. if stdenv.hostPlatform.isAarch32 then @@ -366,9 +366,13 @@ in { # Support range >= 11 && < 16 buildTargetLlvmPackages = pkgsBuildTarget.llvmPackages_15; llvmPackages = pkgs.llvmPackages_15; - }; + } // pkgs.lib.optionalAttrs stdenv.targetPlatform.isWasm { + # Use GHC/tweag's custom libffi for wasm + libffi = pkgs.targetPackages.libffi-wasm-ghc; + libffiAttr = "libffi-wasm-ghc"; + }); ghc96 = compiler.ghc962; - ghcHEAD = callPackage ../development/compilers/ghc/head.nix { + ghcHEAD = callPackage ../development/compilers/ghc/head.nix ({ bootPkgs = # For GHC 9.2 no armv7l bindists are available. if stdenv.hostPlatform.isAarch32 then @@ -384,10 +388,14 @@ in { # https://github.com/xattr/xattr/issues/44 and # https://github.com/xattr/xattr/issues/55 are solved. inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook; - # 2023-01-15: Support range >= 10 && < 15 - buildTargetLlvmPackages = pkgsBuildTarget.llvmPackages_14; - llvmPackages = pkgs.llvmPackages_14; - }; + # 2023-07-04: Support range >= 10 && < 16 + buildTargetLlvmPackages = pkgsBuildTarget.llvmPackages_15; + llvmPackages = pkgs.llvmPackages_15; + } // pkgs.lib.optionalAttrs stdenv.targetPlatform.isWasm { + # Use GHC/tweag's custom libffi for wasm + libffi = pkgs.targetPackages.libffi-wasm-ghc; + libffiAttr = "libffi-wasm-ghc"; + }); ghcjs = compiler.ghcjs810; ghcjs810 = callPackage ../development/compilers/ghcjs/8.10 { diff --git a/pkgs/top-level/release-cross.nix b/pkgs/top-level/release-cross.nix index 3c6feba6b812f..cd04d31d3e992 100644 --- a/pkgs/top-level/release-cross.nix +++ b/pkgs/top-level/release-cross.nix @@ -75,6 +75,8 @@ let boehmgc = nativePlatforms; hello = nativePlatforms; zlib = nativePlatforms; + haskellPackages.hello = nativePlatforms; + haskell.packages.ghcHEAD.hello = nativePlatforms; }; darwinCommon = { diff --git a/pkgs/top-level/release-haskell.nix b/pkgs/top-level/release-haskell.nix index 6113dcdb121d3..63ff0973445da 100644 --- a/pkgs/top-level/release-haskell.nix +++ b/pkgs/top-level/release-haskell.nix @@ -471,6 +471,22 @@ let ; }; }; + + pkgsCross.wasi32 = { + haskellPackages = { + inherit (packagePlatforms pkgs.pkgsCross.wasi32.haskellPackages) + ghc + hello + ; + }; + + haskell.packages.ghcHEAD = { + inherit (packagePlatforms pkgs.pkgsCross.wasi32.haskell.packages.ghcHEAD) + ghc + hello + ; + }; + }; }) (versionedCompilerJobs { # Packages which should be checked on more than the