Introduction to WebAssembly and C++
\n\nModern web development is constantly seeking ways to improve performance. WebAssembly (Wasm) is a low-level binary instruction format that runs in the browser at near-native speed. Combined with C++, one of the fastest and most powerful programming languages, Wasm opens up new horizons: from high-performance games and simulations to complex data processing algorithms directly in the browser.
\n\nIn this article, we will go from the basics to practical application: we will break down how to compile C++ code into WebAssembly, run it in the browser, and optimize it for maximum performance.
\n\n1. Toolchain and Environment Setup
\n\nThe main tool for compiling C++ to WebAssembly is the Emscripten compiler suite. It translates LLVM bytecode into Wasm and automatically generates the JavaScript glue code needed to load the module.
\n\nInstalling Emscripten
\nThe recommended installation method is via the emsdk package manager:
# Clone the repository\ngit clone https://github.com/emscripten-core/emsdk.git\ncd emsdk\n\n# Install and activate the latest version\n./emsdk install latest\n./emsdk activate latest\n\n# Add environment variables (shell variables)\nsource ./emsdk_env.sh\n\nAfter installation, you will have the emcc (compiler) and em++ (C++ compiler) commands, which are wrappers around Clang.
2. Compiling C++ to WebAssembly
\n\nLet's look at a simple example. Create a file hello.cpp:
#include <emscripten/emscripten.h>\n\n// Function accessible from JavaScript\nextern "C" {\n int EMSCRIPTEN_KEEPALIVE add(int a, int b) {\n return a + b;\n }\n}\n\nAn important element is the EMSCRIPTEN_KEEPALIVE macro. It prevents the function from being removed by the optimizer and makes it exportable.
Let's compile our code:
\n\nem++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3\n\nLet's break down the flags:
\n- \n
-o hello.html— creates an HTML file with a launch example. \n -s WASM=1— explicitly specifies Wasm generation (enabled by default). \n -s EXPORTED_FUNCTIONS='["_add"]'— list of exported functions (with the_prefix). \n -O3— high optimization level. \n
As a result, we get three files: hello.html, hello.js (glue code), and hello.wasm.
3. Interaction with JavaScript
\n\nAfter compilation, we can call our C++ function from JavaScript. Here is the minimal code for loading the module:
\n\n<!DOCTYPE html>\n<html>\n<head>\n <script>\n var Module = {};\n Module.onRuntimeInitialized = function() {\n // The add function is now available\n var result = Module._add(5, 7);\n console.log("Result: " + result); // 12\n };\n </script>\n <script src="hello.js"></script>\n</head>\n<body></body>\n</html>\n\nKey points:
\n- \n
Module.onRuntimeInitialized— an event called after the Wasm module is loaded. \n - Function names in JS get the
_prefix (e.g.,_add). \n - For passing complex data structures (strings, arrays),
Module._mallocand pointers are used. \n
Passing Strings
\nExample of a function returning a greeting:
\n\n// C++ code\nextern "C" {\n const char* EMSCRIPTEN_KEEPALIVE greet(const char* name) {\n static std::string msg = "Hello, " + std::string(name) + "!";\n return msg.c_str();\n }\n}\n\nIn JavaS