Back to the Future with WebAssembly

Hello, Habr! I present to you the translation of the article "Back To The Future With WebAssembly" by Attila Vágó.

This post is a translation of an article that talks about the properties of WebAssemly and Emscripten. Original article in English.

The author of the article, Attila Vago, is a senior software developer at HMH. Writes code, blogs and stuff on the Internet. A polyglot of programming languages, a pragmatic figure, with a passion for JavaScript and easy access. Easily inspired and inspiring person with a strong addiction to things for nerds, great food, craft beer and Lego. Used by Mac. He exercises at 6 in the morning.

In 2011, I wrote my first independent line of non-HTML code (I worked with it in 2007), and it was written in the very good old C taught by Professor David J. Malan from Harvard University. He will forever remain my inspiration not only for the study of programming, but also for programmatic thinking. I also remembered that making a peanut butter sandwich is just for me, but it is an incredibly difficult task for a computer and equally difficult for a person pretending to be a computer.

If you watched the video, at least the first 18 minutes (I know that it takes a long time, but programming takes time), then you will understand why to this day C is close to my heart. To my disappointment, I never learned it, because, let's face it, for a web developer, C is the least of the priorities. I never had a real reason to dive deep into this language, despite buying countless Udemy courses and C books, I never touched them (keep your judgmental looks to yourself, you did too) or lie to myself that if I buy smart watch Pebble, which work in C, then be sure to write a code for them. Yes exactly! None of these reasons were good enough.

What is WebAssembly and how does it overtake JS?

WebAssembly (Wasm for short) is a binary instruction format for a stacked virtual machine.

“Wasm was developed as a portable platform for compiling high-level languages ​​such as C / C ++ / Rust, which allows you to deploy client and server applications on the Internet”
- kindly explains

In other words, the above means that you can write modules that work on the Internet in a browser / server, but are written in languages ​​such as C, compiled into a binary file and therefore incredibly fast because they work directly on the hardware of the machine. Compared to them, scripting languages ​​such as JavaScript have several levels of abstraction between code and hardware, which, among other things, makes them slow. Of course, this does not always matter, and each of them has its own place in the program or even the web ecosystem.

Based on this, Wasm by structure (initially) supports only integers and floating-point numbers, which gives great computing power and, therefore, is often used for canvas-type implementations. It’s important to understand that WebAssembly is not a threat to JavaScript - at least for now - and, as you will see later in this article, C and JavaScript can actually live very happily in the same project and can run each other's code. Yes, something like that.

Emscripten "glues" C and JS

Now hold on! I know what I am saying. You can’t say things like “run C in JS and vice versa” and expect the world to not react. No matter how strange it sounds, I’m not fooling. It turns out that Emscripten is a chain of tools for compiling in asm.js and WebAssembly, designed using LLVM (my God, I learned half of these things while typing the text of the article), which allows you to run C and C ++ on the Internet at almost native speed without plug-ins.

Well, here is what you need to highlight from this for yourself. Emscripten will help you compile C code in WebAssembly, providing additional tools to ease the load on the developer when it comes to communicating between the two languages, and help launch Wasm in your web project. The basic compilation command for Emscripten is as follows:

emcc lib/strings.c -s WASM=1 -o public/strings.js

While a non-basic command runs like this:

emcc lib/imports.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_getNum', '_main', '_getDoubleNum', '_greet']" -o public/imports.js

Setting up Emscripten is not the easiest thing, but not launching a rocket. The only thing that complicates the setup is that it has many dependencies like Python, Node, xCode, Git, and cMake. All instructions can be found on the installation page and are easy to follow.
Therefore Emscripten:

  • is a great tool for porting, allowing you to compile existing projects written in C or C ++ and run them in all modern browsers. Get out of here, Internet Explorer!
  • great for APIs because it converts OpenGL to WebGL and allows you to use familiar APIs like SDL or directly HTML5. Oh yeah!
  • And it's damn fast: thanks to LLVM, Emscripten, asm.js and WebAssembly, the code runs at almost its own speed. Run, rabbit, run!

Note: You don’t need Emscripten to generate Wasm, since all new browsers have an API for supporting Wasm in the same window, which runs Emscripten as the top layer, which makes the life of the developer much easier. For example, Emscripten will adjust the amount of memory for you, which can be tedious through C.

Examples ... examples are everywhere!

You know, as they say, “a line of code is worth a thousand words” , - OK, this is the prerogative of the narrator and all that, so without further ado, let's take a look at some real code. Off-topic commentary: that day I could not overcome the C syntax. It did not compile half the time, because my code would be shaky. And after eight years I’m like this: "Yes, it looks like JavaScript . "

Guys, if someone starts to see C code in my React, just bring me back to reality, okay?

A little off topic, here's the current C code:


And, accordingly, in JavaScript:


OK, what exactly happens in these files? Actually quite a lot, so I will list.

  1. It is important to understand that main () , unless otherwise specified, always starts first and also compiles by default. If you want to compile another function, you will need to specifically set it in the flag of the EXPORTED_FUNCTIONS array , as shown in the previous section.
  2. You write your C code, as usual, importing its regular libraries, but on top of this you get Emscripten syntactic sugar, as well as more methods / functions than with any other tool.
  3. The imports.js file (the name is arbitrary, but always the same as the C file) referenced by HTML is nothing more than the “glue” Emscripten, which is automatically generated at compilation. No need to worry about it, just make sure it is really referenced.
  4. Printf is just an ordinary C statement registering a string on the console. Nothing special, move on.
  5. Lines 14 and 17 are an anti-pattern, but a good example of running JS in your C code. The only real difference between emscripten_run_script and emscripten_async_run_script is that the latter allows you to run JS in C asynchronously. Mostly with setTimeout () . The reason I said that this is an anti-pattern is because it is. The whole idea of ​​WebAssembly is to run C in JS, not JS in C, and therefore ...
  6. Lines 20 and 24 and their associated JS functions in the index.html file represent the correct template, namely declaring your JS in your JS and returning something for C.
  7. EM_JS , which then launches jsFunction , is simply an easier way — to achieve the same goal as in points 4 and 5.

The predicted result of the above is as follows:


Ladies First!

As with any code, WebAssembly also has a running order. Do not mess with the queue! The order in this case is standard for C order. Everything starts in Main () and whenever main () is ready, Wasm is ready. However, what happens if you need a static function to call at runtime? Well, just a little Emscripten syntactic sugar, and everything goes like clockwork:


We collect flies from the cake

This is well-written code, especially the simple things illustrated in the previous sections, but we all know that the real world is much larger than “Hello World”, and half of each developer’s time is spent figuring out why the code isn’t doing what should. Bugs are simply inevitable and in a sense are part of life.

When you run C in JS or any Wasm, for that matter, everything can become even more depressing. Fortunately, Emscripten comes to the rescue again by providing two very useful debugging methods:

// browser debugger gets triggered
// browser console warning with stack-trace
emscripten_log(EM_LOG_WARN, “‘param’ your message”);

Quick Gonzalez hurries to help

Believe it or not, the creators of Emscripten have thought of everything. One big feature - and the last one that I will mention in this article, since there are too many of them to put them all in one - is the basis for rapid development and testing. You can compile your Wasm, build a project and start the server in one fell swoop:

emrun --port 7777 --no_browser public/index.html
Now listening at http://localhost:7777/

The html page you are running is not emrun-capable. Stdout, stderr and exit (returncode) capture will not work. Recompile the application with the --emrun linker flag to enable this, or pass --no_emrun_detect to emrun to hide this check.

Okay, in two fellows ... the above example works, but the next works better, which explains the error shown.

// compile as emrun project
emcc lib/strings.c -s WASM=1 --emrun -o public/index.html
// run the emrun server again
emrun --port 7777 --no_browser public/index.html

I just leave it like that. Studying WebAssembly, I celebrated St. Patrick's Day and the next day. Not quite sure what will happen next, but it thrilled me enough to sit in front of the monitor for two days, trying to get into the basics of WebAssebly, and that should mean something, right? This is the very C code I've written since 2011, and it feels great. I think WebAssembly has a real future, but I'm not sure if it will completely take over the network and kill JS, as some preach. And what do you think?


Also popular now: