Back to the Future! From C++ to Angular

Alex
ngconf
Published in
8 min readFeb 28, 2019

How to integrate C++ code with Web Assembly in our Angular Projects.

Downloaded from Wikipedia, This image can have rights.

Back to the old schools days, I remember writing a lot of C/C++, as my primary language, for a lot of school projects. C /C++ is known to be a very powerful language. Thanks to C/C++’s performance, it is often used to develop game engines, games, and desktop apps.

Nowadays, It sounds a little weird to do web development with languages like C/C++, Prolog, Perl and many other good languages that are not considered web languages.

Maybe you have heard about Web Assembly? If not, you should read these articles first.

A cartoon intro to Web Assembly

What is Web Assembly?

So what’s the deal? Let’s begin, the first step is to build the component in C/C++, you can compile it into WebAssembly using a tool called Emscripten. Emscripten is an LLVM to JavaScript compiler.

The installation and setup instructions are detailed here, and just to verify emscripten is installed you can type.

./emcc -v
Just to be sure emscripten is installed and ready to go.

Create a helloworld.c file using Notepad or VS Code or whatever editor you like.

helloworld.c

To build the JavaScript version of this code, simply specify the C/C++ file after emcc (use em++to force compilation as C++):

./emcc tests/hello_world.c

As a result of this 2 files are generated a.out.js and a.out.wasm, the .wasm file os our web assembly compiled code and the other one, the .js is our JavaScript file which contains the runtime support to load and execute it.

a.out.wasm is a binary file

Run the a.out,js using node

node a.out.js

As as you can expect the output is hello, world!, nothing really impressive but it’s illustrative.

Running in Node a previous C language code.

Generating HTML

Emscripten can generate an HTML output.

./emcc tests/hello_world.c -o hello.html

And we can see it in our browser, maybe we need a web server, so the easiest way to do this is to use the python SimpleHTTPServer (in the current directory do python -m SimpleHTTPServer 8080 and then open http://localhost:8080/hello.html).

Finally we can see the ouput on a html generated file

The fun part

Let´s see another example, maybe this is Graphics Programming 101 but I think the possibilities are endless, for instance, we can use the SDL API.

Simple DirectMedia Layer is a cross-platform development library designed to provide low-level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.

Graphics Programming 101

This exercise was made in 1997, 22 years ago!

But the number of changes required to bring this code to the web is really quite minimal.

1997, no Angular yet!!

Let’s see some C++ code for a nice color cube, also using SDL ( the previous one was made in pure C ), you can access the repo here, this code was taken from the official emscripten repo.

hello_world_sdl.cpp

// Copyright 2011 The Emscripten Authors.  All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. these licenses can be
// found in the LICENSE file.

#include <stdio.h>
#include <SDL/SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

extern "C" int main(int argc, char** argv) {
printf("Hello from C++ to Angular!\n");

SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *screen = SDL_SetVideoMode(256, 256, 32, SDL_SWSURFACE);

#ifdef TEST_SDL_LOCK_OPTS
EM_ASM("SDL.defaults.copyOnLock = false; SDL.defaults.discardOnLock = true; SDL.defaults.opaqueFrontBuffer = false;");
#endif

if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen);
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
#ifdef TEST_SDL_LOCK_OPTS
// Alpha behaves like in the browser, so write proper opaque pixels.
int alpha = 255;
#else
// To emulate native behavior with blitting to screen, alpha component is ignored. Test that it is so by outputting
// data (and testing that it does get discarded)
int alpha = (i+j) % 255;
#endif
*((Uint32*)screen->pixels + i * 256 + j) = SDL_MapRGBA(screen->format, i, j, 255-i, alpha);
}
}
if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
SDL_Flip(screen);

printf("you should see a smoothly-colored square - no sharp lines but the square borders!\n");
printf("and here is some text that should be HTML-friendly: amp: |&| double-quote: |\"| quote: |'| less-than, greater-than, html-like tags: |<cheez></cheez>|\nanother line.\n");

SDL_Quit();

return 0;
}

Just a couple of observations.

Emscripten provides a number of helper methods that make interactions between the module and JavaScript easier.

Emscripten includes a conditional compilation symbol, __EMSCRIPTEN__, that you can use to detect if the solution is being compiled by Emscripten.

__EMSCRIPTEN__ explanation

THE EXTERN “C” BLOCK

In C++ function names can be overloaded, so to make sure the name is unique when compiled, the compiler mangles the name by adding information to it about the function’s parameters. The compiler changing the names of functions when the code is compiled is a problem for external code wanting to call a specific method because that method’s name no longer exists.

You’ll want to tell the compiler to not adjust the names of the methods that the JavaScript code will be calling. To do this you need to include an extern "C" block around the methods.

Continue. Repeat the previous compilation steps.

And the output in our browser.

Our color cube .cpp output in HTML.

Having Emscripten generate an HTML file is not typically used for production but is very useful if you are learning about Web Assembly.

Web Assembly opens fantastic and interesting new alternatives and it’s already supported in browsers, and no, Web Assembly doesn’t replace JavaScript but does expand the Web. Enables new, hybrid ( WASM + JS ) designs.

Web Assembly is here, it works.

Angular Integration

We can start creating a new project called “ng-wasm”:

ng new ng-wasm

As you may know, we are now able to serve the app right away and test it with the following command:

ng serve --open

The app should load on the web browser at http://localhost:4200/ as shown in the image below.

Business as usual.

Create a component with the Angular cli.

$ ng g c -is -it colorcube

This is short for ng generate component. -is stands for in-line styling and -it stands for in-line templating.

colorcube folder

The hello_world_sdl.cpp could be located in the same folder — the one with the color cube C++ code, but just be sure that after compilation you get the files (webassembly.js and webassembly.wasm) inside the color cube folder.

Emscripten can be instructed to generate the WebAssembly module file and, depending on the options specified in the command line, Emscripten can also include a JavaScript plumbing file and an HTML file.

A JavaScript plumbing file is a JavaScript file that Emscripten generates. The contents of the file can vary depending on the command line arguments given.

Compile now this code with the following command:

emcc \
-O3 \
-s WASM=1 \
-s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" \
-o webassembly.js \
hello_world_sdl.cpp

Note that I compile the C++ code with optimizations on (-O3 parameter), which makes the output more compact and efficient (if possible).

The flag that tells Emscripten that you want a WebAssembly module is: -s WASM=1 (the dash for -s is a hyphen), without this parameter, it would generate asm.js code instead. And the EXTRA_EXPORTED_RUNTIME_METHODS=[‘ccall’] option is needed because we want to call the C functions from Javascript using the Module.ccall() javascript function (not in this example).

There are several optimization flags available on Emscripten’s website at https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html.

2 files are generated

As we already mentioned at the beginning of this article, after the compilation 2 files are generated, our plumbing js file and the wasm.

The WebAssembly code is now ready to be used. Let’s go back to the Angular project now.

Let’s change the app.component.ts file to have the following code:

Create and declare a component.

Include the selector in app-component.html

<app-colorcube>

In the colorcube.component.ts file code as following.

Can’t generate the WAT because the <SDL/SDL.h> library so I’m having a bad time trying to get things done.

But other solutions is to give Angular access to the WASM code, so we can create a cpp folder inside the src folder of the Angular project. See the following example, it’s a pretty simple main.c file.

#include <string.h>
#include <emscripten/emscripten.h>

double EMSCRIPTEN_KEEPALIVE multiply(double a, double b) {
return a * b;
}

int EMSCRIPTEN_KEEPALIVE get_length(const char* text) {
return strlen(text);
}

int main() {}
cpp folder

We have two C functions that we decorated with EMSCRIPTEN_KEEPALIVE, which prevents the compiler from inlining or removing them. Compile as shown in previous examples.

This is roughly the easiest way to integrate a web assembly generated code in Angular.

Let’s change again the app.component.ts file to have the following code:

We can see the implementation of two methods of the AppComponent class that will forward the call to our WebAssembly code generated previously.

Modify the app.component.html

Add a couple of buttons to the app.componet.html to call the functions. The first button will call the multiply() function and the second button will call the getLength() function.

The last step

Angular doesn’t automatically load the WebAssembly, so We have to manually change the index.html file.

Verify your name and location of the compiled js and wasm (we have it in a cpp folder).

This code imports the Javascript glue code generated by the WebAssembly compiler, but it also defines a Module.locateFile() function that will be used by WebAssembly to find the WASM file.

So the final step is pretty neat just wrap Web Assembly as an Angular Service as you can see in the following image.

Hoora!

Happy coding!

Thanks Alex

EnterpriseNG is coming November 4th & 5th, 2021.

Come hear top community speakers, experts, leaders, and the Angular team present for 2 stacked days on everything you need to make the most of Angular in your enterprise applications.
Topics will be focused on the following four areas:
• Monorepos
• Micro frontends
• Performance & Scalability
• Maintainability & Quality
Learn more here >> https://enterprise.ng-conf.org/

--

--

Alex
ngconf
Writer for

DevOps Lead @evinova, former Dynatrace Solutions Engineer. Cheerleader in Chief for KMMX, Technical Writer & International Speaker, Dad & 2 cats.