Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
12086ef
build(ci): add riscv64 cross-compile support
rodneyosodo May 7, 2026
50af7a2
feat(example): add Go Wasmtime example
rodneyosodo May 7, 2026
f62c81d
ci(workflows): add example-build GitHub Actions workflow
rodneyosodo May 7, 2026
e956dc2
build(cgo): Move -lm from global LDFLAGS to linux targets
rodneyosodo May 7, 2026
d378ef0
ci(workflow): add Rust and wasmtime build for riscv64
rodneyosodo May 7, 2026
354351c
ci(riscv): add riscv64 build and update local.sh
rodneyosodo May 7, 2026
a043a8f
ci(test-minimal-runtime): back up riscv64 lib and download v44 libs
rodneyosodo May 7, 2026
2a779d5
ci(download-wasmtime): ensure build/linux-riscv64 exists
rodneyosodo May 7, 2026
953920e
ci: download prebuilt riscv64 wasmtime C API artifact
JeffMboya May 8, 2026
afe5a99
fix: review corrections for riscv64 support
JeffMboya May 8, 2026
bf1cd10
fix: address remaining PR review comments
JeffMboya May 8, 2026
24664d2
fix: respect TMPDIR in mktemp call for riscv64 backup
JeffMboya May 8, 2026
1a1df1b
build(example): bump wasmtime-go to v45
rodneyosodo Jun 4, 2026
6362760
ci(workflow): pin Python version to 3.8
rodneyosodo Jun 4, 2026
d2655d0
feat(build): add linux-riscv64 support
rodneyosodo Jun 4, 2026
c73b7ab
ci(local): add Zig wrapper to strip --target for riscv
rodneyosodo Jun 4, 2026
8fce0cb
ci(local): set Cargo RISC-V linker env for local build
rodneyosodo Jun 4, 2026
d9b7e9e
ci(local): Create separate Zig compile and link wrappers
rodneyosodo Jun 4, 2026
24d2344
ci(workflows): consolidate example build into main workflow
rodneyosodo Jun 9, 2026
d23a88b
ci(download-wasmtime): remove riscv64 min skip
rodneyosodo Jun 9, 2026
9905d7d
ci(build): remove riscv64 cross-compile steps and use CMake
rodneyosodo Jun 9, 2026
e128722
ci(test-minimal-runtime): remove riscv64 backup/restore logic
rodneyosodo Jun 16, 2026
8ee0751
ci: remove example directory
rodneyosodo Jun 16, 2026
51dc0d7
ci: simplify cross-compilation verification
rodneyosodo Jun 16, 2026
cd2753b
cgo: simplify riscv64 LDFLAGS
rodneyosodo Jun 16, 2026
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
51 changes: 51 additions & 0 deletions .github/workflows/main.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the test suite be built for another architecture without running it? Or can Go run tests with QEMU emulation? I'd prefer to avoid adding such weighty new CI configuration here if possible.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, Go can cross-compile the test suite without running it by using GOOS and GOARCH without executing the tests. However, go test with CGO dependencies cannot run under QEMU emulation - you’d need a native riscv64 environment or use user-mode QEMU with proper cross-compilation setup, which would be more complex than the current approach.
The current CI builds a binary to verify cross-compilation works, but we could simplify this by just running go build on the test files instead of the full test suite. Would that address your concern about avoiding weighty CI configuration?

Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,57 @@ jobs:
run: ./ci/test-minimal-runtime/test.sh
if: runner.os != 'Windows'

build-cross:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
goarch: [amd64, arm64, riscv64]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v2
with:
python-version: 3.8
- run: python ci/download-wasmtime.py

- uses: actions/setup-go@v2
with:
go-version: '1.24.x'

- name: Install cross-compiler (arm64)
if: matrix.goarch == 'arm64'
run: sudo apt-get update && sudo apt-get install -y gcc-aarch64-linux-gnu

- name: Install zig (riscv64)
if: matrix.goarch == 'riscv64'
uses: mlugg/setup-zig@v2
with:
version: 0.14.0

- name: Build test files for amd64
if: matrix.goarch == 'amd64'
env:
GOARCH: amd64
CGO_ENABLED: 1
run: go build -o /dev/null ./... 2>&1 | head -20

- name: Build test files for arm64
if: matrix.goarch == 'arm64'
env:
GOARCH: arm64
CGO_ENABLED: 1
CC: aarch64-linux-gnu-gcc
run: go build -o /dev/null ./... 2>&1 | head -20

- name: Build test files for riscv64
if: matrix.goarch == 'riscv64'
env:
GOARCH: riscv64
CGO_ENABLED: 1
CC: zig cc -target riscv64-linux-gnu
run: go build -o /dev/null ./... 2>&1 | head -20

coverage:
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ cc_library(
"@io_bazel_rules_go//go/platform:windows_amd64": ["build/windows-x86_64/libwasmtime.a"],
"@io_bazel_rules_go//go/platform:darwin_arm64": ["build/macos-aarch64/libwasmtime.a"],
"@io_bazel_rules_go//go/platform:linux_arm64": ["build/linux-aarch64/libwasmtime.a"],
"@io_bazel_rules_go//go/platform:linux_riscv64": ["build/linux-riscv64/libwasmtime.a"],
}),
hdrs = glob(["build/include/**/*.h"]),
includes = ["build/include"],
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
## Installation

```sh
go get -u github.com/bytecodealliance/wasmtime-go/v45@v45.0.1
go get -u github.com/bytecodealliance/wasmtime-go/v45@v45.0.0
```

Be sure to check out the [API documentation][api]!
Expand All @@ -34,8 +34,9 @@ This Go library uses CGO to consume the C API of the [Wasmtime
project][wasmtime] which is written in Rust. Precompiled binaries of Wasmtime
are checked into this repository on tagged releases so you won't have to install
Wasmtime locally, but it means that this project only works on Linux x86\_64,
macOS x86\_64 , and Windows x86\_64 currently. Building on other platforms will
need to arrange to build Wasmtime and use `CGO_*` env vars to compile correctly.
Linux aarch64, Linux riscv64, macOS x86\_64, macOS aarch64, and Windows x86\_64 currently.
Building on other platforms will need to arrange to build Wasmtime and use
`CGO_*` env vars to compile correctly.

This project has been tested with Go 1.13 or later.

Expand Down Expand Up @@ -130,11 +131,11 @@ $ git clone https://github.com/bytecodealliance/wasmtime-go
Next up you'll want to have a [local Wasmtime build
available](https://bytecodealliance.github.io/wasmtime/contributing-building.html).

You'll need to build at least the `wasmtime-c-api` crate, which, at the time of
this writing, would be:
You'll need to build the `wasmtime-c-api` artifact crate to produce the static
library (`libwasmtime.a`) and shared library (`libwasmtime.so`):

```sh
$ cargo build -p wasmtime-c-api
$ cargo build --release -p wasmtime-c-api --manifest-path crates/c-api/artifact/Cargo.toml
```

Once you've got that you can set up the environment of this library with:
Expand Down Expand Up @@ -166,7 +167,7 @@ Make sure everything passes at the current version.
Next run:

```
$ git ls-files | xargs sed -i 's/v16/v17/g'
$ git ls-files | xargs sed -i 's/v45/v46/g'
$ python3 ci/download-wasmtime.py
$ go test
```
Expand Down
6 changes: 5 additions & 1 deletion ci/download-wasmtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
['wasmtime-{}-x86_64-macos-c-api.tar.xz', 'macos-x86_64'],
['wasmtime-{}-aarch64-linux-c-api.tar.xz', 'linux-aarch64'],
['wasmtime-{}-aarch64-macos-c-api.tar.xz', 'macos-aarch64'],
['wasmtime-{}-riscv64gc-linux-c-api.tar.xz', 'linux-riscv64'],
]

try:
Expand Down Expand Up @@ -49,7 +50,10 @@
z.extractall()
else:
t = tarfile.open(fileobj=io.BytesIO(contents))
t.extractall()
if hasattr(tarfile, 'data_filter'):
t.extractall(filter='data')
else:
t.extractall()
Comment on lines +53 to +56

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this changing?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Python tarfile.extractall() method changed in Python 3.12+ to require a filter parameter to prevent path traversal https://docs.python.org/3.12/library/tarfile.html#tarfile.TarFile.extractall. Without the filter argument, Python 3.12+ raises a DeprecationWarning and will fail in future versions. The conditional check ensures backward compatibility with older Python versions.


src = filename.replace('.zip', '').replace('.tar.xz', '')
include_src = src + '/min/include' if args.min else src + '/include'
Expand Down
60 changes: 39 additions & 21 deletions ci/local.sh

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file unfortuantely hasn't been maintained in awhile. Nowadays can this be updated to use CMake to build the C API? That'll handle headers and such. Also, can all the risc-v specific logic be removed? I don't think any of it should be necessary here (e.g. Zig shouldn't be needed)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to use CMake for building the C API as requested

Original file line number Diff line number Diff line change
@@ -1,35 +1,53 @@
#!/bin/bash
set -euo pipefail

wasmtime=$1
if [ "$wasmtime" = "" ]; then
echo "must pass path to wasmtime"
echo "usage: $0 <path-to-wasmtime>"
exit 1
fi

# Clean and re-create "build" directory hierarchy
rm -rf build
for d in "include" "include/wasmtime" "linux-x86_64" "macos-x86_64" "windows-x86_64" "linux-aarch64" "macos-aarch64"; do
path="build/$d"
mkdir -p "$path"
name=$(basename $d)
echo "package ${name/-/_}" > "$path/empty.go"

# Build the C API with CMake (invokes cargo under the hood)
cmake -S "$wasmtime/crates/c-api" -B "$wasmtime/build-cmake" -DCMAKE_BUILD_TYPE=Release
cmake --build "$wasmtime/build-cmake"
rm -rf "$wasmtime/build-cmake"

# Create the expected directory structure with empty.go files
for d in "include" "include/wasmtime" "include/wasmtime/component" "include/wasmtime/component/types" "include/wasmtime/types" "linux-x86_64" "macos-x86_64" "windows-x86_64" "linux-aarch64" "macos-aarch64" "linux-riscv64"; do
mkdir -p "build/$d"
name=$(basename "$d" | tr - _)
echo "package $name" > "build/$d/empty.go"
done

build="$wasmtime/target/release"
if [ ! -d "$build" ]; then
build="$wasmtime/target/debug"
fi
# Use absolute path for symbolic links
build=$(cd "$build" && pwd)
# Determine host platform
host_os=$(uname -s)
host_arch=$(uname -m)
case "$host_os-$host_arch" in
Linux-x86_64) platform=linux-x86_64; rust_target=x86_64-unknown-linux-gnu ;;
Linux-aarch64) platform=linux-aarch64; rust_target=aarch64-unknown-linux-gnu ;;
Linux-riscv64) platform=linux-riscv64; rust_target=riscv64gc-unknown-linux-gnu ;;
Darwin-x86_64) platform=macos-x86_64; rust_target=x86_64-apple-darwin ;;
Darwin-arm64) platform=macos-aarch64; rust_target=aarch64-apple-darwin ;;
*) echo "Unsupported platform: $host_os-$host_arch"; exit 1 ;;
esac

if [ ! -f "$build/libwasmtime.a" ]; then
echo 'Missing libwasmtime.a. Did you `cargo build -p wasmtime-c-api`?'
# The CMake/cargo build puts artifacts in the wasmtime target directory.
# Native builds go to target/release/, cross builds to target/$rust_target/release/.
wasmtime_target_dir="$wasmtime/target/$rust_target/release"
if [ ! -d "$wasmtime_target_dir" ]; then
wasmtime_target_dir="$wasmtime/target/release"
fi
Comment on lines +24 to 41

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using the install cmake target there shouldn't be any need to rummage around in the build directory to find files. Can that be used instead? (same for headers)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMake’s install target could be used, but it would require adjusting wasmtime-go’s directory structure expectations. CMake typically installs to $prefix/lib/ and $prefix/include/, whereas the current structure expects the library directly in the platform directory (build/$platform/libwasmtime.a) and headers in a shared build/include/. Using cmake --install would give us build/$platform/lib/libwasmtime.a, requiring either moving the file or updating the ffi.go cgo flags.


for d in "linux-x86_64" "macos-x86_64" "linux-aarch64" "macos-aarch64"; do
ln -s "$build/libwasmtime.a" "build/$d/libwasmtime.a"
done
# Find the built library (may be libwasmtime.a or wasmtime.lib)
built_lib=$(find "$wasmtime_target_dir" -maxdepth 1 -name "libwasmtime*.a" -o -name "wasmtime.lib" | head -1)
if [ -z "$built_lib" ]; then
echo "Failed to find built wasmtime library in $wasmtime_target_dir"
exit 1
fi
ln -s "$built_lib" "build/$platform/libwasmtime.a"

cp "$wasmtime"/crates/c-api/include/*.h build/include
cp -r "$wasmtime"/crates/c-api/include/wasmtime build/include
cp "$wasmtime"/crates/c-api/wasm-c-api/include/*.h build/include
# Copy headers
cp "$wasmtime/crates/c-api/include/"*.h build/include/
cp -r "$wasmtime/crates/c-api/include/wasmtime" build/include/
22 changes: 17 additions & 5 deletions ci/test-minimal-runtime/test.sh
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"

WASMTIME_GO="$(cd "$SCRIPT_DIR/../.." && pwd)"
DOWNLOAD_SCRIPT="$WASMTIME_GO/ci/download-wasmtime.py"

# Step 1: Ensure the local wasmtime-go build directory has the v45 full libraries.
# The local build may contain libraries built from a different wasmtime version
# (e.g., a newer version built from local Rust source), which causes serialization format mismatches.
# We temporarily replace them with the official v45 release binaries.
trap 'rm -rf vendor module.cwasm' EXIT
(
cd "$WASMTIME_GO"
python3 "$DOWNLOAD_SCRIPT"
)

# Step 1: Create a pre-compiled module using the full Wasmtime library.
# Step 2: Create a pre-compiled module using the full Wasmtime library.
go run create_cwasm.go

# Step 2: Vendor the module, then adjust the vendored copy so it compiles
# Step 3: Vendor the module, then adjust the vendored copy so it compiles
# against the minimal Wasmtime library:
# a) Remove Go source files that call C functions absent from the min binary.
# b) Download the min static libraries over the full ones so CGO links the right lib.
DOWNLOAD_SCRIPT="$(pwd)/../download-wasmtime.py"
go mod vendor
(
cd vendor/github.com/bytecodealliance/wasmtime-go/v45
rm -f wat2wasm.go wasi.go *_feat_*.go *_feats_*.go
python3 "$DOWNLOAD_SCRIPT" --min
)

# Step 3: Test that the minimal Wasmtime binary can deserialize and run a module.
# Step 4: Test that the minimal Wasmtime binary can deserialize and run a module.
go test -count=1 .
11 changes: 6 additions & 5 deletions ffi.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package wasmtime

// #cgo CFLAGS:-I${SRCDIR}/build/include
// #cgo !windows LDFLAGS:-lwasmtime -lm -ldl -pthread
// #cgo !windows LDFLAGS:-ldl -pthread
// #cgo windows CFLAGS:-DWASM_API_EXTERN= -DWASI_API_EXTERN=
// #cgo windows LDFLAGS:-lwasmtime -luserenv -lole32 -lntdll -lws2_32 -lkernel32 -lbcrypt
// #cgo linux,amd64 LDFLAGS:-L${SRCDIR}/build/linux-x86_64
// #cgo linux,arm64 LDFLAGS:-L${SRCDIR}/build/linux-aarch64
// #cgo darwin,amd64 LDFLAGS:-L${SRCDIR}/build/macos-x86_64
// #cgo darwin,arm64 LDFLAGS:-L${SRCDIR}/build/macos-aarch64
// #cgo linux,amd64 LDFLAGS:-L${SRCDIR}/build/linux-x86_64 -lwasmtime -lm
// #cgo linux,arm64 LDFLAGS:-L${SRCDIR}/build/linux-aarch64 -lwasmtime -lm
// #cgo linux,riscv64 LDFLAGS:-L${SRCDIR}/build/linux-riscv64 -lwasmtime -lm
// #cgo darwin,amd64 LDFLAGS:-L${SRCDIR}/build/macos-x86_64 -lwasmtime
// #cgo darwin,arm64 LDFLAGS:-L${SRCDIR}/build/macos-aarch64 -lwasmtime
// #cgo windows,amd64 LDFLAGS:-L${SRCDIR}/build/windows-x86_64
// #include <wasm.h>
import "C"
Expand Down
1 change: 1 addition & 0 deletions includebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
_ "github.com/bytecodealliance/wasmtime-go/v45/build/include/wasmtime/component/types"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/include/wasmtime/types"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/linux-aarch64"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/linux-riscv64"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/linux-x86_64"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/macos-aarch64"
_ "github.com/bytecodealliance/wasmtime-go/v45/build/macos-x86_64"
Expand Down
Loading