# Emscripten: compiling C and C++ to WebAssembly with emcc

> Emscripten turns C and C++ into WebAssembly plus a JavaScript loader, using LLVM and Binaryen. It is the right tool when you have a native codebase and a browser or Node.js target, and the wrong tool when you just want to hand-write a small wasm module.

**emscripten-core/emscripten** — Emscripten: An LLVM-to-WebAssembly Compiler

- Repository: https://github.com/emscripten-core/emscripten
- Stars: 27,641 · Forks: 3,558
- Language: C++
- License: NOASSERTION
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/emscripten-core-emscripten

## What Emscripten solves, and who ends up using it

The problem is not writing WebAssembly. The problem is having a few hundred thousand lines of C or C++ that already work, plus a build system, plus dependencies, and needing that code to run in a browser or in Node.js. Emscripten compiles those sources to WebAssembly using LLVM and Binaryen, and emits a JavaScript file that loads and runs the module. The README states that output can run on the Web, in Node.js, and in wasm runtimes.

The audience is narrower than "anyone curious about wasm". It is people porting existing portable applications. The README points at Unity and Google Earth as examples of complex graphical native applications that were ported, and attributes that to Web support for portable APIs such as OpenGL and SDL2. If your code calls SDL2 for input and windowing, or OpenGL for rendering, that API surface is the reason Emscripten is a realistic path rather than a research project.

Emscripten mostly focuses on compiling C and C++ through Clang, but the README notes it can be integrated with other LLVM-using compilers, giving Rust's wasm32-unknown-emscripten target as the example. That single sentence matters more than it looks: it means the toolchain is positioned as an LLVM backend target, not as a C-only compiler.

## How the LLVM-to-WebAssembly pipeline actually fits together

Emscripten is not a compiler in the sense that it parses your C++. Clang does the front-end work, LLVM does the middle-end optimization and code generation, and Binaryen handles the WebAssembly-specific optimization and generation stage. Emscripten is the driver that wires those together, supplies the runtime libraries, and produces the JavaScript glue.

The output shape is the part worth understanding before you start. Compiling a source file produces a WebAssembly module plus a JavaScript file that can load and run it, according to the README. That JavaScript is not decoration. It is the loader, and it is what you actually execute in a browser or under Node.js, Deno or Bun. When you ask for an HTML output instead, Emscripten generates a sample page that loads that JavaScript.

Around the compiler sits a set of tools that mirror a Unix toolchain, visible in the repository's top-level entries: emcc.py and em++.py as the compiler drivers, emar.py and emranlib.py for archives, emstrip.py for stripping, emcmake.py, emconfigure.py and emmake.py for build systems, emrun.py for serving output, plus embuilder.py, emsize.py and emscan-deps.py. That layout is the real answer to "how do I build an existing project": you point its configure step at emconfigure and its make step at emmake, and the same commands that built a native binary build a wasm one.

## Installing Emscripten and compiling a first file

The README gives two installation routes. The recommended one is the Emscripten SDK, emsdk, with instructions on the downloads page of the Emscripten website. The second is a manual install from a Git checkout: install the dependencies yourself, then run the bootstrap script.

```bash
./bootstrap.py
```

The README points at the developer guide on the website for the details of that manual path. If you are not modifying Emscripten itself, the SDK route is the one the project recommends, and it is also the route that lets you pin a version.

Once emcc is on your path, treat it like gcc or clang. The README's own example:

```bash
$ emcc hello.c -o hello.js
$ node hello.js
Hello, world!
```

Run that and you should see the program's output printed by Node.js. The second line is not an Emscripten command; it is Node.js executing the JavaScript file Emscripten just generated, which is the point of the whole pipeline.

If you want something you can open in a browser, ask for HTML instead:

```bash
$ emcc hello.c -o hello.html
```

The README says you can then serve the generated hello.html with the emrun tool, or with a web server of your choosing. For a CMake project, the repository ships emcmake.py, which is the entry point you would use in place of cmake before running your normal build.

## Where Emscripten is the wrong tool, and the constraints it imposes

The clearest boundary is the one the README draws itself: Emscripten mostly focuses on compiling C and C++ using Clang. If your code is not LLVM-compilable, or your language's wasm support does not go through an LLVM target, Emscripten is not your path. Rust works because it has a wasm32-unknown-emscripten target, not because Emscripten understands Rust.

There is a hard environment floor. The repository's pyproject.toml declares requires-python = ">=3.10", so the Python tooling that drives the build expects Python 3.10 or newer. On a machine pinned to an older Python, the driver scripts and the bootstrap path are out of reach until that is resolved.

A second constraint is the two-artifact output. You do not get a single .wasm file you can drop anywhere and forget. You get a module plus JavaScript that loads and runs it, and the README's own examples show both files. Anything that consumes the build has to handle that pair, which is a different deployment shape from shipping a native binary.

The repository layout also tells you something about the cost of contributing rather than consuming. There is a test/ directory, a docs/ directory, a site/ directory, and a Makefile whose only documented targets are install and dist, with no_default explicitly refusing to run without an explicit target. Building a distributable archive is a supported operation; casually building the compiler from source is a project of its own.

## Emscripten compared with a compiler that targets wasm directly

The alternative most people weigh against Emscripten is a language toolchain that emits WebAssembly on its own, without an LLVM stage in between. The difference is architectural, not cosmetic.

With a direct-to-wasm compiler, the language's own compiler and runtime know about the wasm target from the start. There is no C ABI to imitate, no JavaScript loader generated for you, and no need to route through Clang. The trade-off is that you get that language's ecosystem only. The moment you need to link a C library, or call SDL2, or reuse an OpenGL codebase, the direct path stops being simpler.

Emscripten's approach is the opposite bet. It accepts a heavier pipeline (Clang, LLVM, Binaryen, plus a runtime and a JavaScript loader) in exchange for making an enormous body of existing portable C and C++ usable. The README's examples of ported graphical applications are the evidence that this bet pays off at scale. If your project is a small amount of new code, the direct route is less machinery. If your project is existing C or C++ that already builds with a Unix-style toolchain, Emscripten is the shorter distance.

## Licence and the cost of keeping the toolchain current

Emscripten is available under two licences, the MIT licence and the University of Illinois/NCSA Open Source License. The README describes both as permissive open source licences with little if any practical difference, and explains the dual offering historically: MIT is well known and suitable for a compiler toolchain, while the NCSA licence was offered so Emscripten's code could be integrated upstream into LLVM. The README notes that reason became less important after the switch to the LLVM wasm backend, and that LLVM itself relicensed to Apache 2.0 with exceptions. Its practical summary is that you can consider Emscripten MIT licensed, which permits commercial and non-commercial use. That is the project's own characterization; if licence terms decide anything for your organization, read LICENSE rather than a README paragraph.

On upgrades, the release cadence is visible from the tags. 6.0.7 was tagged on 2026-08-17, 6.0.8 on 2026-08-20, and 6.0.9 on 2026-09-01, and the last push to the repository was on 2026-09-20. Patch releases land within weeks of each other, so pinning an emsdk version and moving it deliberately is cheaper than tracking the tip. The repository also carries emscripten-version.txt, which is what the Makefile reads to name the distribution directory and archive, so a version string is a first-class part of the build rather than a label applied at release time.

## Conclusion

Adopt Emscripten if you already have a C or C++ codebase and need it running on the Web, in Node.js, or in a wasm runtime, and you can accept the SDK install and the Python 3.10 floor. Do not adopt it for small hand-written wasm modules or for languages with their own wasm toolchain that does not route through LLVM. Before committing, verify that your compiler front end can target wasm32-unknown-emscripten, that the emsdk version you pin matches the release you intend to ship, and that your build actually produces an artifact you can serve.

## FAQ

### What is Emscripten used for?

It compiles C and C++ to WebAssembly using LLVM and Binaryen, so existing native code can run on the Web, in Node.js, and in wasm runtimes. The README gives SDL2 and OpenGL support as the reason complex graphical applications such as Unity and Google Earth could be ported.

### Is Emscripten safe?

The material describes Emscripten as a compiler toolchain and does not make security claims about it. What it does document is the licence position: MIT and the University of Illinois/NCSA Open Source License, both permissive, with the README saying you can consider it MIT licensed.

### Does Emscripten require Python 3.10 or higher?

The repository's pyproject.toml declares requires-python = ">=3.10", so the Python tooling expects 3.10 or newer. The README's manual install path runs ./bootstrap.py, which is part of that Python tooling.

### What is the difference between WebAssembly and Emscripten?

WebAssembly is the target format; Emscripten is the toolchain that produces it from C and C++, using LLVM and Binaryen. The README notes that Emscripten output runs on the Web, in Node.js, and in wasm runtimes, and that it can also be driven by other LLVM-using compilers such as Rust's wasm32-unknown-emscripten target.

### How do I install Emscripten?

The README gives two routes: the Emscripten SDK, emsdk, which it recommends and which is documented on the website's downloads page, and a manual install from a Git checkout where you install the dependencies and run ./bootstrap.py. The developer guide on the website covers the manual path in more detail.

### Is Emscripten open source?

Yes. The README states it is available under the MIT licence and the University of Illinois/NCSA Open Source License, describing both as permissive with little practical difference between them.

## Sources

- [emscripten-core/emscripten on GitHub](https://github.com/emscripten-core/emscripten)
- [Issues](https://github.com/emscripten-core/emscripten/issues)
- [README](https://github.com/emscripten-core/emscripten/blob/main/README.md)
- [Releases](https://github.com/emscripten-core/emscripten/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/emscripten-core-emscripten
