Working with WebAssembly and C++: From A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction to WebAssembly and C++

\n\n

Modern 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\n

In 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\n

1. Toolchain and Environment Setup

\n\n

The 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\n

Installing Emscripten

\n

The recommended installation method is via the emsdk package manager:

\n\n
# 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\n

After installation, you will have the emcc (compiler) and em++ (C++ compiler) commands, which are wrappers around Clang.

\n\n

2. Compiling C++ to WebAssembly

\n\n

Let's look at a simple example. Create a file hello.cpp:

\n\n
#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\n

An important element is the EMSCRIPTEN_KEEPALIVE macro. It prevents the function from being removed by the optimizer and makes it exportable.

\n\n

Let's compile our code:

\n\n
em++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3
\n\n

Let'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
\n\n

As a result, we get three files: hello.html, hello.js (glue code), and hello.wasm.

\n\n

3. Interaction with JavaScript

\n\n

After 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\n

Key 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._malloc and pointers are used.
  • \n
\n\n

Passing Strings

\n

Example 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\n

In JavaS

Blogs

Book Recommendations