WebAssembly Compiling C

Why Compile C to WebAssembly?

Compiling C to WebAssembly offers several advantages:

  1. High Performance: C programs compiled to Wasm achieve near-native execution speeds.
  2. Portability: Wasm modules run consistently across different platforms and environments.
  3. Reusability: Existing C libraries and codebases can be integrated into web applications.
  4. Security: WebAssembly’s sandboxed environment ensures that C code runs securely without compromising the host system.

Prerequisites for Compiling C to WebAssembly

Before compiling, ensure the following tools are installed:

  1. Emscripten SDK (emsdk): A toolchain for compiling C/C++ code to WebAssembly.
  2. C Compiler: Emscripten includes a C compiler (emcc) that converts C to Wasm.

Step-by-Step Process to Compile C to WebAssembly

Step 1: Install the Emscripten SDK

Clone the Emscripten repository:

git clone https://github.com/emscripten-core/emsdk.git
cd emsdk

Install and activate the SDK:

./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh

Verify the installation:

emcc --version

Step 2: Write C Code

Create a simple C program to demonstrate the compilation process.

Example: A Simple Addition Program

// add.c
#include <stdio.h>

int add(int a, int b) {
return a + b;
}

int main() {
int x = 5, y = 7;
printf("Sum: %d\n", add(x, y));
return 0;
}

Step 3: Compile the C Code to WebAssembly

Use the emcc command to compile the C program into a WebAssembly module.

Basic Compilation:

emcc add.c -o add.html

This generates:

  • add.html: A web page to load the Wasm module.
  • add.wasm: The compiled WebAssembly binary.
  • add.js: A JavaScript file to interact with the Wasm module.

Advanced Compilation: Exporting Functions To expose specific functions for JavaScript, use EXPORTED_FUNCTIONS:

emcc add.c -s EXPORTED_FUNCTIONS="['_add']" -o add.html

Here, _add is the function being exported.

Step 4: Load and Execute the WebAssembly Module

To use the compiled WebAssembly module, write JavaScript to interact with it.

Example: Load and Use the Wasm Module

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebAssembly Example</title>
<script src="add.js"></script>
</head>
<body>
<h1>WebAssembly Demo</h1>
<script>
const Module = {
onRuntimeInitialized: function () {
const sum = Module._add(5, 7); // Call the exported 'add' function
console.log('Sum:', sum);
document.body.innerHTML += `<p>Sum: ${sum}</p>`;
},
};
</script>
</body>
</html>
  1. The JavaScript code loads the Wasm module (add.wasm).
  2. It uses the _add function from the Wasm binary to compute the sum of two numbers.
  3. The result is displayed in the browser console and on the page.

Step 5: Optimize the WebAssembly Binary

For production use, optimize the Wasm binary to reduce size and improve performance.

Optimization Flags:

  • -01, -02, -03: Different levels of optimization
  • -oz: Optimize for size
  • -s ALLOW_MRMORY_GROWTH=1: Allow dynamic memory growth

Example:

emcc add.c -O3 -s EXPORTED_FUNCTIONS="['_add']" -o add.wasm

Real-World Use Case: Integrating a C Library into WebAssembly

Suppose you want to use the math.h library in a Wasm environment.

Code Example: Calculating Factorials

// factorial.c
#include <math.h>
#include <stdio.h>

int factorial(int n) {
if (n == 0) return 1;
return n * factorial(n - 1);
}

int main() {
int num = 5;
printf("Factorial of %d is %d\n", num, factorial(num));
return 0;
}

Compile and Use the Module

emcc factorial.c -s EXPORTED_FUNCTIONS="['_factorial']" -o factorial.html

Then, load it in a JavaScript application similar to the example above.

Benefits of WebAssembly for C Developers

  1. Extend Reach
    Compile C libraries to WebAssembly to reuse them in web-based projects without rewriting code.
  2. Seamless Integration
    Use WebAssembly with JavaScript for powerful, interactive applications.
  3. Future-Proof
    WebAssembly’s growing support ensures longevity for compiled C projects.

Best Practices for Compiling C to WebAssembly

  1. Use Clear Exported Functions
    Ensure only required functions are exposed to the JavaScript environment.
  2. Optimize Code
    Use compiler optimization flags (-03, -oz) for faster execution and smaller binaries.
  3. Test Thoroughly
    Debug Wasm modules to ensure correctness and security.
  4. Secure Imports
    Limit imported functions to avoid unnecessary exposure.

Leave a Comment