Skip to content

Exprimental WASI support for ports/unix #13676

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/ports_unix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,17 @@ jobs:
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures

wasi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install packages
run: source tools/ci.sh && ci_unix_wasi_setup
- name: Build
run: source tools/ci.sh && ci_unix_wasi_build
- name: Run main test suite
run: source tools/ci.sh && ci_unix_wasi_run_tests
- name: Print failures
if: failure()
run: tests/run-tests.py --print-failures
21 changes: 20 additions & 1 deletion ports/unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ QSTR_DEFS += qstrdefsport.h
QSTR_GLOBAL_DEPENDENCIES += $(VARIANT_DIR)/mpconfigvariant.h

# OS name, for simple autoconfig
ifeq ($(VARIANT),wasi)
UNAME_S := wasi
else
UNAME_S := $(shell uname -s)
endif

# include py core make definitions
include $(TOP)/py/py.mk
Expand Down Expand Up @@ -107,7 +111,7 @@ CC = clang
endif
# Use clang syntax for map file
LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip
else
else ifeq ($(UNAME_S),Linux)
# Use gcc syntax for map file
LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
endif
Expand Down Expand Up @@ -303,6 +307,21 @@ $(BUILD)/lib/libffi/include/ffi.h: $(TOP)/lib/libffi/configure
PREFIX = /usr/local
BINDIR = $(DESTDIR)$(PREFIX)/bin

ifeq ($(VARIANT),wasi)
# LLVM still uses the older version of EH proposal. ("phase 3")
# Convert to the latest version of EH proposal with exnref.
$(BUILD)/$(PROG).spilled.exnref: $(BUILD)/$(PROG).spilled
$(WASM_OPT) --translate-to-exnref --enable-exception-handling \
-o $(BUILD)/$(PROG).spilled.exnref $(BUILD)/$(PROG).spilled

# Unlike emscripten, WASI doesn't provide a way to scan GC roots
# like WASM locals. Hopefully --spill-pointers can workaround it.
$(BUILD)/$(PROG).spilled: $(BUILD)/$(PROG)
$(WASM_OPT) --spill-pointers -o $(BUILD)/$(PROG).spilled $(BUILD)/$(PROG)

all: $(BUILD)/$(PROG).spilled.exnref
endif

install: $(BUILD)/$(PROG)
install -d $(BINDIR)
install $(BUILD)/$(PROG) $(BINDIR)/$(PROG)
Expand Down
2 changes: 2 additions & 0 deletions ports/unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ typedef long mp_off_t;
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)

// Enable sys.executable.
#ifndef MICROPY_PY_SYS_EXECUTABLE
#define MICROPY_PY_SYS_EXECUTABLE (1)
#endif

#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)

Expand Down
12 changes: 9 additions & 3 deletions ports/unix/unix_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@
#endif
#endif

#ifndef _WIN32
#if defined(_WIN32) || defined(__wasi__)
#define HAS_SIGNAL 0
#else
#define HAS_SIGNAL 1
#endif

#if HAS_SIGNAL
#include <signal.h>

static void sighandler(int signum) {
Expand Down Expand Up @@ -75,7 +81,7 @@ static void sighandler(int signum) {
void mp_hal_set_interrupt_char(char c) {
// configure terminal settings to (not) let ctrl-C through
if (c == CHAR_CTRL_C) {
#ifndef _WIN32
#if HAS_SIGNAL
// enable signal handler
struct sigaction sa;
sa.sa_flags = 0;
Expand All @@ -84,7 +90,7 @@ void mp_hal_set_interrupt_char(char c) {
sigaction(SIGINT, &sa, NULL);
#endif
} else {
#ifndef _WIN32
#if HAS_SIGNAL
// disable signal handler
struct sigaction sa;
sa.sa_flags = 0;
Expand Down
6 changes: 6 additions & 0 deletions ports/unix/variants/mpconfigvariant_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@
#define MICROPY_PY_OS_INCLUDEFILE "ports/unix/modos.c"
#define MICROPY_PY_OS_ERRNO (1)
#define MICROPY_PY_OS_GETENV_PUTENV_UNSETENV (1)
#ifndef MICROPY_PY_OS_SYSTEM
#define MICROPY_PY_OS_SYSTEM (1)
#endif
#define MICROPY_PY_OS_URANDOM (1)

// Enable the unix-specific "time" module.
Expand All @@ -111,11 +113,15 @@
#endif

// The "select" module is enabled by default, but disable select.select().
#ifndef MICROPY_PY_SELECT_POSIX_OPTIMISATIONS
#define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (1)
#endif
#define MICROPY_PY_SELECT_SELECT (0)

// Enable the "websocket" module.
#ifndef MICROPY_PY_WEBSOCKET
#define MICROPY_PY_WEBSOCKET (1)
#endif

// Enable the "machine" module, mostly for machine.mem*.
#define MICROPY_PY_MACHINE (1)
Expand Down
42 changes: 42 additions & 0 deletions ports/unix/variants/wasi/mpconfigvariant.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

// Set base feature level.
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES)

// WASI has different values for POLL constants.
#define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (0)

// WASI doesn't have executable or process.
#define MICROPY_PY_OS_SYSTEM (0)
#define MICROPY_PY_SYS_EXECUTABLE (0)

// Network support is limited in WASI.
// WebSocket isn't too useful without network.
#define MICROPY_PY_WEBSOCKET (0)

// Enable extra Unix features.
#include "../mpconfigvariant_common.h"
47 changes: 47 additions & 0 deletions ports/unix/variants/wasi/mpconfigvariant.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# prerequisites
#
# WASI_SDK: wasi-sdk 25.0 or later
# WASM_OPT: binaryen wasm-opt version_117 or later

# Note:
# we specify the target "--target=wasm32-wasi" explicitly below for the case
# where $CLANG is built with a configuration different from wasi-sdk.
# ditto for "-B $(WASI_SDK)/bin/".

WASI_SDK = /opt/wasi-sdk-25.0
WASI_SYSROOT = $(WASI_SDK)/share/wasi-sysroot
WASM_OPT = wasm-opt
RESOURCE_DIR = $(shell $(WASI_SDK)/bin/clang --print-resource-dir)
CLANG = $(WASI_SDK)/bin/clang

CC = $(CLANG) --sysroot $(WASI_SYSROOT) -resource-dir $(RESOURCE_DIR)
STRIP = $(WASI_SDK)/bin/strip
SIZE = $(WASI_SDK)/bin/size

CFLAGS += --target=wasm32-wasi -D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_MMAN -mllvm -wasm-enable-sjlj
LDFLAGS += --target=wasm32-wasi -lwasi-emulated-process-clocks -lwasi-emulated-signal -lwasi-emulated-mman -lsetjmp -B $(WASI_SDK)/bin/

# WASI doesn't have FFI
MICROPY_PY_FFI = 0

# When threading is enabled, micropython GC uses signals, which is
# not available on WASI.
MICROPY_PY_THREAD = 0

# Disable for now because network support is limited in WASI.
MICROPY_PY_SOCKET = 0
MICROPY_PY_SSL = 0

# ../../lib/berkeley-db-1.xx/PORT/include/db.h:40:10:
# fatal error: 'sys/cdefs.h' file not found
MICROPY_PY_BTREE = 0

# WASI doesn't have termios
MICROPY_PY_TERMIOS = 0
MICROPY_USE_READLINE = 0

# The following things might just work as they are.
# Disabled for now because I'm not interested in them.
MICROPY_VFS_FAT = 0
MICROPY_VFS_LFS1 = 0
MICROPY_VFS_LFS2 = 0
5 changes: 3 additions & 2 deletions tests/run-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,9 @@ def send_get(what):
cmdlist = [os.path.abspath(MICROPYTHON), "-X", "emit=" + args.emit]
if args.heapsize is not None:
cmdlist.extend(["-X", "heapsize=" + args.heapsize])
if sys.platform == "darwin":
cmdlist.extend(["-X", "realtime"])
if os.getenv("MICROPY_MICROPYTHON_WASM") is None:
if sys.platform == "darwin":
cmdlist.extend(["-X", "realtime"])

cwd = os.path.dirname(test_file)

Expand Down
30 changes: 30 additions & 0 deletions tools/ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,36 @@ function ci_unix_qemu_riscv64_run_tests {
(cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py)
}

function ci_unix_wasi_setup {
wget https://github.com/WebAssembly/binaryen/releases/download/version_123/binaryen-version_123-x86_64-linux.tar.gz
zcat binaryen-version_123-x86_64-linux.tar.gz | tar x
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz
zcat wasi-sdk-25.0-x86_64-linux.tar.gz | tar x
wget https://github.com/yamt/toywasm/releases/download/v68.0.0/toywasm-v68.0.0-full-ubuntu-22.04-amd64.tgz
mkdir toywasm
zcat toywasm-v68.0.0-full-ubuntu-22.04-amd64.tgz | tar -C toywasm -x
}

function ci_unix_wasi_build {
make ${MAKEOPTS} -C ports/unix VARIANT=wasi \
WASI_SDK=$(pwd -P)/wasi-sdk-25.0-x86_64-linux \
WASM_OPT=$(pwd -P)/binaryen-version_123/bin/wasm-opt \
submodules
make ${MAKEOPTS} -C ports/unix VARIANT=wasi \
WASI_SDK=$(pwd -P)/wasi-sdk-25.0-x86_64-linux \
WASM_OPT=$(pwd -P)/binaryen-version_123/bin/wasm-opt
}

function ci_unix_wasi_run_tests {
# Note: for simplicity, use absolute path where possible
# because wasi doesn't have the concept of "current directory" natively.
(cd tests && \
MICROPY_MICROPYTHON=$(pwd -P)/../tools/run-with-toywasm.sh \
TOYWASM=$(pwd -P)/../toywasm/bin/toywasm \
MICROPY_MICROPYTHON_WASM=$(pwd -P)/../ports/unix/build-wasi/micropython.spilled.exnref \
./run-tests.py -d $(pwd -P)/basics)
}

########################################################################################
# ports/windows

Expand Down
10 changes: 10 additions & 0 deletions tools/run-with-toywasm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#! /bin/sh

if [ ! -e "${MICROPY_MICROPYTHON_WASM}" ]; then
echo "MICROPY_MICROPYTHON_WASM is not set properly" >&2
exit 1
fi

exec ${TOYWASM:-toywasm} --wasi --wasi-dir=/ \
${MICROPY_MICROPYTHON_WASM} \
-- "$@"
Loading