Skip to content

Instantly share code, notes, and snippets.

@WesThorburn
Last active September 11, 2024 07:17
Show Gist options
  • Save WesThorburn/00c47b267a0e8c8431e06b14997778e4 to your computer and use it in GitHub Desktop.
Save WesThorburn/00c47b267a0e8c8431e06b14997778e4 to your computer and use it in GitHub Desktop.
Linux: Compile C++ to WebAssembly and JavaScript using Emscripten and CMake

Linux: Compile C++ to WebAssembly and JavaScript using Emscripten and CMake

Download and Install Emscripten

  • My preferred installation location is /home/user
  • Get the latest sdk: git clone https://github.com/emscripten-core/emsdk.git
  • Enter the cloned directory: cd emsdk
  • Checkout main: git checkout main
  • Install the lastest sdk tools: ./emsdk install latest
  • Activate the latest sdk tools: ./emsdk activate latest
  • Activate path variables: source ./emsdk_env.sh
  • Configure emsdk in your bash profile by running: echo 'source "/home/user/emsdk/emsdk_env.sh"' >> $HOME/.bash_profile

Your project structure

build/  
include/  
src/  
public/  
CMakeLists.txt  
  • Build directory starts empty, place header (.h) files inside /include and source (.cpp) files inside /src.

  • The public folder is where the output files will go, also keep the index.html, images and css here too.

  • CMakeLists.txt stays the root directory.

  • In the root directory, set the CMAKE Toolchain file by running: CMAKE_TOOLCHAIN_FILE=/home/user/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake Ensure you update your path with the location of your emsdk installation location

Compile to WASM (default)

cd build  
emcmake cmake ..  
make

Compile to JS

cd build  
emcmake cmake .. -DJS_ONLY=ON  
make

After Editing Files

make

After Adding/Removing Files

emcmake cmake ..  
make

If the emsdk directory is moved

  • From the project root directory run: CMAKE_TOOLCHAIN_FILE=[/path/to]/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake

  • Then from the /build directory, run: emcmake cmake ..

  • Output .js, .wasm.js and wasm.wasm files will appear in the public directory.

  • Make sure you web server serves from /public.

  • The index.html will load a.js if WebAssembly isn't supported by the client browser.

If the error: fatal error: emscripten.h: No such file or directory or The program 'emcmake' is currently not installed or The program 'emconfigure' is currently not installed is seen, check that your CMAKE_TOOLCHAIN_FILE path is correct as this is often the cause. You could also try re-installing by removing the /build directory, and run through emscripten installation again, making sure you run: source ./emsdk_env.sh at end. Then recreate the /build directory and run emcmake cmake .. and make again.

project (client)
cmake_minimum_required(VERSION 3.5.1)
option(JS_ONLY "Compiles to native JS (No WASM)" OFF)
add_definitions(-std=c++11 -O3)
include_directories(include)
file(GLOB SOURCES src/*.cpp)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/public")
add_executable(a ${SOURCES})
if(JS_ONLY)
message(STATUS "Setting compilation target to native JavaScript")
set(CMAKE_EXECUTABLE_SUFFIX ".js")
set_target_properties(a PROPERTIES LINK_FLAGS "-s WASM=0 -s EXPORTED_FUNCTIONS='[_main]'")
else(JS_ONLY)
message(STATUS "Setting compilation target to WASM")
set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js")
set_target_properties(a PROPERTIES LINK_FLAGS "-s WASM=1 -s EXPORTED_FUNCTIONS='[_main]'")
endif(JS_ONLY)
<!DOCTYPE html>
<html>
<head></head>
<body>
<script>
!function(e, t){
console.log("Loading client...");
var n = "a.wasm.js";
if(!e.WebAssembly){
n = "a.js"
}
console.log("Script set to " + n);
var o = t.createElement("script");
o.async = !0, o.type = "text/javascript", o.src = n, o.onerror = function(t) {
console.error("Script Error"), console.error(t), setTimeout(function() {
e.location.reload(!0)
}, 3e3)
};
var r = t.getElementsByTagName("script")[0];
r.parentNode.insertBefore(o, r)
}(window, document);
</script>
</body>
</html>
@scimad
Copy link

scimad commented Dec 5, 2020

Thanks a lot @WesThorburn.

@aykejriw
Copy link

[ 5%] Linking CXX executable ../output/pimWasm.js
em++: error: no input files
CMakeFiles/pimWasm.dir/build.make:373: recipe for target '../output/pimWasm.js' failed
make[2]: *** [../output/pimWasm.js] Error 1
CMakeFiles/Makefile2:82: recipe for target 'CMakeFiles/pimWasm.dir/all' failed
make[1]: *** [CMakeFiles/pimWasm.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2

I am getting above error. Can someone please guide here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment