Compile C/C++ into JavaScript with Emscripten and Docker

June 9, 2015

JavaScript continues its march towards its destiny as the universal programming language, largely due to its cross-platform portability. In previous blog posts, we demonstrated how to cross compile a large, scientific C++ library, ITK, by using cross-compilation capabilities of CMake for a number platforms,

In this post, we will go through the steps to cross-compile ITK to JavaScript and run its test suite. Over a decade of development by hundreds of top-notch research programmers is then immediately accessible to anyone with a web browser.

Edit 2016-10-10: The instructions below now use dockcross. Cross compile for other platforms by replacing dockcross/browser-asmjs with dockcross/linux-armv7, etc.

Edit 2021-07-22: For the browser cross-complilation case to WebAssembly / JavaScript, we now have a dedicated dockcross extension project: itk.js.

1) Get the cross-compiling toolchain

As with previous posts, we will use Docker to grab the toolchain:

docker pull dockcross/browser-asmjs
docker run --rm dockcross/browser-asmjs > ./dockcross-browser-asmjs
chmod +x ./dockcross-browser-asmjs

This Docker image contains of a recent version of CMake and Emscripten, along with Emscripten’s dependencies.

2) Obtain the source and create a build tree

If there is a source tree and build tree, e.g.

git clone https://itk.org/ITK.git
cd ITK
git checkout e19ddf0c830d
cd ..
mkdir -p ITK-build

3) Build and test

For the purposes of running the test suite, we will add flags for Emscripten that sacrifice run-time performance at the cost of functionality:

flags='-Wno-warn-absolute-paths --memory-init-file 0 -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1'

Inside the container, the environmental variable CMAKE_TOOLCHAIN_FILE has been configured to point to the toolchain file CMake uses to inform itself about the build environment. Pass this file to CMake during configuration.

./dockcross-browser-asmjs cmake -HITK -BITK-build \
 -G Ninja \
 "-DCMAKE_CXX_FLAGS=$flags" "-DCMAKE_C_FLAGS=$flags"

./dockcross-browser-asmjs ninja -CITK-build

The -G Ninja flag tells CMake to use our favorite generator, the Ninja generator.

Emscripten uses NodeJS as the CMAKE_CROSSCOMPILING_EMULATOR; with CMake 3.3 and later, this means NodeJS is used to also run the test suite. For NodeJS to access the file paths passed as command line arguments, the paths must be mounted to the NODEFS file system. ITK’s test driver is instrumented to mount the source tree and build tree when executed.

Start the Experimental dashboard build!

./dockcross-browser-asmjs bash -c 'cd ITK-build && ctest -D Experimental -j$(nproc)'

Enjoy ITK!

11 comments to Compile C/C++ into JavaScript with Emscripten and Docker

  1. Hi,

    Thank you for this very interesting series of posts using Docker. While I understand the interest of cross-compiling for several architectures and OSes to distribute my applications, I don’t really see a use case for the use on the browser. Could you (or someone else) give some examples of those?

    Thank you.

    J.

  2. Hi Jordi,

    Yes, please stay tuned for a following post that demonstrates the value of this functionality.

    Thanks,
    Matt

  3. Hello Matt,
    I have set up emscripten in my system and I was able to compile ITK4.8 using ’emmake make’.
    I am trying to build an external project that uses ITK. I’m having trouble in the linking stage. I have messages such as:

    WARNING root: emcc: cannot find library “ITKCommon”

    warning: unresolved symbol: _ZN3itk10DataObject13ResetPipelineEv

    It seems that the liking rules are not passed to emmake.

    Does any one know how to set up the compilation properly?

    Any comments or suggestion will be greatly appreciated.

    Cheers,

    Juan

  4. Hello Juan,

    For both, just using emmake is likely insufficient. Try using the CMAKE_TOOLCHAIN_FILE as described above for both builds.

    HTH,
    Matt

  5. I am using CMAKE_TOOLCHAIN_FILE but I still have those linking warnings.
    The execution does not work because of it.

    Juan

  6. Hi Juan,

    Please post your CMakeLists.txt for your project and the cmake command used to configure your project on the ITK mailing list, and we can follow-up there.

    Thanks,
    Matt

  7. Hi! I’m new to docker and cross compiling as well. I was able to pull the cross compiler image from docker. However, I get stuck at step 2. It says something about a dockcross script and that I can’t run it manually. I pulled the linux-arm-v7 cross compiler,too. The problem, however, still persists. Could you suggest a solution? Thanks in advance for your time.

  8. Hi Matt,
    I am new to dockcross and ITK, and I am running win10 and have installed WSL2 with Ubuntu 20.94, I run docker in that termial window. Now I meet a problem like below :

    CMake Warning at CMake/itkExternal_Eigen3.cmake:59 (find_package):
    By not providing “FindITKInternalEigen3.cmake” in CMAKE_MODULE_PATH this
    project has asked CMake to find a package configuration file provided by
    “ITKInternalEigen3”, but CMake did not find one.

    Could not find a package configuration file provided by “ITKInternalEigen3”
    with any of the following names:

    ITKInternalEigen3Config.cmake
    itkinternaleigen3-config.cmake
    

    Add the installation prefix of “ITKInternalEigen3” to CMAKE_PREFIX_PATH or
    set “ITKInternalEigen3_DIR” to a directory containing one of the above
    files. If “ITKInternalEigen3” provides a separate development package or
    SDK, be sure it has been installed.
    Call Stack (most recent call first):
    CMakeLists.txt:534 (include)

    CMake Error at CMake/itkExternal_Eigen3.cmake:61 (message):
    ITKInternalEigen3 configuration faileed

    REPORT:

    — The C compiler identification is unknown

    — The CXX compiler identification is unknown

    — Check for working C compiler: /emsdk_portable/sdk/emcc

    — Check for working C compiler: /emsdk_portable/sdk/emcc — broken

    — Configuring incomplete, errors occurred!

    See also
    “/work/ITK-build/ITKInternalEigen3-build/CMakeFiles/CMakeOutput.log”.

    See also
    “/work/ITK-build/ITKInternalEigen3-build/CMakeFiles/CMakeError.log”.

    CMake Error at /usr/share/cmake-3.13/Modules/CMakeTestCCompiler.cmake:52
    (message):

    The C compiler
    
    
    
      "/emsdk_portable/sdk/emcc"
    
    
    
    is not able to compile a simple test program.
    
    
    
    It fails with the following output:
    
    
    
      Change Dir: /work/ITK-build/ITKInternalEigen3-build/CMakeFiles/CMakeTmp
    
      Run Build Command:"/usr/bin/ninja" "cmTC_1f0ae"
      [1/2] Building C object CMakeFiles/cmTC_1f0ae.dir/testCCompiler.c.o
      FAILED: CMakeFiles/cmTC_1f0ae.dir/testCCompiler.c.o
      /emsdk_portable/sdk/emcc   -Wno-warn-absolute-paths --memory-init-file 0 -s DISABLE_EXCEPTION_CATCHING=0 ALLOW_MEMORY_GROWTH=1  -Wno-uninitialized -Wno-unused-parameter -Wall -Wcast-align -Wdisabled-optimization -Wextra -Wformat=2 -Winvalid-pch -Wno-format-nonliteral -Wpointer-arith -Wshadow -Wunused -Wwrite-strings -funit-at-a-time -Wno-strict-overflow -o CMakeFiles/cmTC_1f0ae.dir/testCCompiler.c.o   -c testCCompiler.c
      ERROR:root:ALLOW_MEMORY_GROWTH=1: No such file or directory ("ALLOW_MEMORY_GROWTH=1" was expected to be an input file, based on the commandline arguments provided)
      ninja: build stopped: subcommand failed.
    

    I download the source code from itk website , it is InsightToolkit-5.2.0.zip
    docker is running on systray but not container runs. The dockcross-browser-asmjs script said it is no intend to be run mannually.
    So, what should I do , please ?

    thanks in advance !

    William

Leave a Reply