├── .gitignore ├── .gitmodules ├── README.md ├── build-stuff-overlay.nix ├── build-wasm-app.nix ├── common-overlays.nix ├── cross-overlays-haskell.nix ├── cross-overlays-libiconv.nix ├── cross.nix ├── default.nix ├── fib-example ├── CMakeLists.txt ├── default.nix └── fib.c ├── haskell-examples └── default.nix ├── hello-example ├── CMakeLists.txt ├── default.nix └── hello.c ├── hydra.json ├── jobsets.nix ├── jsaddle-wasm ├── default.nix └── github.json ├── libiconv-wasm32.patch ├── musl.nix ├── nixpkgs └── default.nix ├── primitive-0.6.4.patch ├── primitive-0.7.0.patch ├── release.nix ├── webabi ├── default.nix └── github.json └── webghc.nix /.gitignore: -------------------------------------------------------------------------------- 1 | **/result 2 | llvm-mirror/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebGHC/wasm-cross/5f580e6739c82485b017d10b11bc9ec377150ef9/.gitmodules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wasm-cross 2 | 3 | ### `wasm-cross` is a toolchain for cross compiling C and Haskell to WebAssembly, using the `WebGHC` and `LLVM` 4 | 5 | The generated WebAssembly binary can be run on a browser using the [`webabi`](https://github.com/WebGHC/webabi) library. 6 | 7 | It currently provides a minimal ABI, sufficient to run the Haskell code using the `jsaddle` library with [`jsaddle-wasm`](https://github.com/WebGHC/jsaddle-wasm) 8 | 9 | ## Quick start 10 | 11 | #### Setup nix cache 12 | 13 | - If you're using linux, a nix binary cache is available at https://nixcache.webghc.org with a public key of: 14 | 15 | `hydra.webghc.org-1:knW30Yb8EXYxmUZKEl0Vc6t2BDjAUQ5kfC1BKJ9qEG8=` 16 | 17 | - When using reflex-platform you may want to add its cache as well: https://nixcache.reflex-frp.org 18 | 19 | `ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI=` 20 | 21 | ### Build an example app 22 | 23 | ``` 24 | git clone git@github.com:WebGHC/wasm-cross.git 25 | cd wasm-cross; 26 | ``` 27 | 28 | Reflex TodoMVC 29 | ``` 30 | nix-build release.nix -A examples.wasm.reflex-todomvc 31 | ``` 32 | 33 | Miso 2048 34 | 35 | ``` 36 | nix-build release.nix -A examples.wasm._2048 37 | ``` 38 | 39 | ### Nix based build with TemplateHaskell support 40 | 41 | #### Template Haskell 42 | 43 | For Template Haskell support the [save/load-splices infrastructure](https://github.com/WebGHC/ghc/commits/webghc-8.6.5-splices) is used. This was initially created to support the `arm` cross-compilation, but it works equally well for `WebGHC`. 44 | 45 | This works by first compiling the code for `x86/64` arch, and then using the splices generated by it in the `wasm` compilation. 46 | It needs the `reflex-platform`'s nix wizardry to achieve this. 47 | It works well for the straightforward use cases of Template Haskell, but may break for more complicated uses. 48 | 49 | Note: use of `reflex` is not required to use `reflex-platform`, it should work well for `Miso` too. 50 | 51 | In order to support `TemplateHaskell` the `reflex-platform` and nix based build is necessary. 52 | 53 | See the [example JSaddle app](https://github.com/WebGHC/example-jsaddle-project) 54 | and the [example Reflex app](https://github.com/WebGHC/example-reflex-project) 55 | 56 | ### Cabal based build without TemplateHaskell support 57 | 58 | If you dont need TemplateHaskell support, then you can use only `cabal` to do the builds, which works much faster as it can do builds incrementally. 59 | 60 | The `reflex-platform` is used here as it provides an easier to use interface for creating a nix-shell with all the dependencies necessary for a cabal project. 61 | 62 | Get the latest `reflex-platform` from https://github.com/reflex-frp/reflex-platform/ 63 | 64 | - For a JSaddle app, add the `jsaddle-wasm` in your executable's cabal file, and put the `-threaded` option in `if !arch(wasm32)` block. 65 | 66 | > Note: `reflex-dom` library from v0.7 onwards already includes `jsaddle-wasm` dependency, so it is not necessary to modify anything. 67 | 68 | > TODO: add instructions for `miso` and `reflex-dom` < 0.7 69 | 70 | - Use the `work-on` script from reflex-platform to obtain a shell with `WebGHC` 71 | 72 | ``` sh 73 | /scripts/work-on wasm ./. 74 | ``` 75 | 76 | Then do the `cabal configure` with following options, followed by `cabal build` 77 | 78 | ``` sh 79 | cabal configure --configure-option=--host=wasm32-unknown-unknown-wasm --with-ghc=wasm32-unknown-unknown-wasm-ghc --with-ghc-pkg=wasm32-unknown-unknown-wasm-ghc-pkg --with-gcc=wasm32-unknown-unknown-wasm-cc --with-ld=wasm32-unknown-unknown-wasm-ld --with-ar=wasm32-unknown-unknown-wasm-ar --with-hsc2hs=wasm32-unknown-unknown-wasm-hsc2hs 80 | cabal build 81 | ``` 82 | 83 | #### Limitations / Known issues 84 | 85 | - The `-threaded` option is not supported with `WebGHC`. 86 | You will have to put to modify the cabal file to exclude this option like this: 87 | 88 | ``` 89 | if !arch(wasm32) 90 | ghc-options: -threaded 91 | ``` 92 | 93 | - The `-Werror` option is known to cause compilation failure as it converts the `clang` warnings to errors. 94 | This is a temporary issue, as it should be possible to get rid of `clang` warnings altogether. 95 | 96 | ### Other details 97 | 98 | The C toolchain is made up of Clang / LLVM, LLD, and [a fork of musl](https://github.com/WebGHC/musl). 99 | 100 | The Haskell compilation is done using WebGHC, which is a fork of GHC 101 | 102 | GHC cross compilers are built from [a fork](https://github.com/WebGHC/ghc) using the Nix infrastructure largely developed by John Ericson (@Ericson2314), producing a working `haskellPackages`. 103 | 104 | [`webabi`](https://github.com/WebGHC/webabi) is the "kernel" to support `musl`'s syscalls. 105 | 106 | 107 | 108 | ### Notes 109 | 110 | - We have [forked `nixpkgs`](https://github.com/WebGHC/nixpkgs) just to support the `wasm32-unknown-unknown-wasm` compilation target, as this support cannot be provided by overlays. 111 | All other changes needed to nixpkgs, which cannot be done by overlays, have already been upstreamed. 112 | 113 | The choice of target triple is still under debate, with `wasm32-unknown-unknown` or `wasm32-unknown-unknown-webghc` being other candidates. 114 | 115 | - The `wasm-cross` contains some code for `nodejs` support, but unfortunately it has not been maintained. If there is interest in running the executables outside the browser environment, then this could be resurrected with a little effort. 116 | -------------------------------------------------------------------------------- /build-stuff-overlay.nix: -------------------------------------------------------------------------------- 1 | self: super: { 2 | 3 | webabi = self.callPackage ./webabi {}; 4 | 5 | webghc-runner = self.writeShellScriptBin "webghc-runner" '' 6 | exec ${self.nodejs-8_x}/bin/node ${self.webabi}/lib/node_modules/webabi/build/node_runner.js "$@" 7 | ''; 8 | 9 | build-wasm-app = self.callPackage ./build-wasm-app.nix {}; 10 | } 11 | -------------------------------------------------------------------------------- /build-wasm-app.nix: -------------------------------------------------------------------------------- 1 | { lib, runCommand, lndir, binaryen, wabt, webabi, gzip 2 | }: 3 | 4 | let 5 | indexHtml = { ename, scripts, styles }: builtins.toFile "index.html" '' 6 | 7 | 8 | 9 | 10 | ${lib.concatMapStrings (s: "") styles} 11 | 12 | 13 | 14 | ${lib.concatMapStrings (s: "") scripts} 15 | 16 | 17 | 18 | 19 | 20 | 21 | ''; 22 | 23 | indexHtmlWorker = { ename, scripts, styles }: builtins.toFile "index.html" '' 24 | 25 | 26 | 27 | 28 | ${lib.concatMapStrings (s: "") styles} 29 | 30 | 31 | 32 | 33 | ${lib.concatMapStrings (s: "") scripts} 34 | 41 | 42 | 43 | ''; 44 | 45 | # On certain apps like reflex-todomvc, doing wasm-strip first and then wasm-opt gives 46 | # smaller size files. 47 | in { ename, pkg, assets ? [], scripts ? [], styles ? [] }: runCommand "wasm-app-${ename}" { 48 | nativeBuildInputs = [ lndir binaryen wabt ]; 49 | passthru = { inherit pkg; }; 50 | } '' 51 | if [ ! -f "${pkg}/bin/${ename}" ]; then 52 | echo "The pkg: ${pkg} does not have the executable named ${ename}" 53 | exit 1 54 | fi 55 | mkdir -p $out 56 | lndir ${webabi}/lib/node_modules/webabi/build $out 57 | lndir ${webabi}/lib/node_modules/webabi/jsaddleJS $out 58 | ln -s ${pkg}/bin/${ename} $out/ 59 | ${lib.concatMapStringsSep "\n" (a: "ln -s ${a} $out/") assets} 60 | ln -s ${indexHtml { inherit ename scripts styles; }} $out/index.html 61 | cp ${pkg}/bin/${ename} $out/${ename}-tmp 62 | chmod u+w $out/${ename}-tmp 63 | wasm-strip $out/${ename}-tmp 64 | wasm-opt -Oz $out/${ename}-tmp -o $out/${ename}-opt 65 | rm $out/${ename}-tmp 66 | gzip -c $out/${ename}-opt > $out/${ename}-opt.gz 67 | '' 68 | -------------------------------------------------------------------------------- /common-overlays.nix: -------------------------------------------------------------------------------- 1 | { build-wasm-app }: 2 | self: super: { 3 | inherit build-wasm-app; 4 | fib-example = self.callPackage ./fib-example {}; 5 | 6 | hello-example = self.callPackage ./hello-example {}; 7 | 8 | haskell-example = self.build-wasm-app { ename = "hello"; pkg = self.haskell.packages.ghcWasm.hello; }; 9 | 10 | # Issue happens when combining pkgsStatic & custom cross stdenv. 11 | # We need to force a normal busybox here to avoid hitting a 12 | # weird bootstrapping issue. 13 | busybox-sandbox-shell = super.busybox-sandbox-shell.override { busybox = self.busybox; }; 14 | } 15 | -------------------------------------------------------------------------------- /cross-overlays-haskell.nix: -------------------------------------------------------------------------------- 1 | ghcSrc: ghcVersion: haskellProfiling: 2 | self: super: { 3 | haskell = 4 | let inherit (super) haskell; 5 | ghcPkgName = "ghc" + super.lib.strings.stringAsChars (x: if x == "." then "" else x) ghcVersion; 6 | in haskell // { 7 | packages = haskell.packages // { 8 | ghcWasm = haskell.packages.${ghcPkgName}.override (drv: { 9 | ghc = (self.buildPackages.haskell.compiler.ghcHEAD.override { 10 | enableShared = false; 11 | enableRelocatedStaticLibs = false; 12 | enableIntegerSimple = true; 13 | enableTerminfo = false; 14 | # Options for newer nixpkgs 15 | # enableDwarf = false; 16 | # libffi = null; 17 | version = ghcVersion; 18 | useLLVM = true; 19 | buildLlvmPackages = self.buildPackages.llvmPackages_8; 20 | llvmPackages = self.buildPackages.llvmPackages_8; 21 | }).overrideAttrs (drv: { 22 | nativeBuildInputs = drv.nativeBuildInputs or [] ++ [self.buildPackages.autoreconfHook self.buildPackages.buildPackages.git]; 23 | src = ghcSrc; 24 | # Use this to test nix-build on your local GHC checkout. 25 | # src = self.lib.cleanSource ./ghc; 26 | hardeningDisable = drv.hardeningDisable or [] 27 | ++ ["stackprotector" "pic"]; 28 | dontDisableStatic = true; 29 | NIX_NO_SELF_RPATH=1; 30 | patches = self.lib.filter (p: p.name != "loadpluginsinmodules.diff") (drv.patches or []); 31 | }); 32 | overrides = self.lib.composeExtensions (drv.overrides or (_:_:{})) (hsSelf: hsSuper: { 33 | primitive = self.haskell.lib.appendPatch hsSuper.primitive (if ghcVersion == "8.6.5" then ./primitive-0.6.4.patch else ./primitive-0.7.0.patch); 34 | mkDerivation = args: hsSuper.mkDerivation (args // { 35 | dontStrip = true; 36 | enableSharedExecutables = false; 37 | enableSharedLibraries = false; 38 | enableDeadCodeElimination = false; 39 | doHaddock = false; 40 | doCheck = false; 41 | enableLibraryProfiling = haskellProfiling; 42 | }); 43 | }); 44 | }); 45 | }; 46 | }; 47 | } -------------------------------------------------------------------------------- /cross-overlays-libiconv.nix: -------------------------------------------------------------------------------- 1 | (self: super: { 2 | libiconvReal = super.libiconvReal.overrideDerivation (attrs: {patches = [./libiconv-wasm32.patch];}); 3 | libiconv = self.libiconvReal; # By default, this wants to pull stuff out of glibc or something 4 | }) -------------------------------------------------------------------------------- /cross.nix: -------------------------------------------------------------------------------- 1 | nixpkgs: postOverlays : 2 | 3 | { lib 4 | , localSystem, crossSystem, config, overlays, crossOverlays ? [] 5 | } @ args: 6 | 7 | assert crossSystem != null; 8 | 9 | let 10 | bootStages = import "${nixpkgs.path}/pkgs/stdenv" { 11 | inherit lib localSystem overlays; 12 | 13 | crossSystem = localSystem; 14 | crossOverlays = []; 15 | 16 | # Ignore custom stdenvs when cross compiling for compatability 17 | config = builtins.removeAttrs config [ "replaceStdenv" ]; 18 | }; 19 | 20 | in bootStages ++ [ 21 | 22 | # Build Packages 23 | (vanillaPackages: { 24 | inherit config overlays; 25 | selfBuild = false; 26 | stdenv = 27 | assert vanillaPackages.stdenv.buildPlatform == localSystem; 28 | assert vanillaPackages.stdenv.hostPlatform == localSystem; 29 | assert vanillaPackages.stdenv.targetPlatform == localSystem; 30 | vanillaPackages.stdenv.override { targetPlatform = crossSystem; }; 31 | }) 32 | 33 | # Run Packages 34 | (toolPackages: let 35 | prefix = "${crossSystem.config}-"; 36 | llvmPackages = toolPackages.llvmPackages_8; 37 | ldFlags = 38 | if crossSystem.isWasm 39 | then "--allow-undefined-file=${musl-cross}/lib/wasm.syms" 40 | else null; 41 | mkClang = { libc ? null, ccFlags ? null, ldFlags ? null }: toolPackages.wrapCCWith { 42 | name = "clang-cross-wrapper"; 43 | cc = llvmPackages.clang-unwrapped; 44 | bintools = toolPackages.wrapBintoolsWith { 45 | bintools = llvmPackages.bintools; 46 | inherit libc; 47 | }; 48 | inherit libc; 49 | extraBuildCommands = '' 50 | # We don't yet support C++ 51 | # https://github.com/WebGHC/wasm-cross/issues/1 52 | echo "-target ${crossSystem.config} -nostdlib++" >> $out/nix-support/cc-cflags 53 | '' + toolPackages.lib.optionalString (ccFlags != null) '' 54 | echo "${ccFlags}" >> $out/nix-support/cc-cflags 55 | '' + toolPackages.lib.optionalString (ldFlags != null) '' 56 | echo "${ldFlags}" >> $out/nix-support/cc-ldflags 57 | '' + toolPackages.lib.optionalString (libc != null) '' 58 | echo "--sysroot ${libc}" >> $out/nix-support/cc-cflags 59 | '' + toolPackages.lib.optionalString (crossSystem ? fpu) '' 60 | echo "-mfpu=${crossSystem.fpu}" >> $out/nix-support/cc-cflags 61 | '' + toolPackages.lib.optionalString (crossSystem ? target-cpu) '' 62 | echo "-mcpu=${crossSystem.target-cpu}" >> $out/nix-support/cc-cflags 63 | '' + toolPackages.lib.optionalString (crossSystem ? thread-model) '' 64 | echo "-mthread-model ${crossSystem.thread-model}" >> $out/nix-support/cc-cflags 65 | ''; 66 | }; 67 | mkStdenv = cc: let x = toolPackages.stdenv.override (old: { 68 | buildPlatform = localSystem; 69 | hostPlatform = crossSystem; 70 | targetPlatform = crossSystem; 71 | inherit cc; 72 | allowedRequisites = null; 73 | }); in x // { 74 | mkDerivation = args: x.mkDerivation (args // { 75 | hardeningDisable = args.hardeningDisable or [] 76 | ++ [ 77 | "stackprotector" 78 | 79 | # These two cause arguments to be placed before the 80 | # -flavor argument, but -flavor must be first. Since we 81 | # statically link everything, these don't matter anyway. 82 | "relro" 83 | "bindnow" 84 | ] ++ toolPackages.lib.optional crossSystem.isWasm "pic"; 85 | dontDisableStatic = true; 86 | NIX_NO_SELF_RPATH=1; 87 | dontStrip = true; 88 | } // toolPackages.lib.optionalAttrs (!crossSystem.isWasm) { 89 | configureFlags = 90 | (let flags = args.configureFlags or []; 91 | in if builtins.isString flags then [flags] else flags) 92 | ++ toolPackages.lib.optionals (!(args.dontConfigureStatic or false)) ["--enable-static" "--disable-shared"]; 93 | }); 94 | isStatic = true; 95 | }; 96 | 97 | clangCross-noLibc = mkClang { 98 | ccFlags = "-nostdinc -nodefaultlibs"; 99 | }; 100 | clangCross-noCompilerRt = mkClang { 101 | libc = musl-cross; 102 | ccFlags = "-nodefaultlibs -lc"; 103 | inherit ldFlags; 104 | }; 105 | clangCross = mkClang { 106 | ccFlags = "-rtlib=compiler-rt -resource-dir ${compiler-rt}"; 107 | inherit ldFlags; 108 | libc = musl-cross; 109 | }; 110 | 111 | stdenv-noLibc = mkStdenv clangCross-noLibc; 112 | stdenv-noCompilerRt = mkStdenv clangCross-noCompilerRt; 113 | 114 | musl-cross = toolPackages.callPackage ./musl.nix { 115 | hostPlatform = crossSystem; 116 | stdenv = stdenv-noLibc; 117 | }; 118 | compiler-rt = toolPackages.llvmPackages_8.compiler-rt.override { 119 | # baremetal = true; 120 | # hostPlatform = crossSystem; 121 | stdenv = stdenv-noCompilerRt; 122 | }; 123 | in { 124 | inherit config; 125 | overlays = overlays ++ crossOverlays ++ [ 126 | (self: super: { 127 | inherit compiler-rt musl-cross clangCross-noLibc clangCross-noCompilerRt clangCross; 128 | }) 129 | ] ++ postOverlays; 130 | selfBuild = false; 131 | stdenv = mkStdenv clangCross; 132 | }) 133 | 134 | ] 135 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgsFunc ? import ./nixpkgs 2 | , haskellProfiling ? false 3 | , overlays ? [] 4 | }: 5 | 6 | let 7 | webghc = import ./webghc.nix { inherit ((nixpkgsFunc {}).buildPackages) fetchgit; }; 8 | 9 | in (nixpkgsFunc {}).lib.makeExtensible (project: { 10 | nixpkgsArgs = { 11 | overlays = overlays; 12 | # XXX This is required just to build some haskell packages with ghcjs. (ie to build release.nix completely) 13 | config = { allowBroken = true; }; 14 | }; 15 | 16 | nixpkgsCrossArgs = ghcSrc: ghcVersion: { 17 | stdenvStages = import ./cross.nix (nixpkgsFunc {}) 18 | [ (import ./cross-overlays-libiconv.nix) 19 | (import ./cross-overlays-haskell.nix ghcSrc ghcVersion haskellProfiling) 20 | ]; 21 | crossSystem = { 22 | config = "wasm32-unknown-unknown-wasm"; 23 | arch = "wasm32"; 24 | libc = null; 25 | useLLVM = true; 26 | disableDynamicLinker = true; 27 | thread-model = "single"; 28 | # target-cpu = "bleeding-edge"; 29 | }; 30 | }; 31 | 32 | nixpkgs = nixpkgsFunc project.nixpkgsArgs; 33 | nixpkgsWasm = nixpkgsFunc (project.nixpkgsArgs // 34 | project.nixpkgsCrossArgs webghc.ghc881Src "8.8.1"); 35 | nixpkgsWasm865 = nixpkgsFunc (project.nixpkgsArgs // 36 | project.nixpkgsCrossArgs webghc.ghc865Src "8.6.5"); 37 | }) 38 | -------------------------------------------------------------------------------- /fib-example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (FIB_EXAMPLE) 2 | add_executable (fib fib.c) 3 | install (TARGETS fib DESTINATION bin) 4 | -------------------------------------------------------------------------------- /fib-example/default.nix: -------------------------------------------------------------------------------- 1 | { build-wasm-app, stdenv, cmake }: 2 | 3 | build-wasm-app { ename = "fib"; pkg = stdenv.mkDerivation { 4 | name = "fib-example"; 5 | src = ./.; 6 | nativeBuildInputs = [ cmake ]; 7 | }; } 8 | -------------------------------------------------------------------------------- /fib-example/fib.c: -------------------------------------------------------------------------------- 1 | int fib(int n) { 2 | if (n == 0 || n == 1) { 3 | return n; 4 | } else { 5 | return fib(n - 1) + fib(n - 2); 6 | } 7 | } 8 | 9 | int main(int argc, char **argv) { 10 | return fib(10); 11 | } 12 | -------------------------------------------------------------------------------- /haskell-examples/default.nix: -------------------------------------------------------------------------------- 1 | pkgs: pkgsSuper: 2 | 3 | let 4 | jsaddle-src = pkgs.fetchgit { 5 | url = https://github.com/ghcjs/jsaddle; 6 | rev = "4b135448f425edf968d5058b901b57064c9d2b7a"; 7 | sha256 = "0xpsv1pp1a13vq5vk1wjj1iq0cfnq9cv7lkrv2rl6yd47slwmn2a"; 8 | }; 9 | reflex-examples-src = pkgs.fetchgit { 10 | url = https://github.com/dfordivam/reflex-examples; 11 | rev = "5cb9bed97f9441bd925117b9d743574cab66f017"; 12 | sha256 = "1s9kksj61v8zfv7vkg420mi8kqg2q68w6qg62930amfbf9cjbb72"; 13 | }; 14 | miso-src = pkgs.fetchgit { 15 | url = https://github.com/WebGHC/miso; 16 | rev = "6f4dac08fd57cf18d4869a8b7014e286654dd650"; 17 | sha256 = "0gqf9hzvmk9lzmfcpf9bzb637c1767p0z9p86k2zn8a1p0gs8a9j"; 18 | fetchSubmodules = true; 19 | }; 20 | dependent-sum-src = pkgs.fetchgit { 21 | url = https://github.com/WebGHC/dependent-sum; 22 | rev = "5158a7dc5e714ca82e94c76ceec838ad85b0efab"; 23 | sha256 = "0k9z63snfdz5rl6lndy2nclk4wpqv60mkbjs8l4jy42ammk8554r"; 24 | }; 25 | jsaddle-stress-tests-src = pkgs.fetchgit { 26 | url = https://github.com/dfordivam/jsaddle-stress-tests; 27 | rev = "6b4b13c302e17f62c6c7e858bc4f17161901299d"; 28 | sha256 = "1y3xxd4fb24qqq6bi32ypk3m9lx6m8npc2rdav5b7w32ra1rbjn4"; 29 | }; 30 | 31 | haskellLib = pkgs.haskell.lib; 32 | inherit (pkgs) lib; 33 | extensions = isWasm: lib.composeExtensions 34 | (haskellLib.packageSourceOverrides { 35 | jsaddle = jsaddle-src + /jsaddle; 36 | jsaddle-dom = pkgs.fetchgit { 37 | url = https://github.com/ghcjs/jsaddle-dom; 38 | rev = "da15a025eb06888cabf2e463b4f87ce14f65742b"; 39 | sha256 = "0rdwn3g2yy247am714xz3rid98d8j7ccjq8hhsp3mpvpf2w5ipmj"; 40 | }; 41 | jsaddle-warp = jsaddle-src + /jsaddle-warp; 42 | jsaddle-wasm = pkgs.fetchFromGitHub ( 43 | let json = builtins.fromJSON (builtins.readFile ../jsaddle-wasm/github.json); 44 | in { inherit (json) owner repo rev sha256; 45 | private = json.private or false; 46 | } 47 | ); 48 | 49 | Keyboard = reflex-examples-src + /Keyboard; 50 | draganddrop = reflex-examples-src + /drag-and-drop; 51 | fileinput = reflex-examples-src + /fileinput; 52 | nasapod = reflex-examples-src + /nasa-pod; 53 | othello = reflex-examples-src + /othello; 54 | 55 | bench-wasm = jsaddle-stress-tests-src + /bench-wasm; 56 | miso = miso-src; 57 | 58 | dependent-sum = dependent-sum-src + /dependent-sum; 59 | dependent-sum-template = dependent-sum-src + /dependent-sum-template; 60 | dependent-map = pkgs.fetchgit { 61 | url = https://github.com/WebGHC/dependent-map; 62 | rev = "c28ef5350b3c03c4ff92e669703e4eb67e61ffa5"; 63 | sha256 = "1a1ha24bsm15pywd51d50gax6ssydhvjr1fcz53vb7i2xpr7iv3f"; 64 | }; 65 | monoidal-containers = "0.6"; 66 | lens = "4.18.1"; 67 | witherable = "0.3.4"; 68 | prim-uniq = pkgs.fetchgit { 69 | url = https://github.com/WebGHC/prim-uniq; 70 | rev = "34570a948f7d84a1821ed6d8305ed094c4f6eb15"; 71 | sha256 = "15xm0ky6dgndn714m99vgxyd4cr782gn0rf8zyf7v8mnj7mhcrc0"; 72 | }; 73 | }) 74 | (self: super: 75 | let 76 | reflex-dom-pkg = import (pkgs.fetchgit { 77 | url = https://github.com/dfordivam/reflex-dom; 78 | rev = "6bdc206bd83d2db62eb7d98372c9bf4fd355e7da"; 79 | sha256 = "0wa8pzmmyqk31d0rvhwg2hzmrj3rji655lag253l8xdhlc6561sw"; 80 | }) self; 81 | in { 82 | mkDerivation = args: super.mkDerivation (args // { doCheck = false; }); 83 | ref-tf = haskellLib.doJailbreak super.ref-tf; 84 | 85 | reflex = self.callPackage (pkgs.fetchgit { 86 | url = https://github.com/dfordivam/reflex; 87 | rev = "369b9db9fc50c612123b433848b8423711847462"; 88 | sha256 = "0jbizndl408n5df65fx5haxc60y2vph4wpiznkqr0a92f6ijf94r"; 89 | }) { useTemplateHaskell = false; }; 90 | reflex-dom-core = haskellLib.dontCheck 91 | (haskellLib.appendConfigureFlag 92 | (reflex-dom-pkg.reflex-dom-core) 93 | "-f-use-template-haskell") ; 94 | reflex-dom = haskellLib.disableCabalFlag reflex-dom-pkg.reflex-dom "webkit2gtk"; 95 | reflex-todomvc = self.callPackage (pkgs.fetchgit { 96 | url = https://github.com/reflex-frp/reflex-todomvc; 97 | rev = "91227b8baa90a6d1e51c803eff7f966dbafe875a"; 98 | sha256 = "0sbpkzxv96z2a11k3nzjw6ik4998si64vspkhii7i00rv0yxc33k"; 99 | }) {}; 100 | 101 | miso = with haskellLib; 102 | let 103 | deps = [self.file-embed self.aeson-pretty] ++ [(if isWasm then self.jsaddle-wasm else self.jsaddle-warp)]; 104 | patches = miso-src + /submodules.patch; 105 | flags = ["-fexamples"] ++ lib.optional isWasm "-fjsaddle-wasm"; 106 | in addBuildDepends (appendPatch (appendConfigureFlags super.miso flags) patches) deps; 107 | 108 | constraints-extras = haskellLib.disableCabalFlag super.constraints-extras "build-readme"; 109 | 110 | # the reflex-dom cabal2nix doesn't get deps correctly, so specify thse 111 | chrome-test-utils = null; 112 | jsaddle-webkit2gtk = null; 113 | 114 | # Stop building servant docs, it needs cython which fails to compile 115 | servant = haskellLib.overrideCabal super.servant (old: { 116 | postInstall = ""; 117 | }); 118 | }); 119 | wasmHaskellPackages = pkgs.haskell.packages.ghcWasm.extend (extensions true); 120 | ghcjsHaskellPackages = pkgs.haskell.packages.ghcjs86.extend (extensions false); 121 | 122 | reflexExamples = { 123 | keyboard.pname = "Keyboard"; 124 | draganddrop.pname = "draganddrop"; 125 | draganddrop.assets = ["${reflex-examples-src}/drag-and-drop/arduino.jpg"]; 126 | reflex-todomvc.pname = "reflex-todomvc"; 127 | nasapod.pname = "nasapod"; 128 | othello.pname = "othello"; 129 | fileinput.pname = "fileinput"; 130 | # Some tests to benchmark wasm code 131 | bench-wasm.pname = "bench-wasm"; 132 | }; 133 | misoExamples = { 134 | _2048.pname = "miso"; 135 | _2048.ename = "2048"; 136 | _2048.assets = [(pkgs.runCommand "2048-css" {nativeBuildInputs=[pkgs.buildPackages.sass];} "mkdir -p $out && sass ${miso-src}/examples/2048/static/main.scss $out/main.css" + /main.css)]; 137 | _2048.styles = ["main.css"]; 138 | flatris.pname = "miso"; 139 | mario.pname = "miso"; 140 | mario.assets = ["${miso-src}/examples/mario/imgs"]; 141 | simple.pname = "miso"; 142 | todo-mvc.pname = "miso"; 143 | }; 144 | examples = reflexExamples // lib.mapAttrs (n: e: e // { 145 | assets = e.assets or [] ++ ["${miso-src}/jsbits"]; 146 | scripts = e.scripts or [] ++ ["jsbits/delegate.js" "jsbits/diff.js" "jsbits/isomorphic.js" "jsbits/util.js"]; 147 | }) misoExamples; 148 | 149 | toWasm = name: { pname, assets ? [], ename ? name, scripts ? [], styles ? [] }: 150 | let pkg = wasmHaskellPackages.${pname}; 151 | in pkgs.build-wasm-app { inherit ename pkg assets scripts styles; }; 152 | 153 | ghcjsIndexHtml = styles: builtins.toFile "index.html" '' 154 | 155 | 156 | 157 | ${lib.concatMapStrings (s: "") styles} 158 | 159 | 160 | 161 | 162 | 163 | ''; 164 | 165 | toGhcjs = name: { pname, assets ? [], ename ? name, scripts ? [], styles ? [] }: 166 | let pkg = ghcjsHaskellPackages.${pname}; 167 | in pkgs.runCommand "ghcjs-app-${ename}" { nativeBuildInputs = [pkgs.xorg.lndir pkgs.closurecompiler pkgs.gzip]; } '' 168 | mkdir -p $out 169 | lndir ${pkg}/bin/${ename}.jsexe $out 170 | ln -s ${lib.concatStringsSep " " assets} $out/ 171 | ln -fs ${ghcjsIndexHtml styles} $out/index.html 172 | closure-compiler $out/all.js ${lib.optionalString (pname != "miso") "--compilation_level=ADVANCED_OPTIMIZATIONS --jscomp_off=checkVars --externs=$out/all.js.externs"} | tee $out/all.adv.min.js | gzip > $out/all.adv.min.js.gz 173 | ''; 174 | 175 | in { 176 | inherit wasmHaskellPackages; 177 | examples.wasm = pkgs.recurseIntoAttrs (lib.mapAttrs toWasm examples); 178 | examples.ghcjs = pkgs.recurseIntoAttrs (lib.mapAttrs toGhcjs examples); 179 | } 180 | -------------------------------------------------------------------------------- /hello-example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project (HELLO) 2 | add_executable (hello hello.c) 3 | install (TARGETS hello DESTINATION bin) 4 | -------------------------------------------------------------------------------- /hello-example/default.nix: -------------------------------------------------------------------------------- 1 | { build-wasm-app, stdenv, cmake }: 2 | 3 | build-wasm-app { ename = "hello"; pkg = stdenv.mkDerivation { 4 | name = "hello-example"; 5 | src = ./.; 6 | nativeBuildInputs = [ cmake ]; 7 | }; } 8 | -------------------------------------------------------------------------------- /hello-example/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv) { 6 | printf("Hello, World!\n"); 7 | sleep(2); 8 | volatile int *x; 9 | for (int i = 0; i < 100; ++i) { 10 | x = (int *) malloc(9 * sizeof(int)); 11 | printf("%d\n", x[0]); 12 | } 13 | printf("Hello, World2!\n"); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /hydra.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": 1, 3 | "hidden": true, 4 | "description": "Jobsets", 5 | "nixexprinput": "src", 6 | "nixexprpath": "jobsets.nix", 7 | "checkinterval": 300, 8 | "schedulingshares": 100, 9 | "enableemail": false, 10 | "emailoverride": "", 11 | "keepnr": 10, 12 | "inputs": { 13 | "src": { 14 | "type": "git", 15 | "value": "https://github.com/WebGHC/wasm-cross.git master", 16 | "emailresponsible": false 17 | }, 18 | "wasm-cross-prs": { 19 | "type": "githubpulls", 20 | "value": "WebGHC wasm-cross", 21 | "emailresponsible": false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /jobsets.nix: -------------------------------------------------------------------------------- 1 | { wasm-cross-prs }: 2 | 3 | let 4 | pkgs = import ./nixpkgs {}; 5 | mkFetchGithub = value: { 6 | inherit value; 7 | type = "git"; 8 | emailresponsible = false; 9 | }; 10 | in 11 | with pkgs.lib; 12 | let 13 | defaults = jobs: { 14 | inherit (jobs) description; 15 | enabled = 1; 16 | hidden = false; 17 | keepnr = 10; 18 | schedulingshares = 100; 19 | checkinterval = 120; 20 | enableemail = false; 21 | emailoverride = ""; 22 | nixexprinput = "wasm-cross"; 23 | nixexprpath = "release.nix"; 24 | inputs = jobs.inputs; 25 | }; 26 | branchJobset = branch: defaults { 27 | description = "wasm-cross-${branch}"; 28 | inputs = { 29 | wasm-cross = { 30 | value = "https://github.com/WebGHC/wasm-cross.git ${branch}"; 31 | type = "git"; 32 | emailresponsible = false; 33 | }; 34 | }; 35 | }; 36 | makePr = num: info: { 37 | name = "wasm-cross-pr-${num}"; 38 | value = defaults { 39 | description = "#${num}: ${info.title}"; 40 | inputs = { 41 | wasm-cross = { 42 | value = "https://github.com/${info.head.repo.owner.login}/${info.head.repo.name}.git ${info.head.ref}"; 43 | type = "git"; 44 | emailresponsible = false; 45 | }; 46 | }; 47 | }; 48 | }; 49 | prs = mapAttrs' makePr (builtins.fromJSON (builtins.readFile wasm-cross-prs)); 50 | jobsetsAttrs = prs // genAttrs ["master"] branchJobset; 51 | in { 52 | jobsets = pkgs.writeText "spec.json" (builtins.toJSON jobsetsAttrs); 53 | } 54 | -------------------------------------------------------------------------------- /jsaddle-wasm/default.nix: -------------------------------------------------------------------------------- 1 | # DO NOT HAND-EDIT THIS FILE 2 | import ((import {}).fetchFromGitHub ( 3 | let json = builtins.fromJSON (builtins.readFile ./github.json); 4 | in { inherit (json) owner repo rev sha256; 5 | private = json.private or false; 6 | } 7 | )) 8 | -------------------------------------------------------------------------------- /jsaddle-wasm/github.json: -------------------------------------------------------------------------------- 1 | { 2 | "owner": "WebGHC", 3 | "repo": "jsaddle-wasm", 4 | "branch": "export-apis", 5 | "rev": "54c66ac302942ff3d420f400d66a19b88044a964", 6 | "sha256": "0qbwzpgzrswbmjzfdk4zhkh6q1fwpkw9qbcpgjqqcacs9ymyspni" 7 | } 8 | -------------------------------------------------------------------------------- /libiconv-wasm32.patch: -------------------------------------------------------------------------------- 1 | diff -ruN libiconv-1.16/build-aux/config.sub libiconv-1.16-patched/build-aux/config.sub 2 | --- libiconv-1.16/build-aux/config.sub 2019-04-27 03:29:05.000000000 +0900 3 | +++ libiconv-1.16-patched/build-aux/config.sub 2019-11-23 21:36:56.794790501 +0900 4 | @@ -135,7 +135,7 @@ 5 | | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ 6 | | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ 7 | | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ 8 | - | storm-chaos* | os2-emx* | rtmk-nova*) 9 | + | storm-chaos* | os2-emx* | rtmk-nova* | unknown-wasm) 10 | basic_machine=$field1 11 | os=$maybe_os 12 | ;; 13 | @@ -1511,6 +1511,8 @@ 14 | ;; 15 | ios) 16 | ;; 17 | + unknown-wasm) 18 | + ;; 19 | none) 20 | ;; 21 | *-eabi) 22 | diff -ruN libiconv-1.16/lib/loop_wchar.h libiconv-1.16-patched/lib/loop_wchar.h 23 | --- libiconv-1.16/lib/loop_wchar.h 2018-09-18 01:06:14.000000000 +0900 24 | +++ libiconv-1.16-patched/lib/loop_wchar.h 2019-11-23 21:40:43.599165612 +0900 25 | @@ -36,7 +36,9 @@ 26 | # include 27 | # define BUF_SIZE 64 /* assume MB_LEN_MAX <= 64 */ 28 | /* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */ 29 | +#ifndef __wasm__ 30 | extern size_t mbrtowc (); 31 | +#endif 32 | # ifdef mbstate_t 33 | # define mbrtowc(pwc, s, n, ps) (mbrtowc)(pwc, s, n, 0) 34 | # define mbsinit(ps) 1 35 | diff -ruN libiconv-1.16/libcharset/build-aux/config.sub libiconv-1.16-patched/libcharset/build-aux/config.sub 36 | --- libiconv-1.16/libcharset/build-aux/config.sub 2019-04-27 03:29:05.000000000 +0900 37 | +++ libiconv-1.16-patched/libcharset/build-aux/config.sub 2019-11-23 21:39:26.892696874 +0900 38 | @@ -135,7 +135,7 @@ 39 | | linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \ 40 | | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ 41 | | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ 42 | - | storm-chaos* | os2-emx* | rtmk-nova*) 43 | + | storm-chaos* | os2-emx* | rtmk-nova* | unknown-wasm) 44 | basic_machine=$field1 45 | os=$maybe_os 46 | ;; 47 | @@ -1511,6 +1511,8 @@ 48 | ;; 49 | ios) 50 | ;; 51 | + unknown-wasm) 52 | + ;; 53 | none) 54 | ;; 55 | *-eabi) 56 | -------------------------------------------------------------------------------- /musl.nix: -------------------------------------------------------------------------------- 1 | { stdenv, lib, buildPackages, fetchFromGitHub, hostPlatform, buildPlatform }: 2 | 3 | stdenv.mkDerivation ({ 4 | name = "musl"; 5 | 6 | src = fetchFromGitHub { 7 | owner = "WebGHC"; 8 | repo = "musl"; 9 | rev = "6133d9643afeb7ad1ba195d648fa81518bc60cdc"; 10 | sha256 = "1mnbk32nrgy6dqwiy2qi4ypn61yx3fjxr50dp9i0izhw3y5bq6n9"; 11 | }; 12 | 13 | postInstall = '' 14 | for f in crtbegin crtend crtbeginS crtendS; do 15 | touch $f.c 16 | $CC -c -o $out/lib/$f.o $f.c 17 | done 18 | ''; 19 | 20 | enableParallelBuilding = true; 21 | } // lib.optionalAttrs (hostPlatform != buildPlatform) { 22 | CROSS_COMPILE = "${hostPlatform.config}-"; 23 | }) 24 | -------------------------------------------------------------------------------- /nixpkgs/default.nix: -------------------------------------------------------------------------------- 1 | import (builtins.fetchTarball { 2 | url = https://github.com/WebGHC/nixpkgs/archive/1ab030ae80d1383fba4850668ea899daf226adf6.tar.gz; 3 | sha256 = "1nvpxj6x78il35aj68111rfy5rxx77fz7ykg90ql7qnjf9h0fsym"; 4 | }) 5 | -------------------------------------------------------------------------------- /primitive-0.6.4.patch: -------------------------------------------------------------------------------- 1 | diff -Naur primitive-0.6.4.0/Data/Primitive/Internal/Operations.hs primitive-0.6.4.0-patched/Data/Primitive/Internal/Operations.hs 2 | --- primitive-0.6.4.0/Data/Primitive/Internal/Operations.hs 2018-05-30 14:38:36.000000000 -0400 3 | +++ primitive-0.6.4.0-patched/Data/Primitive/Internal/Operations.hs 2018-07-22 17:16:32.176601099 -0400 4 | @@ -1,4 +1,4 @@ 5 | -{-# LANGUAGE MagicHash, UnliftedFFITypes #-} 6 | +{-# LANGUAGE MagicHash, UnliftedFFITypes, CApiFFI #-} 7 | 8 | -- | 9 | -- Module : Data.Primitive.Internal.Operations 10 | @@ -30,61 +30,61 @@ 11 | import Foreign.C.Types 12 | import GHC.Prim 13 | 14 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 15 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 16 | setWord8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 17 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 18 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 19 | setWord16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 20 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 21 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 22 | setWord32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 23 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 24 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 25 | setWord64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word64_# -> IO () 26 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 27 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 28 | setWordArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 29 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 30 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 31 | setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 32 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 33 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 34 | setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 35 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 36 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 37 | setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 38 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 39 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 40 | setInt64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int64_# -> IO () 41 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 42 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 43 | setIntArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 44 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 45 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 46 | setAddrArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Addr# -> IO () 47 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float" 48 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Float" 49 | setFloatArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Float# -> IO () 50 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double" 51 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Double" 52 | setDoubleArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Double# -> IO () 53 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char" 54 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Char" 55 | setWideCharArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Char# -> IO () 56 | 57 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 58 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 59 | setWord8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 60 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 61 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 62 | setWord16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 63 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 64 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 65 | setWord32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 66 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 67 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 68 | setWord64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word64_# -> IO () 69 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 70 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 71 | setWordOffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 72 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 73 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 74 | setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 75 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 76 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 77 | setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 78 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 79 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 80 | setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 81 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 82 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 83 | setInt64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int64_# -> IO () 84 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 85 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 86 | setIntOffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 87 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 88 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 89 | setAddrOffAddr# :: Addr# -> CPtrdiff -> CSize -> Addr# -> IO () 90 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float" 91 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Float" 92 | setFloatOffAddr# :: Addr# -> CPtrdiff -> CSize -> Float# -> IO () 93 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double" 94 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Double" 95 | setDoubleOffAddr# :: Addr# -> CPtrdiff -> CSize -> Double# -> IO () 96 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char" 97 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Char" 98 | setWideCharOffAddr# :: Addr# -> CPtrdiff -> CSize -> Char# -> IO () 99 | 100 | -------------------------------------------------------------------------------- /primitive-0.7.0.patch: -------------------------------------------------------------------------------- 1 | diff -Naur primitive-0.7.0.0/Data/Primitive/Internal/Operations.hs primitive-0.7.0.0-patched/Data/Primitive/Internal/Operations.hs 2 | --- primitive-0.7.0.0/Data/Primitive/Internal/Operations.hs 2018-05-30 14:38:36.000000000 -0400 3 | +++ primitive-0.7.0.0-patched/Data/Primitive/Internal/Operations.hs 2018-07-22 17:16:32.176601099 -0400 4 | @@ -1,4 +1,4 @@ 5 | -{-# LANGUAGE MagicHash, UnliftedFFITypes #-} 6 | +{-# LANGUAGE MagicHash, UnliftedFFITypes, CApiFFI #-} 7 | 8 | -- | 9 | -- Module : Data.Primitive.Internal.Operations 10 | @@ -30,65 +30,65 @@ 11 | import Foreign.C.Types 12 | import GHC.Exts 13 | 14 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 15 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 16 | setWord8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 17 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 18 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 19 | setWord16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 20 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 21 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 22 | setWord32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 23 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 24 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 25 | setWord64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word64_# -> IO () 26 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 27 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 28 | setWordArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () 29 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 30 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 31 | setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 32 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 33 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 34 | setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 35 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 36 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 37 | setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 38 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 39 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 40 | setInt64Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int64_# -> IO () 41 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 42 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 43 | setIntArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () 44 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 45 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 46 | setAddrArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Addr# -> IO () 47 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 48 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 49 | setStablePtrArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> StablePtr# a -> IO () 50 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float" 51 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Float" 52 | setFloatArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Float# -> IO () 53 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double" 54 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Double" 55 | setDoubleArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Double# -> IO () 56 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char" 57 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Char" 58 | setWideCharArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Char# -> IO () 59 | 60 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 61 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 62 | setWord8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 63 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 64 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 65 | setWord16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 66 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 67 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 68 | setWord32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 69 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 70 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 71 | setWord64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word64_# -> IO () 72 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 73 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 74 | setWordOffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () 75 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" 76 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word8" 77 | setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 78 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" 79 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word16" 80 | setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 81 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" 82 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word32" 83 | setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 84 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" 85 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word64" 86 | setInt64OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int64_# -> IO () 87 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" 88 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Word" 89 | setIntOffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () 90 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 91 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 92 | setAddrOffAddr# :: Addr# -> CPtrdiff -> CSize -> Addr# -> IO () 93 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Ptr" 94 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Ptr" 95 | setStablePtrOffAddr# :: Addr# -> CPtrdiff -> CSize -> StablePtr# a -> IO () 96 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Float" 97 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Float" 98 | setFloatOffAddr# :: Addr# -> CPtrdiff -> CSize -> Float# -> IO () 99 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Double" 100 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Double" 101 | setDoubleOffAddr# :: Addr# -> CPtrdiff -> CSize -> Double# -> IO () 102 | -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Char" 103 | +foreign import capi unsafe "primitive-memops.h hsprimitive_memset_Char" 104 | setWideCharOffAddr# :: Addr# -> CPtrdiff -> CSize -> Char# -> IO () 105 | 106 | -------------------------------------------------------------------------------- /release.nix: -------------------------------------------------------------------------------- 1 | {}: 2 | 3 | let 4 | nixpkgsBuildStuff = (import ./. { overlays = [ (import ./build-stuff-overlay.nix) ]; }).nixpkgs; 5 | inherit (nixpkgsBuildStuff) build-wasm-app webabi; 6 | in with import ./. { 7 | overlays = [ 8 | (import ./common-overlays.nix { inherit build-wasm-app; }) 9 | (import ./haskell-examples) 10 | ]; 11 | }; 12 | 13 | let 14 | inherit (nixpkgs) lib; 15 | fromPkgs = pkgs: { 16 | inherit (pkgs.stdenv) cc; 17 | inherit (pkgs) musl-cross; 18 | fib-example = pkgs.fib-example.pkg; 19 | hello-example = pkgs.hello-example.pkg; 20 | inherit (pkgs.haskell.packages.integer-simple.ghc881) hello ghc; 21 | }; 22 | in { 23 | inherit (nixpkgs.llvmPackages_8) llvm clang clang-unwrapped compiler-rt 24 | lld bintools; 25 | inherit (nixpkgs) binaryen cmake wabt; 26 | inherit (nixpkgsWasm) wasmHaskellPackages; 27 | inherit webabi; 28 | 29 | wasm = nixpkgs.recurseIntoAttrs (fromPkgs nixpkgsWasm // { 30 | inherit (nixpkgsWasm.haskell.packages.ghcWasm) hello ghc; 31 | fib-example-web = nixpkgsWasm.fib-example; 32 | hello-example-web = nixpkgsWasm.hello-example; 33 | haskell-example-web = nixpkgsWasm.haskell-example; 34 | primitive = nixpkgsWasm.haskell.packages.ghcWasm.primitive; 35 | }); 36 | 37 | wasm865 = nixpkgs.recurseIntoAttrs (fromPkgs nixpkgsWasm865 // { 38 | inherit (nixpkgsWasm865.haskell.packages.ghcWasm) hello ghc; 39 | fib-example-web = nixpkgsWasm865.fib-example; 40 | hello-example-web = nixpkgsWasm865.hello-example; 41 | haskell-example-web = nixpkgsWasm865.haskell-example; 42 | primitive = nixpkgsWasm865.haskell.packages.ghcWasm.primitive; 43 | }); 44 | 45 | # TODO: fix compilation of examples with ghc 865 46 | examples = nixpkgs.recurseIntoAttrs { 47 | inherit (nixpkgsWasm.examples) wasm; 48 | inherit (nixpkgs.examples) ghcjs; 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /webabi/default.nix: -------------------------------------------------------------------------------- 1 | # DO NOT HAND-EDIT THIS FILE 2 | let fetch = { private ? false, fetchSubmodules ? false, owner, repo, rev, sha256, ... }: 3 | if !fetchSubmodules && !private then builtins.fetchTarball { 4 | url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"; inherit sha256; 5 | } else (import {}).fetchFromGitHub { 6 | inherit owner repo rev sha256 fetchSubmodules private; 7 | }; 8 | in import (fetch (builtins.fromJSON (builtins.readFile ./github.json))) 9 | -------------------------------------------------------------------------------- /webabi/github.json: -------------------------------------------------------------------------------- 1 | { 2 | "owner": "WebGHC", 3 | "repo": "webabi", 4 | "branch": "split-worker-and-main-thread-code", 5 | "private": false, 6 | "rev": "5aee539cfd29982f9fd2680ad9df0c741375796c", 7 | "sha256": "1bcka8g0xljgcrj5ga8vi47n0nnnvk3m2k0y99hqa7knk7jzzdw4" 8 | } 9 | -------------------------------------------------------------------------------- /webghc.nix: -------------------------------------------------------------------------------- 1 | { fetchgit }: 2 | { 3 | ghc881Src = fetchgit { 4 | url = "https://github.com/WebGHC/ghc.git"; 5 | rev = "daebc38ffb78c21904eb3b508790f43291fe2e87"; 6 | sha256 = "1dwlxpna0bp0gnj0lrzwcdpzjvcyg1j55r1dajpxpxhf71i74iqg"; 7 | fetchSubmodules = true; 8 | }; 9 | 10 | ghc865Src = fetchgit { 11 | url = "https://github.com/WebGHC/ghc.git"; 12 | rev = "9f0543186dc8a423d5dbe48502b19282816e024f"; 13 | sha256 = "0qpvaaccqd14dpq66b16vmaakily0chyk87hcalh63iym02qdspw"; 14 | fetchSubmodules = true; 15 | }; 16 | 17 | ghc865SplicesSrc = fetchgit { 18 | url = "https://github.com/WebGHC/ghc.git"; 19 | rev = "1d4026e91ec844ccbe23dacc26a399e250b8fd11"; 20 | sha256 = "061rnv15yqg83y8cx85294jl29bmvd2cb9h7zfz4bihr79m0ln0n"; 21 | fetchSubmodules = true; 22 | }; 23 | } 24 | --------------------------------------------------------------------------------