1# User's Guide to Emscripten in Nixpkgs 2 3[Emscripten](https://github.com/kripken/emscripten): An LLVM-to-JavaScript Compiler 4 5This section of the manual covers how to use `emscripten` in nixpkgs. 6 7Minimal requirements: 8 9* nix 10* nixpkgs 11 12Modes of use of `emscripten`: 13 14* **Imperative usage** (on the command line): 15 16 If you want to work with `emcc`, `emconfigure` and `emmake` as you are used to from Ubuntu and similar distributions you can use these commands: 17 18 * `nix-env -i emscripten` 19 * `nix-shell -p emscripten` 20 21* **Declarative usage**: 22 23 This mode is far more power full since this makes use of `nix` for dependency management of emscripten libraries and targets by using the `mkDerivation` which is implemented by `pkgs.emscriptenStdenv` and `pkgs.buildEmscriptenPackage`. The source for the packages is in `pkgs/top-level/emscripten-packages.nix` and the abstraction behind it in `pkgs/development/em-modules/generic/default.nix`. 24 * build and install all packages: 25 * `nix-env -iA emscriptenPackages` 26 27 * dev-shell for zlib implementation hacking: 28 * `nix-shell -A emscriptenPackages.zlib` 29 30 31## Imperative usage 32 33A few things to note: 34 35* `export EMCC_DEBUG=2` is nice for debugging 36* `~/.emscripten`, the build artifact cache sometimes creates issues and needs to be removed from time to time 37 38 39## Declarative usage 40 41Let's see two different examples from `pkgs/top-level/emscripten-packages.nix`: 42 43* `pkgs.zlib.override` 44* `pkgs.buildEmscriptenPackage` 45 46Both are interesting concepts. 47 48A special requirement of the `pkgs.buildEmscriptenPackage` is the `doCheck = true` is a default meaning that each emscriptenPackage requires a `checkPhase` implemented. 49 50* Use `export EMCC_DEBUG=2` from within a emscriptenPackage's `phase` to get more detailed debug output what is going wrong. 51* ~/.emscripten cache is requiring us to set `HOME=$TMPDIR` in individual phases. This makes compilation slower but also makes it more deterministic. 52 53### Usage 1: pkgs.zlib.override 54 55This example uses `zlib` from nixpkgs but instead of compiling **C** to **ELF** it compiles **C** to **JS** since we were using `pkgs.zlib.override` and changed stdenv to `pkgs.emscriptenStdenv`. A few adaptions and hacks were set in place to make it working. One advantage is that when `pkgs.zlib` is updated, it will automatically update this package as well. However, this can also be the downside... 56 57See the `zlib` example: 58 59 zlib = (pkgs.zlib.override { 60 stdenv = pkgs.emscriptenStdenv; 61 }).overrideDerivation 62 (old: rec { 63 buildInputs = old.buildInputs ++ [ pkgconfig ]; 64 # we need to reset this setting! 65 NIX_CFLAGS_COMPILE=""; 66 configurePhase = '' 67 # FIXME: Some tests require writing at $HOME 68 HOME=$TMPDIR 69 runHook preConfigure 70 71 #export EMCC_DEBUG=2 72 emconfigure ./configure --prefix=$out --shared 73 74 runHook postConfigure 75 ''; 76 dontStrip = true; 77 outputs = [ "out" ]; 78 buildPhase = '' 79 emmake make 80 ''; 81 installPhase = '' 82 emmake make install 83 ''; 84 checkPhase = '' 85 echo "================= testing zlib using node =================" 86 87 echo "Compiling a custom test" 88 set -x 89 emcc -O2 -s EMULATE_FUNCTION_POINTER_CASTS=1 test/example.c -DZ_SOLO \ 90 libz.so.${old.version} -I . -o example.js 91 92 echo "Using node to execute the test" 93 ${pkgs.nodejs}/bin/node ./example.js 94 95 set +x 96 if [ $? -ne 0 ]; then 97 echo "test failed for some reason" 98 exit 1; 99 else 100 echo "it seems to work! very good." 101 fi 102 echo "================= /testing zlib using node =================" 103 ''; 104 105 postPatch = pkgs.stdenv.lib.optionalString pkgs.stdenv.isDarwin '' 106 substituteInPlace configure \ 107 --replace '/usr/bin/libtool' 'ar' \ 108 --replace 'AR="libtool"' 'AR="ar"' \ 109 --replace 'ARFLAGS="-o"' 'ARFLAGS="-r"' 110 ''; 111 }); 112 113### Usage 2: pkgs.buildEmscriptenPackage 114 115This `xmlmirror` example features a emscriptenPackage which is defined completely from this context and no `pkgs.zlib.override` is used. 116 117 xmlmirror = pkgs.buildEmscriptenPackage rec { 118 name = "xmlmirror"; 119 120 buildInputs = [ pkgconfig autoconf automake libtool gnumake libxml2 nodejs openjdk json_c ]; 121 nativeBuildInputs = [ pkgconfig zlib ]; 122 123 src = pkgs.fetchgit { 124 url = "https://gitlab.com/odfplugfest/xmlmirror.git"; 125 rev = "4fd7e86f7c9526b8f4c1733e5c8b45175860a8fd"; 126 sha256 = "1jasdqnbdnb83wbcnyrp32f36w3xwhwp0wq8lwwmhqagxrij1r4b"; 127 }; 128 129 configurePhase = '' 130 rm -f fastXmlLint.js* 131 # a fix for ERROR:root:For asm.js, TOTAL_MEMORY must be a multiple of 16MB, was 234217728 132 # https://gitlab.com/odfplugfest/xmlmirror/issues/8 133 sed -e "s/TOTAL_MEMORY=234217728/TOTAL_MEMORY=268435456/g" -i Makefile.emEnv 134 # https://github.com/kripken/emscripten/issues/6344 135 # https://gitlab.com/odfplugfest/xmlmirror/issues/9 136 sed -e "s/\$(JSONC_LDFLAGS) \$(ZLIB_LDFLAGS) \$(LIBXML20_LDFLAGS)/\$(JSONC_LDFLAGS) \$(LIBXML20_LDFLAGS) \$(ZLIB_LDFLAGS) /g" -i Makefile.emEnv 137 # https://gitlab.com/odfplugfest/xmlmirror/issues/11 138 sed -e "s/-o fastXmlLint.js/-s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]' -o fastXmlLint.js/g" -i Makefile.emEnv 139 ''; 140 141 buildPhase = '' 142 HOME=$TMPDIR 143 make -f Makefile.emEnv 144 ''; 145 146 outputs = [ "out" "doc" ]; 147 148 installPhase = '' 149 mkdir -p $out/share 150 mkdir -p $doc/share/${name} 151 152 cp Demo* $out/share 153 cp -R codemirror-5.12 $out/share 154 cp fastXmlLint.js* $out/share 155 cp *.xsd $out/share 156 cp *.js $out/share 157 cp *.xhtml $out/share 158 cp *.html $out/share 159 cp *.json $out/share 160 cp *.rng $out/share 161 cp README.md $doc/share/${name} 162 ''; 163 checkPhase = '' 164 165 ''; 166 }; 167 168### Declarative debugging 169 170Use `nix-shell -I nixpkgs=/some/dir/nixpkgs -A emscriptenPackages.libz` and from there you can go trough the individual steps. This makes it easy to build a good `unit test` or list the files of the project. 171 1721. `nix-shell -I nixpkgs=/some/dir/nixpkgs -A emscriptenPackages.libz` 1732. `cd /tmp/` 1743. `unpackPhase` 1754. cd libz-1.2.3 1765. `configurePhase` 1776. `buildPhase` 1787. ... happy hacking... 179 180## Summary 181 182Using this toolchain makes it easy to leverage `nix` from NixOS, MacOSX or even Windows (WSL+ubuntu+nix). This toolchain is reproducible, behaves like the rest of the packages from nixpkgs and contains a set of well working examples to learn and adapt from. 183 184If in trouble, ask the maintainers. 185