EM++(1)

πŸ‘‘ EM++(1) β€” User Commands, but make it a group chat πŸ’…βœ¨

okay so you opened the em++ manual. It's giving compiler for WASM and JavaScript energy, like g++ or clang++ but with extra sparkle. Manual name: EM++(1), User Commands section, periodt. Let's get into it, bestie.


πŸŽ€ NAME πŸŽ€

em++ - emscripten compiler for WASM and JavaScript like g++ or clang++

🌸 DESCRIPTION 🌸

Emscripten Compiler Frontend (emcc) ***

The Emscripten Compiler Frontend ("emcc") is used to call the Emscripten compiler from the command line. It's effectively a drop-in replacement for a standard compiler like gcc or clang.

Command line syntax ===================

emcc [options] file...

(Note that you will need "./emcc" if you want to run emcc from your current directory.)

The input file(s) can be either source code files that Clang can handle (C or C++), object files (produced by emcc -c), or LLVM assembly files.

Arguments ---------

Most clang options will work, as will gcc options, for example:

# Display this information emcc --help

# Display compiler version information emcc --version

To see the full list of Clang options supported on the version of Clang used by Emscripten, run clang --help.

Options that are modified or new in emcc are listed below:

  • -O0 β€” [compile+link] No optimizations (default). This is the recommended setting for starting to port a project, as it includes various assertions.

This and other optimization settings are meaningful both during compile and during link. During compile it affects LLVM optimizations, and during link it affects final optimization of the code in Binaryen as well as optimization of the JS. (For fast incremental builds -O0 is best, while for release you should link with something higher.)

  • -O1 β€” [compile+link] Simple optimizations. During the compile step these include LLVM -O1 optimizations. During the link step this omits various runtime assertions in JS that -O0 would include.
  • -O2 β€” [compile+link] Like -O1, but enables more optimizations. During link this will also enable various JavaScript optimizations.
Note: These JavaScript optimizations can reduce code size by removing things that the compiler does not see being used, in particular, parts of the runtime may be stripped if they are not exported on the Module object. The compiler is aware of code in --pre-js and --post-js, so you can safely use the runtime from there. Alternatively, you can use EXPORTED_RUNTIME_METHODS, see src/settings.js.
  • -O3 β€” [compile+link] Like -O2, but with additional optimizations that may take longer to run and may increase code size.
Note: This is a good setting for a release build.
  • -Og β€” [compile+link] Like -O1, with an additional flag to extend the liveness of variables for improved debugging. In future versions, additional optimizations might also be disabled.
  • -Os β€” [compile+link] Like -O3, but focuses more on code size (and may make tradeoffs with speed). This can affect both Wasm and JavaScript.
  • -Oz β€” [compile+link] Like -Os, but reduces code size even further, and may take longer to run. This can affect both Wasm and JavaScript.
Note: For more tips on optimizing your code, see Optimizing Code.
  • -sOPTION[=VALUE] β€” [different OPTIONs affect at different stages, most at link time] Emscripten build options. For the available options, see src/settings.js.
Note: If no value is specified it will default to 1.
Note: It is possible, with boolean options, to use the NO_ prefix to reverse their meaning. For example, -sEXIT_RUNTIME=0 is the same as -sNO_EXIT_RUNTIME=1 and vice versa. This is not recommended in most cases.
Note: Lists can be specified as comma separated strings:
-sEXPORTED_FUNCTIONS=foo,bar
Note: We also support older list formats that involve more quoting. Lists can be specified with or without quotes around each element and with or without brackets around the list. For example, all the following are equivalent:
-sEXPORTED_FUNCTIONS="foo","bar"

-sEXPORTED_FUNCTIONS=["foo","bar"]

-sEXPORTED_FUNCTIONS=[foo,bar]
Note: For lists that include brackets or quote, you need quotation marks (") around the list in most shells (to avoid errors being raised). Two examples are shown below:
-sEXPORTED_FUNCTIONS="['liblib.so']"

-s"EXPORTED_FUNCTIONS=['liblib.so']"

You can also specify that the value of an option will be read from a file. For example, the following will set EXPORTED_FUNCTIONS based on the contents of the file at path/to/file.

-sEXPORTED_FUNCTIONS=@/path/to/file
Note: * In this case the file should contain a list of symbols, one per line. For legacy use cases JSON-formatted files are also supported: e.g. ["_func1", "func2"]. * The specified file path must be absolute, not relative. * The file may contain comments where the first character of the line is '#'.
Note: Options can be specified as a single argument with or without a space between the -s and option name. e.g. -sFOO or -s FOO. It's highly recommended you use the notation without space.
  • -g β€” [compile+link] Preserve debug information.
    • When compiling to object files, this is the same as in Clang and gcc, it adds DWARF debug information to the object files.
    • When linking, this is equivalent to -g3.
  • -gseparate-dwarf[=FILENAME] β€” [same as -g3 if passed at compile time, otherwise applies at link] Preserve debug information, but in a separate file on the side. This is the same as -g, but the main file will contain no debug info. Instead, debug info will be present in a file on the side, in FILENAME if provided, otherwise the same as the Wasm file but with suffix .debug.wasm. While the main file contains no debug info, it does contain a URL to where the debug file is, so that devtools can find it. You can use -sSEPARATE_DWARF_URL=URL to customize that location (this is useful if you want to host it on a different server, for example).
  • -gsplit-dwarf β€” Enable debug fission, which creates split DWARF object files alongside the wasm object files. This option must be used together with -c.
  • -gsource-map[=inline] β€” [compile+link] [same as -g3 if passed at compile time, otherwise applies at link] Generate a source map using LLVM debug information (which must be present in object files, i.e., they should have been compiled with -g or -gsource-map).

When this option is provided, the .wasm file is updated to have a "sourceMappingURL" section. The resulting URL will have format: "<base-url>" + "<wasm-file-name>" + ".map". "<base-url>" defaults to being empty (which means the source map is served from the same directory as the Wasm file). It can be changed using --source-mapbase.

Path substitution can be applied to the referenced sources using the -sSOURCE_MAP_PREFIXES (link). If "inline" is specified, the sources content is embedded in the source map (in this case you don't need path substitution, but it comes with the cost of having a large source map file).

  • -g<level> β€” [compile+link] If used at compile time, adds progressively more DWARF information to the object file, according to the underlying behavior of clang. If used at link time, controls the level of debuggability overall. Each level builds on the previous one:
    • -g0: Make no effort to keep code debuggable.
    • -g1: Preserve whitespace in JavaScript.
    • -g2: Also preserve function names in compiled code (via the wasm name section).
    • -g3: Also keep LLVM debug info (DWARF) if there is any in the object files (this is the same as -g).
  • --profiling β€” [link] Make the output suitable for profiling. This means including function names in the wasm and JS output, and preserving whitespace in the JS output. It does not affect optimizations (to ensure that performance profiles reflect production builds). Currently this is the same as -g2.
  • --profiling-funcs β€” [link] Preserve wasm function names as in --profiling, but otherwise minify whitespace and names as we normally do in optimized builds. This is useful if you want to look at profiler results based on function names, but do not intend to read the emitted code.
  • --tracing β€” [link] Enable the Emscripten Tracing API.
  • --reproduce=<file.tar> β€” [compile+link] Write tar file containing inputs and command to reproduce invocation. When sharing this file be aware that it will include any object files, source files and libraries that were passed to the compiler.
  • --emit-symbol-map β€” [link] Save a map file between function indexes in the Wasm and function names. By storing the names on a file on the side, you can avoid shipping the names, and can still reconstruct meaningful stack traces by translating the indexes back to the names. This is a simpler format than source maps, but less detailed because it only describes function names and not source locations.
Note: When used with -sWASM=2, two symbol files are created. [name].js.symbols (with WASM symbols) and [name].wasm.js.symbols (with ASM.js symbols)
  • --emit-minification-map <file> β€” [link] In cases where emscripten performs import/export minification this option can be used to output a file that maps minified names back to their original names. The format of this file is single line per import/export of the form <minname>:<origname>.
  • -flto β€” [compile+link] Enables link-time optimizations (LTO).
  • --closure 0|1|2 β€” [link] Runs the Closure Compiler. Possible values are:
    • 0: No closure compiler (default).
    • 1: Run closure compiler. This greatly reduces the size of the support JavaScript code (everything but the WebAssembly or asm.js). Note that this increases compile time significantly.
  • 2: run the Closure compiler on all the emitted code, even on asm.js output while in asm.js mode. This can shrink your code even more, but it does block a whole bunch of asm.js optimizations, so it's not recommended unless you truly want smaller code at all costs. πŸ’…

Note:

  • Lowkey consider using -sMODULARIZE when you're using closure, because closure minifies global names into stuff that might collide with other globals. MODULARIZE wraps all the output in a function instead (peep src/settings.js for that).
  • Closure will minify the name of Module itself by default! 😭 Again, MODULARIZE fixes that. Another way around it: make sure a global variable called Module already exists before the closure-compiled code runs, because then it'll just reuse that variable. 🫢
  • --closure-args=<args> β€” [link] passes arguments through to the Closure compiler. It's basically the CLI way of doing what EMCC_CLOSURE_ARGS does.

Say you wanna hand over an externs file so the JS functions you defined in --pre-js or --post-js don't get minified β€” you'd pass Closure the externs.js file holding those public APIs, and it looks like:

--closure-args=--externs=path/to/externs.js
  • --pre-js <file> β€” [link] names a file whose contents get dropped in before the emitted code and optimized right alongside it. Heads up tho: this might not literally be the very first thing in the JS output, like if MODULARIZE is in play (check src/settings.js). If you really need it to be first, just prepend it to the output yourself after emscripten runs β€” the whole ✨point✨ of --pre-js is that it gets optimized together with the rest of the emscripten output, which unlocks better dead code elimination and minification, and honestly it should only be used for that. So like, don't have --pre-js code mess with the main output in ways that'd confuse the optimizer, e.g. using --pre-js + --post-js together to shove all the output into an inner function scope (that's what MODULARIZE is for).

--pre-js (but not --post-js) is also the move for setting stuff on the Module object, since it shows up before the JS ever looks at Module β€” for example you can define Module['print'] right in there. πŸ‘‘

  • --post-js <file> β€” [link] just like --pre-js, except it emits the file after the emitted code.
  • --extern-pre-js <file> β€” [link] names a file whose contents get prepended to the JavaScript output. This lands on the final JS output after everything else is done β€” optimization, optional MODULARIZE-ation, instrumentation like SAFE_HEAP, all of it. It's literally the same as prepending the file once emcc is finished running, just a convenient way to do it. (For comparison: --pre-js and --post-js optimize the code together with everything else, keep it in the same scope if you're running MODULARIZE, etc.)
  • --extern-post-js <file> β€” [link] like --extern-pre-js, but it goes on the end instead. πŸŽ€
  • --embed-file <file> β€” [link] names a file (with a path) to embed inside the generated WebAssembly module. The path is relative to the current directory at compile time. If you hand it a directory, its entire contents get embedded. 🌸

So if your command includes --embed-file dir/file.dat, then dir/file.dat has to exist relative to the directory where you run emcc.

Note:

Embedding files is generally more efficient than preloading, since it skips copying the file data at runtime. πŸ¦‹

For more deets on the --embed-file options, see Packaging Files.

  • --preload-file <name> β€” [link] names a file to preload before the compiled code runs asynchronously. The path is relative to the current directory at compile time. If you hand it a directory, its entire contents get embedded.

Preloaded files get stored in filename.data, where filename.html is the main file you're compiling to. To actually run your code you need both the .html and the .data. πŸ’–

Note:

This is similar to --embed-file, except it only matters when you're generating HTML (it uses asynchronous binary XHRs), or JavaScript that's gonna live in a web page.

emcc runs tools/file_packager to do the actual packaging of embedded and preloaded files. You can run the file packager yourself if you want (see Packaging using the file packager tool) β€” and then drop the file packager's output into an emcc --pre-js so it executes before your main compiled code. 🫢

For more deets on the --preload-file options, see Packaging Files.

  • --exclude-file <name> β€” [link] files and directories to be left out of --embed-file and --preload-file. Wildcards (*) are supported. ✨
  • --use-preload-plugins β€” [link] tells the file packager to run preload plugins on the files as they get loaded. That does stuff like decoding images and audio with the browser's codecs. πŸ’…
  • --shell-file <path> β€” [link] the path name to a skeleton HTML file used when you're generating HTML output. The shell file it uses needs to contain this token:
{{{ SCRIPT }}}

Note:

  • Check out html/shell.html and html/shell_minimal.html for examples.
  • This argument gets ignored if you specify a target other than HTML with the -o option.
  • --source-map-base <base-url> β€” [link] the base URL for wherever your WebAssembly source maps are gonna be published. Has to be used with -gsource-map.
  • --minify 0 β€” [same as -g1 if passed at compile time, otherwise applies at link] identical to -g1.
  • --js-transform <cmd> β€” [link] gives a <cmd> to be called on the generated code before it gets optimized. This is your moment to modify the JavaScript β€” add some code, remove some code β€” in a way that those tweaks also get optimized together with the generated code. 🌈

<cmd> gets called with the file name of the generated code as a parameter. To change the code, you can read the original data and then either append to it or overwrite it with your modified data.

<cmd> is interpreted as a space-separated list of arguments β€” so a <cmd> of python processor.py makes a Python script run. 🐍

  • --bind β€” [link] links against the embind library. Deprecated: use -lembind instead.
  • --embind-emit-tsd <path> β€” [link] generates a TypeScript definition file. Deprecated: use --emit-tsd instead.
  • --emit-tsd <path> β€” [link] generates a TypeScript definition file for the emscripten module. The definition file includes exported Wasm functions, runtime exports, and exported embind bindings (if you're using them). To generate the bindings from embind, the program gets instrumented and run in node. 😀
  • --ignore-dynamic-linking β€” [link] tells the compiler to ignore dynamic linking (you'll have to manually link to the shared libraries later on, bestie).

Normally emcc just links in code from the dynamic library as if it were statically linked β€” which fails if the same dynamic library gets linked more than once. With this option, dynamic linking is ignored, which lets the build system carry on without errors. 🫢

  • --js-library <lib> β€” [link] a JavaScript library to use on top of the ones in Emscripten's core libraries (src/library_*).
  • -v β€” [general] turns on verbose output. πŸ’€

This prints the internal sub-commands run by emscripten, and passes -v through to Clang.

Tip:

emcc -v is a genuinely useful tool for diagnosing errors. Works with or without other arguments. πŸ‘‘

  • --check β€” [general] runs Emscripten's internal sanity checks and reports any issues with the current configuration.
  • --cache <directory> β€” [general] sets the directory to use as the Emscripten cache. The Emscripten cache stores pre-built versions of libc, libcxx and other libraries. πŸ“

If you're pairing this with --clear-cache, be sure to specify this argument first.

The Emscripten cache defaults to emscripten/cache, but you can override it with the EM_CACHE environment variable or the CACHE config setting.

  • --clear-cache β€” [general] manually clears the cache of compiled Emscripten system libraries (libc++, libc++abi, libc).

Normally this happens automatically, but if you update LLVM inplace (instead of giving a new version its own directory), the caching mechanism can get confused 😭. Clearing the cache can fix weird problems related to cache incompatibilities, like Clang failing to link with library files. It clears other cached data too. After the cache is cleared, this process exits.

By default it also clears any download ports, since the ports directory usually lives inside the cache directory.

  • --use-port=<port> β€” [compile+link] uses the specified port. If you need more than one port, you can use this option multiple times, like --useport=sdl2 --use-port=bzip2. A port can carry options separated by :, like --use-port=sdl2_image:formats=png,jpg. For an external port, hand over the path to the port directly, like --use-port=/path/to/my_port.py. To get more info about a port, use the help option, like --use-port=sdl2_image:help. And to get the list of available ports, use --show-ports. ✨
  • --clear-ports β€” [general] manually clears the local copies of ports from the Emscripten Ports repos (sdl2, etc.). This also clears the cache, to get rid of their builds. 🌸

You should only need to do this if something goes wrong and you want all the ports you use downloaded and built from scratch. After this operation finishes, this process exits.

  • --show-ports
  • [general] β€” shows the list of available projects in the Emscripten Ports repos. Once this operation is done, this process will exit. like, it literally just dips on you after telling you the tea πŸ‘‹βœ¨
  • -Wwarn-absolute-paths β€” ✨ [compile+link] ✨ turns on warnings whenever you use absolute paths in your -I and -L command line directives. why do we care? bc accidental absolute paths are lowkey dangerous β€” sometimes they point at nonportable local system headers and that is not the vibe when you're cross-compiling πŸ’€
  • --emrun β€” 🌸 [link] 🌸 makes the generated output aware of the emrun command line tool. that means you get stdout, stderr and exit(returncode) capture when you run the generated app through emrun. (this enables EXIT_RUNTIME=1, so normal runtime exiting with return code passing works too 🫢)
  • --cpuprofiler β€” πŸ”₯ [link] πŸ”₯ embeds a lil simple CPU profiler right onto the generated page. use it for cursory interactive performance profiling β€” like a vibe check but for your CPU 🧚
  • --memoryprofiler β€” πŸ’œ [link] πŸ’œ embeds a memory allocation tracker onto the generated page. perfect for profiling how your app is using the Emscripten HEAP πŸ‘‘
  • --threadprofiler β€” πŸ¦‹ [link] πŸ¦‹ embeds a thread activity profiler onto the generated page. use it to profile your app's pthread usage when you're targeting multithreaded builds (-pthread) 🧡✨
  • --em-config <path> β€” πŸŽ€ [general] πŸŽ€ tells emscripten where the .emscripten configuration file lives. if you don't specify it, emscripten hunts for .emscripten first in the emscripten directory itself, and then in your home directory (~/.emscripten). you can override all of that with the EM_CONFIG environment variable πŸ’…
  • --valid-abspath <path> β€” βœ… [compile+link] βœ… notes an absolute path that's allowed, so we don't warn about it. (fr fr, absolute include paths normally get warned about, bc they might refer to your local system headers and all that β€” which is exactly what we gotta avoid when cross-compiling πŸ™ˆ)
  • -o <target> β€” 🌈 [link] 🌈 when you're linking an executable, the extension on the target file name is what decides the output type:
    • <name>.js : JavaScript (+ a separate <name>.wasm file if emitting WebAssembly). (this is the default ✨)
    • <name>.mjs : ES6 JavaScript module (+ a separate <name>.wasm file if emitting WebAssembly).
    • <name>.html : HTML + a separate JavaScript file (<name>.js; + a separate <name>.wasm file if emitting WebAssembly).
    • <name>.wasm : WebAssembly without JavaScript support code ("standalone Wasm"; this enables STANDALONE_WASM).

these rules only apply when linking. when you're compiling to object code (see -c just below) the name of the output file is irrelevant, bestie, it truly does not matter 🫠

Note: linking to a file with no extension (or a file ending in .out, like a.out) will cause the generated JavaScript file to be executable, and include a #! line to make it runnable directly. main character energy fr πŸ‘‘

  • -c β€” 🧊 [compile] 🧊 tells emcc to emit an object file, which you can then link with other object files to produce an executable. the classic pipeline moment πŸ’–
  • --output-eol windows|linux β€” πŸͺŸ/🐧 [link] πŸͺŸ/🐧 picks the line ending to generate for the text files that get outputted. pass --output-eol windows and your final output files get Windows \r\n line endings in them. pass --output-eol linux and the final generated files get written with Unix \n line endings. pick your fighter βš”οΈ
  • --cflags β€” πŸ› οΈ [other] πŸ› οΈ prints out the flags emcc would pass to clang to compile source code to object form. so you can go invoke clang yourself, and then run emcc on those outputs just for the final linking + conversion to JS. DIY queen behavior ✨

🫢 Environment variables 🫢

emcc is affected by several environment variables, bestie β€” here's the whole roster:

  • EMMAKEN_JUST_CONFIGURE [other]
  • EMCC_AUTODEBUG [compile+link]
  • EMCC_CFLAGS [compile+link]
  • EMCC_CORES [general]
  • EMCC_DEBUG [general]
  • EMCC_DEBUG_SAVE [general]
  • EMCC_FORCE_STDLIBS [link]
  • EMCC_ONLY_FORCED_STDLIBS [link]
  • EMCC_LOCAL_PORTS [compile+link]
  • EMCC_CLOSURE_ARGS [link] β€” arguments to be passed to Closure Compiler
  • EMCC_STRICT [general]
  • EMCC_SKIP_SANITY_CHECK [general]
  • EM_IGNORE_SANITY [general]
  • EM_CONFIG [general]
  • EM_LLVM_ROOT [compile+link]
  • _EMCC_CCACHE [general] β€” internal setting that is set to 1 by emsdk when integrating with ccache compiler frontend

search for os.environ in emcc.py if you wanna see how these are actually used πŸ‘€ the most interesting one is possibly EMCC_DEBUG, which forces the compiler to dump its build and temporary files to a temporary directory where you can go review them. obsessed with that one ngl πŸ’–


emcc: supported targets: llvm bitcode, WebAssembly, NOT elf β€” (autoconf likes to see elf above to enable shared object support, iykyk 😌)

okay that's the whole page bestie, we ate and left no crumbs πŸ“

and that's a wrap on EM++(1) β€” this was em++ 6.0.5+dfsg+~1.41.5, dated August 2026. go forth and compile something iconic πŸ’…βœ¨πŸ‘‘

πŸ“¦ where this page comes from