Last week I wanted to check out what state Rust was at, in the area of compiling code to an asmjs target using emscripten. As a web developer and a Rust enthusiast, naturally I was pretty interested in the whole concept and I have been watching the git conversations about getting rustc compiling to an emscripten target for quite a while.

I knew that there was a tool called cargo-emscripten located here that essentially does exactly what I want, and makes the whole process pretty painless, however the project readme page on github for that tool now states: "Do not use this. Emscripten support has been merged in Rust."

Wow, that's big news. Does it work? How do I do it? Is there a guide?

I couldn't actually find any more information on it, other than the commit messages of the changes that were checked into the rust master branch throughout the last month or so. I tried a bunch of stuff and finally got it to work, so I figured I should make a guide to help others looking for a similar thing.

This guide is valid for rust nightly as at the 1st of March 2016, line numbers and changes that need to be applied WILL change in time, and when they do I will either update this page, or write a new guide.

1. First we install the Emscripten SDK tools, on Linux and OSX there is a handy CLI tool called emsdk_portable which will do that for us. Download emsdk-portable.tar.gz from the emsdk download page. The following block of commands assumes the file is located in the Downloads folder of your home directory.

In this block will create a new directory in /opt for the emsdk CLI tool, unzip the archive, install the contents to /opt/emsdk, then issue the commands to install the latest version of Emscripten and the latest version of the Emscripten SDK (which is essentially just the fastcomp LLVM and Clang fork).

sudo mkdir /opt/emsdk
sudo chmod 777 /opt/emsdk
cd ~/Downloads
tar -xpszf emsdk-portable.tar.gz
rsync -r ./emsdk_portable/ /opt/emsdk
rm -rf ./emsdk_portable
cd /opt/emsdk
./emsdk update
./emsdk list
./emsdk install emscripten-incoming-64bit #(takes about 2 minutes)

We have to make a small change to emscripten to add rudimentary support for rust Unwind_RaiseException function

cd /opt/emsdk/emscripten/incoming
gedit ./src/library.js

Go to line 4058, and all this line in to the blank space:

_Unwind_RaiseException__deps: ['__cxa_find_matching_catch', '$EXCEPTIONS'],

Now go to line 4060 and replace "abort('Unwind_raiseException')" with:

    Module.printErr('Warning: _Unwind_RaiseException is not correctly implemented');
    EXCEPTIONS.infos[ex] = {
      ptr: ex,
      adjusted: ex,
      type: null,
      destructor: null,
      refcount: 0
    EXCEPTIONS.last = ex;
    {{{ makeThrow('ex') }}}

Now we can continue installing the rest of the emscripten sdk.

./emsdk activate emscripten-incoming-64bit
./emsdk install sdk-incoming-64bit #(takes ages to compile)
./emsdk activate sdk-incoming-64bit

2. Next we will clone the rust git repository. This assumes you do not already have a copy of the rust codebase, and you that you want to clone it into your `~/CODE` directory.

cd ~/CODE
git clone
cd rust

3. After that is completed, we need to make some changes to a rust source file and the config script.

gedit ./src/librustc_llvm/

Go to line 2405, and enter:

init_target!(llvm_component = "jsbackend",

4. Next open the config file for editing.

gedit ./configure

Go to line 969, and change the line to:


5. Next edit the rust main makefile to add jsbacked to the list of known LLVM components.

gedit ./mk/

Go to line 274, and add this to the end of the list of LLVM components:


6. We are now ready to configure and make rustc using our emscripten fastcomp version of the LLVM backend. This also configures a new install prefix for this unique build of rust, so that it won't interfere with any other installations of rustc you have on your system.

./configure --prefix=/usr/local/rust_emscripten --target=i686-unknown-linux-gnu --llvm-root=/opt/emsdk/clang/fastcomp/build_incoming_64 --disable-docs --disable-jemalloc
make #(long, takes ages to compile)
sudo make install

With hopefully no errors, rust is built and installed to /usr/local/rust_emscripten. The rust compiler by itself it not much fun to use, we want cargo too!

7. In this next block of bash commands, we clone the Cargo git repository to our ~/CODE folder, and manually compile a version of cargo configured to use our new rustc. We also install this new cargo binary to /usr/local/rust_emscripten to keep everything together.

cd ~/CODE
git clone
cd cargo
python -B src/etc/
./configure --prefix=/usr/local/rust_emscripten --local-rust-root=/usr/local/rust_emscripten
RUSTC=/usr/local/rust_emscripten/bin/rustc RUSTDOC=/usr/local/rust_emscripten/bin/rustdoc make
sudo make install

8. With cargo successfully built and installed, we want to modify the way that the cargo command is called, because we need to set up some local environment variables for emsdk, cargo, and rustc, which need to be in place every time cargo is called. We do that by making a wrapper script around the cargo binary.

cd /usr/local/rust_emscripten/bin
sudo mv cargo cargo_real
gedit ./cargo

9. Fill in the new cargo file with the following contents

. /opt/emsdk/
export RUSTC=/usr/local/rust_emscripten/bin/rustc
export RUSTDOC=/usr/local/rust_emscripten/bin/rustdoc
/usr/local/rust_emscripten/bin/cargo_real "$@"

10. Now make it executable

sudo chmod +x ./cargo

11. We can test out the cargo build, and our cargo wrapper script, but installing something cool that we will want to use, like racer :)

sudo bash /usr/local/rust_emscripten/bin/cargo install --root /usr/local/rust_emscripten racer

Yes. It worked!

12. Now for the hard stuff. We have a version of rustc which can compile code to asmjs, but we have no rust libraries compiled for that target that we can use to build things with. We cannot yet build libstd for emscripten for a number of reasons. We can however build libcore, which is a library of some vital rust components that every application will need. It will suffice for now.

This chunk of code will build libcore from the rust source directory, but it builds it by itself (out of tree) to avoid conflict with the rest of the rust source files.

cd ~/CODE
/usr/local/rust_emscripten/bin/cargo new core
cd core
rm -r src
ln -s ~/CODE/rust/src/libcore src

13. Now compile it using cargo, and install it to our rustlib directory.

/usr/local/rust_emscripten/bin/cargo build --target=asmjs-unknown-emscripten --release
sudo mkdir -p /usr/local/rust_emscripten/lib/rustlib/asmjs-unknown-emscripten/lib
sudo cp ./target/asmjs-unknown-emscripten/release/libcore.rlib /usr/local/rust_emscripten/lib/rustlib/asmjs-unknown-emscripten/lib

14. At this stage, we now have everything in place we need to generate actual javascript code :), lets test it out with a sample program. Cargo can help us set one up.

cd ~/CODE
/usr/local/rust_emscripten/bin/cargo new --bin jstest
gedit src/

15. In the file, paste this code:

// Entry point for this program
fn start() {
// These functions and traits are used by the compiler, but not
// for a bare-bones hello world. These are normally
// provided by libstd.
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }

16. Finally, run the cargo command to build it.

/usr/local/rust_emscripten/bin/cargo build --target=asmjs-unknown-emscripten

If you go to ./target/asmjs-unknown-emscripten/debug/ and see a file called jstest.js then you have just successfully compiled Rust code to javascript. Well done :)

Joomla SEF URLs by Artio