Building Projects¶
Emscripten provides helper scripts (emconfigure, emcmake, and emmake) that configure your build system to use emcc as a drop-in replacement for gcc — in most cases the rest of your project’s current build system remains unchanged.
Integrating with a build system¶
To build using Emscripten you need to replace gcc with emcc in your build system. This is done using emconfigure (for configure/autotools projects) or emcmake (for CMake projects), which set the appropriate environment variables or CMake toolchain file so that emcc is used.
Configure / Autoconf-based projects¶
Consider the case where you normally build a configure-based project with the following commands:
./configure
make
Tip
If you’re not familiar with these build commands, the article The magic behind configure, make, make install is a good primer.
To build with Emscripten, you would instead use the following commands:
# Run emconfigure with the normal configure command as an argument.
emconfigure ./configure
# Run make to generate Wasm object files.
make
# Compile the linked code generated by make to JavaScript + WebAssembly.
# 'project.o' should be replaced with the make output for your project, and
# you may need to rename it if it isn't something emcc recognizes
# (for example, it might have a different suffix like 'project.so' or
# 'project.so.1', or no suffix like just 'project' for an executable).
# If the project output is a library, you may need to add your 'main.c' file
# here as well.
# [-Ox] represents build optimisations (discussed in the next section).
emcc [-Ox] project.o -o project.js
CMake-based projects¶
Consider the case where you normally build a CMake-based project with the following commands:
cmake -B build
cmake --build build
To build with Emscripten, use emcmake to configure CMake to use the Emscripten toolchain file:
# Run emcmake with the normal cmake command as an argument.
emcmake cmake -B build
# Build the project using cmake --build (or make).
cmake --build build
Note
emcmake automatically passes the Emscripten CMake toolchain file (-DCMAKE_TOOLCHAIN_FILE=.../Emscripten.cmake) to CMake.
Other build systems¶
If your build system doesn’t use configure or CMake, then you can omit the
configuration step and run emmake make (although then you may need to edit
the Makefile manually if compiler variables like CC or CXX are
hardcoded).
Tip
If you use emconfigure or emcmake during the configuration phase, emmake is generally not needed during the build phase because the compiler settings are stored in the generated build files. emmake is primarily needed when building projects that do not have a separate configuration phase.
Make generates Wasm object files. It may also link the object files into
libraries and/or Wasm executables. Unless such a build system has been modified
to also emit JavaScript output, you will need to run an additional emcc
command as shown above, that will emit the final runnable JavaScript and
WebAssembly.
Note
The file output from make might have a different suffix: .a for a static library archive, .so for a shared library, .o for object files (these file extensions are the same as gcc would use for the different types). Irrespective of the file extension, these files contain something that emcc can compile into the final JavaScript + WebAssembly (typically the contents will be Wasm object files, but if you build with LTO then they will contain LLVM bitcode).
Note
Some build systems may not properly emit Wasm object files using the above procedure,
and you may see is not a valid input file warnings. You can run file to
check what a file contains (also you can manually check if the contents
start with \0asm to see if they are Wasm object files, or BC if they
are LLVM bitcode). It is also worth running emmake make VERBOSE=1 which
will print out the commands it runs - you should see emcc being used, and
not the native system compiler. If emcc is not used, you may need to modify
the configure or cmake scripts.
Emscripten linker output files¶
Unless run with certain specific flags (such as -c, -S, -r, or
-shared) emcc will run the link phase which can produce more than just
one file. The set of produced files changes depending on the final flags passed
to emcc and the name of the specified output file. Here is a cheat sheet of
which files are produced under which conditions:
emcc ... -o output.htmlbuilds aoutput.htmlfile as an output, as well as an accompanyingoutput.jslauncher file, and aoutput.wasmWebAssembly file.emcc ... -o output.jsomits generating a HTML launcher file (expecting you to provide it yourself if you plan to run in browser), and produces two files,output.jsandoutput.wasm. (that can be run in e.g. node.js shell)emcc ... -o output.wasmomits generating either JavaScript or HTML launcher file, and produces a single Wasm file built in standalone mode as if the-sSTANDALONE_WASMsetting had been used. The resulting file expects to be run with the WASI ABI - in particular, as soon as you initialize the module you must manually invoke either the_startexport or (in the case of--no-entry) the_initializeexport before doing anything else with it.emcc ... -o output.{html,js} -sWASM=0causes the compiler to target JavaScript, and therefore a.wasmfile is not produced.emcc ... -o output.{html,js} --emit-symbol-mapproduces a fileoutput.{html,js}.symbolsif WebAssembly is being targeted (-sWASM=0not specified), or if JavaScript is being targeted and-Os,-Ozor-O2or higher is specified, but debug level setting is-g1or lower (i.e. if symbols minification did occur).emcc ... -o output.{html,js} -gsource-mapgenerates a source map fileoutput.wasm.map. If targeting JavaScript with-sWASM=0, the filename isoutput.{html,js}.map.emcc ... -o output.{html,js} --preload-file xxxdirective generates a preloaded MEMFS filesystem fileoutput.data.emcc ... -o output.{html,js} -sWASM={0,1} -sSINGLE_FILEmerges JavaScript and WebAssembly code in the single output fileoutput.{html,js}(in base64) to produce only one file for deployment. (If paired with--preload-file, the preloaded.datafile still exists as a separate file)
This list is not exhaustive, but illustrates most commonly used combinations.
Note
Regardless of the name of the output file emcc will always perform
linking and produce a final executable, unless a specific flags (e.g. -c)
direct it to do something else. This differs to previous behaviour where
emcc would default to combining object files (essentially assuming
-r) unless given a specific executable extension (e.g. .js or
.html).
Building projects with optimizations¶
Emscripten performs compiler optimization at two levels: each source file is optimized by LLVM as it is compiled into an object file, and then JavaScript/WebAssembly-specific optimizations are applied when converting object files into the final JavaScript/WebAssembly.
In order to properly optimize code, it is usually best to use the same optimization flags and other compiler options when compiling source to object code, and object code to JavaScript (or HTML).
Consider the examples below:
# Sub-optimal - JavaScript/WebAssembly optimizations are omitted
emcc -O2 a.cpp -c -o a.o
emcc -O2 b.cpp -c -o b.o
emcc a.o b.o -o project.js
# Sub-optimal - LLVM optimizations omitted
emcc a.cpp -c -o a.o
emcc b.cpp -c -o b.o
emcc -O2 a.o b.o -o project.js
# Usually the right thing: The same options are provided at compile and link.
emcc -O2 a.cpp -c -o a.o
emcc -O2 b.cpp -c -o b.o
emcc -O2 a.o b.o -o project.js
However, sometimes you may want slightly different optimizations on certain files:
# Optimize the first file for size, and the rest using `-O2`.
emcc -Oz a.cpp -c -o a.o
emcc -O2 b.cpp -c -o b.o
emcc -O2 a.o b.o -o project.js
Note
Unfortunately each build-system defines its own mechanisms for setting compiler and optimization methods. You will need to work out the correct approach to set the LLVM optimization flags for your system.
Some build systems have a flag like
./configure --enable-optimize.
JavaScript/WebAssembly optimizations are specified in the final step (sometimes called “link”, as that step typically also links together a bunch of files that are all compiled together into one JavaScript/WebAssembly output). For example, to compile with -O1:
# Compile the object file to JavaScript with -O1 optimizations.
emcc -O1 project.o -o project.js
Building projects with debug information¶
Building a project containing debug information requires that debug flags are specified for both the LLVM and JavaScript compilation phases.
To make Clang and LLVM emit debug information in object files you need to compile the sources with -g (exactly the same as with clang or gcc normally).
Note
Each build-system defines its own mechanisms for setting debug flags. To get Clang to emit LLVM debug information, you will need to work out the correct approach for your system.
Some build systems have a flag like
./configure --enable-debug. In CMake-based build systems, set theCMAKE_BUILD_TYPEto"Debug".
To get emcc to include the debug information present in object files when
generating the final JavaScript and WebAssembly, your final emcc command
must specify -g or one of the
-gN debug level options.
# Compile the Wasm object file to JavaScript+WebAssembly, with debug info
# -g or -gN can be used to set the debug level (N)
emcc -g project.o -o project.js
For more general information, see the topic Debugging.
Using libraries¶
Built-in support is available for a number of standard libraries: libc, libc++ and