Mirano

Emscripten

Ever wanted to make applications that run in the browser and are coded in C/C++? Well that’s what Emscripten is for. It is a compiler that will take C/C++ program and compile it to WASM, which can then be executed in all newer browsers.

WHAT IS EMSCRIPTEN

Ever wanted to make applications that runs in the browser and are coded in C/C++? Well that’s what Emscripten is for. It is a compiler that will take C/C++ program and compile it to WASM, which can then be executed in all newer browsers.

Why would you use C or C++ to code programs that run in the browser, and not JavaScript for example? Well there are plenty of reasons, and it mostly revolves around the need to have a full-fledged and very fast language that does not suffer from performance issues, so that we can create applications like: 3D games, Virtual Reality or Augmented Reality programs, processing images or other high-computational algorithms, creating programs for communicating with various industrial machines, etc. For such applications you need to use the language that is extremely fast and efficient, hence the Emscripten. If you want to read more about it, please go here: https://kripken.github.io/emscripten-site/.

The architecture is rather simple if we are looking from 10.000 feet, so it would look something like this:

emscriptentoolchain

Figure 1.1: Emscripten Toolchain

Emscripten compiler takes the C or C++ code and converts it to LLVM bitcode, and then compiler’s core is used to compile the bitcode to WASM (web assembly), that can be executed in the browser. We are going to be using Emscripten Compiler Frontend (emcc) in our examples.

SAMPLE PROGRAM

The sample program would be created in Visual Studio 2019, then we need to compile it using Emscripten and run it in the browser. There is no any specific reason for using VS 2019, since VS 2017 would also work just fine. You can find the code for these examples here.

For the beginning, we would just create a simple Hello World example to demonstrate that it works, and then would go on to actually draw something in the browser to demonstrate that we can use drawing libraries (simple libraries or Open GL) from C/C++ code.

Before we do that, we need to install the compiler itself, so here are the pre-requisites:

  1. Install Python
  2. Clone Emscripten from Github
  3. Install Emscripten
  4. Create C/C++ program and compile it into WASM module.

First, we need to install Python, at the time of writing this post the latest version was Python 3.7.2. Just go to the web site and find the web installer, the installation is straightforward. We need it because the core Emscripten SDK is in Python. If you have it already, then you do not need to re-install. I use Chocolatey to install Python, and many other packages, so if you wish to try it then you can read more about it here, and if you already use Chocolatey then execute this command in command prompt (with elevated privileges as administrator):

choco install python2 --version 2.7.13

Please note that all this is very experimental, and one of the issues I found was that with Python 3 or Python 2 versions 2.7.2 or lower it would not work, as it internally relies on these, so the safest solution for you is to issue the above Chocolatey command to install this specific version of Python.

Git needs to be installed as well, and I am using a Windows 10 machine that has Visual Studio 2019 Preview 1.1 installed (you can use Visual Studio 2017, it should work just fine). So please go to this link, and the install should start automatically. We need Git because we need to first clone the compiler from GitHub and then to install it.

Now open VS developer command prompt, and type this:

git –-version

It returns git version 2.20.1.windows.1 with me. Ok, now we need a folder to clone the Emscripten compiler. I have created the folder “c:\temp\EmscriptenSDK” on my machine, then cd to that folder, and then issues the following command:

git clone https://github.com/juj/emsdk.git

This would download the bootstrap, now we need to install it. Please execute the following commands:

cd emsdk
git pull
emsdk install latest
emsdk activate latest

This installed this version of compiler with me: Emscripten-1.38.21. The whole folder would be around 1.12 Gb, so please be patient.

Okay, so now we have an Emscript compiler installed. Do not close the current command prompt, and execute the following command:

emsdk_env.bat

This should add the environment variable to the PATH, so that we can call the compiler even after we close the command prompt. So close the command prompt, and re-open it again, and try typing this:

emcc --version

It should show you the version, something like emcc (Emscripten gcc/clang-like replacement) 1.38.21 in my case.

If you did not get the version, then you need to set up the environment variable manually…so go to Control Panel -> System -> Advanced System Settings -> Environment Variables… -> and then in System Variables find Path variable -> Edit -> New -> and add “c:\temp\EmscriptenSDK\emsdk” folder (or other folder in your case, if you did not use this one to install the sdk).

Example 1: Show simple message

Let us now fire up Visual Studio, add New Project and create a new empty C++ project. This is what I’ve got:

create-new-project

Then click next, add the name to the project, and finally click on “Create” button. As you can see, I have created the project in c:\temp\EmscriptenDemo folder.

Now right click on the “Source Files” folder in the SolutionExplorer, add new C file and name it test.c, and add the following code to it:

#include <stdio.h>

int main(int argc, char ** argv)
{
	printf( "Hello there from WASM module!\n" );
}

So not much there, just the main function and printing a message that should show in the browser. Let’s try to compile this now and run it in the browser. First compile it in Visual Studio, to make sure everything works, by clicking on Build -> Build EmscriptenDemo, or by pressing SHIFT+F6. If it compiles, then please go to Command Prompt, navigate to the root folder (C:\temp\EmscriptenDemo\EmscriptenDemo in my case), where the test.c file is located in, and execute this command:

emcc test.c -s WASM=1 -o test.html

First time it can take around 20-30 seconds to compile from a cold-started compiler. Every subsequent compilation would be immediate.

This should have produced the following files in the same folder: test.html, test.js and test.wasm.

Please open this folder and right click the test.html file and open it in the browser (I am using FF). You will see the page opened and displaying our message in the console part of the page.

Now just for run, go back to Visual Studio, change the message to "Hello AGAIN there from WASM module!\n" (or something else), save the file, compile with SHIFT+F6, then back to command prompt and execute the same command….after it completes then F5 refresh the browser, it should show you the new message. Don’t close the browser, we’ll need it for the next example.

Example 2: Draw on canvas

Example 2: Draw on canvas Let us now try to do more by drawing on the canvas in the browser. We can use the same project, so please add the new C++ file to the Source Files folder, and name it testsdl.cpp, then add this code to it:

#include <iostream>
#include "SDL.h"
#include "SDL_opengl.h"

int main(int argc, char ** argv)
{
	printf("Testing SDL...!\n");

	SDL_Init(SDL_INIT_VIDEO);

	// Try to create window
	SDL_Window *window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, 
		SDL_WINDOWPOS_CENTERED, 640, 480, SDL_WINDOW_SHOWN);
		
	if (!window)
	{
		fprintf(stderr, "Cannot create window: %s\n", SDL_GetError());
		return 1;
	}

	// Setup renderer
	SDL_Renderer* renderer = NULL;
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

	// Bckg color
	SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
	SDL_RenderClear(renderer);

	// Creat a rect at pos ( 120, 100 ) that's 80 pixels wide and 80 pixels high.
	SDL_Rect rect = { 120, 100, 80, 80 };

	// Square color
	SDL_SetRenderDrawColor(renderer, 255, 128, 0, 255);

	// Now render
	SDL_RenderFillRect(renderer, &rect);
	SDL_RenderPresent(renderer);
	
	//Clean up
	SDL_DestroyWindow(window);
	SDL_Quit();

	return 0;
}

This code uses the SDL library for drawing, and since you most likely do not have it installed then it cannot see it and compiling this with SHIFT+F6 would give you a lot of errors. SDL stands for Simple DirectMedia Layer library, and it is used for creating games and such. The code is simple and has comments, it just paints the background with one color and then draws a rectangle and fills it with another color. Nothing fancy really, but we want to show that we can do this from C++ code in the browser. And besides, if you can draw rectangles (or triangles, to be more precise) then you can create any game or graphical type of application as well, as everything is created using triangles (yes, even the spheres).

There are now two ways from here: we can add the SDL library and make it compile in Visual Studio, and then compile it with Emscripten, or compile it just with Emscripten using the port of SDL and specify the switch for the compiler. How is this possible? Well it is very logical indeed, since we do not really need to compile in Visual Studio and we were doing that only to make sure it really works and can compile, and then did a compilation with Emscripten to WASM. Since I am providing the code for this example you can be sure it works, so you can just go ahead and skip to the section Compile with Emscripten. If you still want to compile it with Microsoft C++ compiler in Visual Studio, and maybe use this to add some more functionality and play with it, then start with the next section Compile with Microsoft C++ Compiler and then continue with Compile with Emscripten.

Compile with Microsoft C++ Compiler

We need to add the SDL library if we were to compile this in Visual Studio, so please follow these steps:

  1. Go to SDL homepage here, then Downloads and then SDL 2.0, find the link “SDL2-devel-2.0.9-VC.zip (Visual C++ 32/64-bit)“ and unpack it somewhere. Then copy the newly created folder to C:\temp or somewhere as per your liking, and rename it to SDL2 (so that we can more easily manipulate it)
  2. My SDL installation is in C:\temp\SDL2….please go to Visual Studio, right click on the project, then C/C++ and General, and add the following path to the “Additional Include Directories”: c:\temp\SDL2\include (or your folder, if different).
  3. Then got to Linker -> General and do the same for “Additional Include Directories”.
  4. Now we need to add libs, so go to the project, right click on the project, Add -> An existing item…then navigate to c:\temp\SDL2\lib\x86 folder and add these files: SDL2.dll, SDL.2.lib and SDL2main.lib. They should now appear in the Solution Explorer.
  5. Try to build the project now with SHIFT+F6, it should build fine.

My Solution Explorer now looks like this:

solution-explorer

Compile with Emscripten

Let us now compile the code in testsdl.cpp with Emscripten and run it in the browser. Please go to the command prompt and execute this command:

emcc test.c -s WASM=1 -o test.html

Now this is different than before, right, because we are now telling the compiler to use the port of SDL2. You can read more about it here: Emscripten Ports. In any case, it should compile our file (you will see the port of SDL2 being downloaded from GitHub) and since we are outputting it to the same html file we can just refresh the existing test.html, and we should see something like this:

solution-explorer

All good…we can now draw on the canvas in the browser from C/C++ code.

CONCLUSION

Emscripten compiler is the powerful solution to use C/C++ or other languages to create applications that target browsers. This opens endless possibilities since we can now use the native code and run it anywhere, from PCs over Linux or Max to iPads. We do not have to port anything to JavaScript or learn JavaScript at all, and this by itself is a huge advantage.

Many projects have already been converted with Emscripten, like Unreal Engine 4, Unity engine, Bullet Physics Engine…you can check a more comprehensive list here.