w2c2
Translates WebAssembly modules to portable C. Inspired by wabt's wasm2c.
Working towards WebAssembly as the Elusive Universal Binary:
โ different
source code โ WebAssembly โ C89 โ OSes,
(C++, Rust, ...) โ CPUs
Features
- Implements the WebAssembly Core Specification 1.0, as well as
- Passes 99.9% of the WebAssembly core semantics test suite
- Written in C89 and generates C89
- Support for many operating systems (e.g. Mac OS X, Mac OS 9, Haiku, Rhapsody, OPENSTEP, NeXTSTEP, DOS, Windows XP, etc.)
- Support for many architectures (e.g. x86, ARM, PowerPC, SPARC, PA-RISC, etc.)
- Support for big-endian systems (e.g. PowerPC, SPARC, PA-RISC, etc.)
- Streaming/single-pass compilation, low memory usage
- Separate compilation into multiple files
- Parallel compilation
- Support for multiple modules and instances
- Support for generating debug information:
- Function names, if function names are provided in the
names
custom section - Source line mapping, if DWARF line information is provided in the
.debug_line
custom section. Requires libdwarf to be installed. See instructions below.
- Function names, if function names are provided in the
- WASI implementation which is able to run clang and Python
Performance
- Coremark 1.0: ~7% slower than native
Compilation
If your system is supported by at least CMake 2.8.12, prefer using CMake to detect features. On systems without CMake you can also use Make.
w2c2
cd w2c2
cmake -B build
cmake --build build
wasi
cd wasi
cmake -B build
cmake --build build
Usage
For example, to compile module.wasm
to module.c
(and module.h
):
./w2c2 module.wasm module.c
Separate Compilation
w2c2 is able to compile a module into separate C files. This is recommended when compiling large modules and on hosts with limited resources.
For example, to compile module.wasm
(and module.h
), into multiple files with 100 functions each:
./w2c2 -f 100 module.wasm module.c
Parallel Compilation
When w2c2 was built with threading support, it is able to compile a module in parallel. By default, w2c2 spawns as many worker threads as CPU cores are available.
To manually specify the number of worker threads, pass the number using the -t
flag.
For example, to compile using 2 threads:
./w2c2 -t 2 module.wasm module.c
Examples
Coremark:
cd examples/coremark
make
./coremark
Testing
Requires Python 3 and wabt (for wast2json
).
cd tests
make gen
make run-tests
WASI Status
- args_get
- args_sizes_get
- clock_res_get
- clock_time_get
- environ_get
- environ_sizes_get
- fd_advise
- fd_allocate
- fd_close
- fd_datasync
- fd_fdstat_get
- fd_fdstat_set_flags
- fd_fdstat_set_rights
- fd_filestat_get
- fd_filestat_set_size
- fd_filestat_set_times
- fd_pread
- fd_prestat_get
- fd_prestat_dir_name
- fd_pwrite
- fd_read
- fd_readdir
- fd_renumber
- fd_seek
- fd_sync
- fd_tell
- fd_write
- path_create_directory
- path_filestat_get
- path_filestat_set_times
- path_link
- path_open
- path_readlink
- path_remove_directory
- path_rename
- path_symlink
- path_unlink_file
- poll_oneoff
- proc_exit
- random_get
- sched_yield
- sock_recv
- sock_send
- sock_shutdown
Development
To build a debug release, pass BUILD=debug
to make
.
To enable sanitizers, list them in the SANITIZERS
variable passed to make
, e.g. make BUILD=debug SANITIZERS="base clang address thread"
.
base
enables the Undefined Behavior Sanitizerclang
enables Clang-specific sanitizersthread
enables the Thread Sanitizeraddress
enables the Address Sanitizer
Installing libdwarf (required for source line mapping)
-
On Linux, try installing a package named like
libdwarf-dev
-
On macOS, you can use Homebrew and install
libdwarf
(notdwarf
!) -
w2c2 currently defaults to using the libdwarf API of >=v0.4.2. v0.6.0 has been tested to work successfully too.
-
If using a version <0.4.2, try passing
-DDWARF_OLD=1
to CMake. Version 20200114 is known to work. -
Since version 0.1.1, libdwarf ships with a pkg-config file, which CMake should be able to detect automatically.
If libdwarf cannot be automatically found by CMake, you get the following message:
-- Checking for module 'libdwarf' -- No package 'libdwarf' found
In that case you can still provide the necessary information manually by passing a variation of the following options:
-DDWARF_FOUND=1 -DDWARF_LIBRARIES=-ldwarf -DDWARF_LIBRARY_DIRS=/usr/lib -DDWARF_INCLUDE_DIRS=/usr/include/libdwarf