How to Build ZXing C++ to Wasm using WASI SDK in Linux

WASI is a modular system interface, which aims to build runnable .wasm modules for any WASI-compliant runtime, not only for Node.js and web browsers. Although WASI is still in development and not stable yet, it is available for some experimental projects. In this article, I will share how to use WASI SDK to build a .wasm barcode reader module by porting ZXing C++.

Installing WASI Runtime

Both Wasmer and Wasmtime support WASI.

Wasmer

curl https://get.wasmer.io -sSfL | sh

Wasmtime

Get the source code and build wasmtime with Rust compiler.

Setting Up WASI Building Environment

Let’s get started with wasi-libc.

To build WASI Libc, you have to use clang 8 or above. If you don’t have clang installed before, you may find the latest clang version is not listed in the apt software repositories.

install clang in debian

The workaround is to add “deb http://deb.debian.org/debian/ testing main” to “/etc/apt/sources.list” and update the sources:

sudo apt update

Then the latest clang 9 is visible:

install clang 9 in debian

Install clang 9 and create relevant symlinks:

sudo apt install clang-9
sudo ln -s /usr/bin/clang-9 /usr/bin/clang
sudo ln -s /usr/bin/clang++-9 /usr/bin/clang++

Now we can build WASI Libs from the source code.

If you just want to use the toolchain, a more convenient way is to install wasi-sdk:

sudo dpkg -i wasi-sdk _7.0 _amd64.deb
export PATH=/opt/wasi-sdk/bin:$PATH
export CC=/opt/wasi-sdk/bin/clang
export CXX=/opt/wasi-sdk/bin/clang++

Create a ‘hello world’ program for the test:

#include <stdio.h>

int main()
{
    printf("hello wasi libc \n");
    return 0;
}

Build the code:

$ clang - target=wasm32-wasi - sysroot=/opt/wasi-sdk/share/wasi-sysroot/ test.c -o test.wasm

Run the app:

wasmer run test.wasm
wasmtime test.wasm

Porting ZXing C++ for WASI SDK

Get the source code of zxing-cpp.

Since the current WASI libc does not yet support C++ exceptions, we need to add -fno-exceptions to CMakeLists.txt:

set (CMAKE _CXX _FLAGS "${CMAKE _CXX _FLAGS} - target=wasm32-wasi -Wall -Wextra -fno-exceptions")

In addition, set sysroot as follows:

set (CMAKE _SYSROOT /opt/wasi-sdk/share/wasi-sysroot)

To pass the build, I have disabled all C++ exception-relevant code and adjusted the project structure.

Build the project to a wasm file:

mkdir build
cd build
cmake ..
cmake --build .

Run the app under the build folder:

qr code

$ wasmer run zxing _barcode _reader.wasm - dir=$(pwd)/../ $(pwd)/../test.png
Text: MEBKM:URL:http://en.wikipedia.org/wiki/Main _Page;;
Format: QR _CODE
Position: 190x367 205x162 422x165 405x342
EC Level: M

$ wasmtime zxing _barcode _reader.wasm - dir=$(pwd)/../ $(pwd)/../test.png
Text: MEBKM:URL:http://en.wikipedia.org/wiki/Main _Page;;
Format: QR _CODE
Position: 190x367 205x162 422x165 405x342
EC Level: M

How to Use Wapm to Publish and Run the Wasm File

Generate a wapm.toml file with init command:

$ wapm init zxing _barcode _reader

Edit wapm.toml:

[package]
name = "yushulx/zxing _barcode _reader"
version = "0.1.4"
description = "A barcode reader app built with ZXing C/C++ and wasi-sdk"
readme = "README.md"
repository = "https://github.com/yushulx/wasi-zxing-wasm"

[[module]]
name = "zxing _barcode _reader"
source = "dist/zxing _barcode _reader.wasm"
abi = "wasi"

[[command]]
name = "zxing _barcode _reader"
module = "zxing _barcode _reader"

Publish the package to wapm.io:

$ wapm login
$ wapm publish

Install the package via wapm and read barcodes from a PNG image:

$ wapm install yushulx/zxing _barcode _reader
$ wapm run zxing _barcode _reader --dir=. test.png

zxing barcode reader built with wasi

My First Wasmtime Experience in Windows 10

Reference

https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-tutorial.md

Source Code

https://github.com/yushulx/wasi-zxing-wasm