Use the latest Clang compiler to create your first 'Hello World' WebAssembly module.
To compile and produce our first WebAssembly module, we'll be using Docker. Docker makes it super easy to run a pre-packaged virtual machine like environment which enables you to install all manner of packages without affecting your main system.
You will also need to be comfortable with using the command line as some of the steps require you to run commands.
Naturally, you will also need a browser capable of running WebAssembly to test out our WebAssembly module. Any post-2017 browser should work.
Using Docker, we'll spin-up a Debian Linux host image (debian:stretch
) with the latest CLang compiler that will enable us to produce our WebAssembly module from source code.
Before we do anything, let's first create a webassembly_helloworld
directory in our local system for our project. Start a terminal (or command prompt) and run the following commands:
mkdir webassembly_helloworld
cd webassembly_helloworld
For your convenience, I have prepared all the source files we'll be using in this guide in this zip file . You can download this file and extract its contents or create the files manually by following the next steps.
We'll need some source code that can be compiled into our "Hello World" WebAssembly module. So, let's create a helloworld.c
source file in the webassembly_helloworld
directory with the following contents:
#include <stdio.h>
#include <errno.h>
int main(int argc, char **argv) {
fprintf(stdout, "Hello World from your first WebAssembly module!\n");
return 0;
}
We have our source file, now we need a way of compiling this into WebAssembly. As mentioned above, we'll start a Debian Linux host (using Docker) that will have everything setup to compile WebAssembly.
To setup the Debian Linux image with everything we need, create a new Dockerfile
file in the webassembly_helloworld
directory with the following contents:
FROM debian:stretch-20190506-slim
RUN apt-get update \
&& apt-get install -y curl gnupg xz-utils
RUN curl -O https://apt.llvm.org/llvm-snapshot.gpg.key \
&& apt-key add llvm-snapshot.gpg.key \
&& echo "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch-9 main" >> /etc/apt/sources.list \
&& echo "deb-src http://apt.llvm.org/stretch/ llvm-toolchain-stretch-9 main" >> /etc/apt/sources.list \
&& apt-get update \
&& apt-get -y install clang-9 lld-9
RUN mkdir /wasi-src ; cd /wasi-src \
&& curl -O -L "https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk-5.0-linux.tar.gz" ; mkdir wasi-sdk ; cd wasi-sdk ; tar -zxvf ../wasi-sdk-*
RUN cd /wasi-src \
&& curl -O -L "https://github.com/CraneStation/wasi-sysroot/releases/download/v0.1-alpha/wasi-sysroot.tar.xz" ; mkdir wasi-sysroot ; cd wasi-sysroot ; tar -xvf ../wasi-sysroot.*
RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-9 100 \
&& update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-9 100 \
&& update-alternatives --install /usr/bin/wasm-ld wasm-ld /usr/bin/wasm-ld-9 100
RUN dirname `clang --target=wasm32-wasi -print-libgcc-file-name` | xargs mkdir \
&& clang --target=wasm32-wasi -print-libgcc-file-name | xargs cp /wasi-src/wasi-sdk/wasi-sdk-5.0/opt/wasi-sdk/lib/clang/8.0.0/lib/wasi/libclang_rt.builtins-wasm32.a
CMD ["/bin/bash"]
WORKDIR /src
With the Dockerfile
file ready to go, We are now ready to prepare what we'll need to compile WebAssembly in the Debian Linux host.
From the webassembly_helloworld
directory, let's prepare the WebAssembly build host by running the following command:
docker build -t webassemblytutor_helloworld .
After running the above command, Docker will download a pre-packaged debian:stretch
host image and setup everything we need to compile WebAssembly. Once the command has completed, let's start the Debian Linux host with the following command:
# start Docker in interactive mode
# map our local machine directory (webassembly_helloworld ) to the /src directory in our Debian Linux host
# ensure permissions inside the Debian Linux host are the same as the running machine
# use our shiny new webassemblytutor_helloworld we prepared in the previous step
# start a bash shell for us to enter our compile commands
docker run \
-it --rm \
-v $PWD:/src \
--user root -e NB_UID=$UID -e NB_GID=$GID \
webassemblytutor_helloworld \
/bin/bash
Now we are ready to compile our "Hello World" WebAssembly module. Let's compile the helloworld.c
we created above with the following command:
clang --target=wasm32-wasi --sysroot=/wasi-src/wasi-sysroot/sysroot helloworld.c -o helloworld.wasm
Finally, let's test our shiny new WebAssembly module with the WASI web polyfill tester at https://wasi.dev/polyfill.
Click choose file and navigate to the webassembly_helloworld
directory we created on the very first step and select the helloworld.wasm
file.
You should see "Hello World from your first WebAssembly module!" appear in the text box. Congratulations, you have compiled your first WebAssembly module.
Using the latest Clang compiler, you have compiled and ran your first "Hello World" WebAssembly module in a web browser. This basic module is a great starting point that you can build upon to compile your own advanced projects.
What do you think?
Have you done anything cool with WebAssembly?
Get in touch via twitter.
Read more articles and tutorials about WebAssembly.