Emscripten CMake integration - under the hood
2021-10-18 21:52
Take any existing CMake-based C/C++ project, and chances are that you will be able to use Emscripten, and call emcmake cmake
, and end up with a JS file that you can run in the browser.
This seems a bit magical, so let’s peek under the hood.
The emcmake
shell script is a wrapper for a python script emcmake.py
. This is a small script, and the main thing it does is to call cmake
with the flag -DCMAKE_TOOLCHAIN_FILE=<path/to/Emscripten.cmake>
. Emscripten.cmake
is where a lot of the magic happens.
The CMAKE_TOOLCHAIN_FILE
variable specifies a path to a “toolchain” file, which is a collection of compilers and utilties to be used by CMake to build the project. Emscripten behaves as a cross compiler in this case.
Emscripten.cmake
does a lot of stuff, at a high level, it sets a bunch of variables so that existing C/C++ projects that are not aware of WebAssembly/JavaScript can compile just fine:
- things like
set(WIN32)
,set(APPLE)
, andset(UNIX 1)
, because a lot of times Emscripten can emulate this well enough - find where the Emscripten compiler actually is, Emscripten relies on other tools like LLVM and Binaryen, which will be found adjacent to where Emscripten is
- sets the compiler to be
emcc
, that way whenever a C/C++ file is compiled,emcc
is used, rather thanclang
orgcc
- sets various C/C++ compile features
- sets various size of data structures
- helper functions to link JS libraries into the output JS file (pre/post/link)
- sets node.js to be the executable for the output JS file
With all these setup, when we eventually ask CMake to build the project, individual C/C++ files are compiled using emcc
, which generates intermediate Wasm files, and then those files are linked again by emcc
, to generate .wasm
and .js
files.