diff --git a/.github/workflows/west.yml b/.github/workflows/west.yml index 37ab54d..db2849f 100644 --- a/.github/workflows/west.yml +++ b/.github/workflows/west.yml @@ -20,43 +20,161 @@ concurrency: cancel-in-progress: true jobs: - build: + build-ffi: + strategy: + matrix: + target: + - aarch64-unknown-linux-musl + - aarch64-linux-android + - riscv64gc-unknown-linux-gnu + - x86_64-pc-windows-gnu + - x86_64-unknown-linux-musl + # TODO: figure out what's different in Mac libraries built this way + #- aarch64-apple-darwin + #- x86_64-apple-darwin + + name: west-${{ matrix.target }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: ./.github/actions/install-nix + with: + cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - uses: ./.github/actions/build-nix + with: + package: west-${{ matrix.target }} + + build-ffi-darwin: + strategy: + matrix: + config: + - os: macos-13 + lib: x86_64-darwin + target: x86_64-apple-darwin + + - os: macos-14 + lib: aarch64-darwin + target: aarch64-apple-darwin + + name: west-${{ matrix.config.target }} + runs-on: ${{ matrix.config.os }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: ./.github/actions/install-nix + with: + cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - run: nix build -L + - run: nix run -L --inputs-from . 'nixpkgs#coreutils' -- --coreutils-prog=cp -RLv ./result artifact + - uses: actions/upload-artifact@v4 + with: + name: west-${{ matrix.config.target }} + path: artifact + + build-wasm: + name: passthrough.wasm + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: ./.github/actions/install-nix + with: + cachixAuthToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - run: nix profile install --inputs-from . '.#rust' 'nixpkgs#wasm-tools' + - run: cargo build -p west-passthrough --target wasm32-unknown-unknown --release + - run: wasm-tools component new target/wasm32-unknown-unknown/release/west_passthrough.wasm -o lib/passthrough.wasm + - uses: actions/upload-artifact@v4 + with: + name: passthrough + path: lib/passthrough.wasm + + test-release: strategy: matrix: config: - #- os: ubuntu-latest - # lib: x86_64-linux - # target: x86_64-unknown-linux-musl + - os: ubuntu-latest + lib: x86_64-linux + target: x86_64-unknown-linux-musl - #- os: windows-latest - # lib: x86_64-windows - # target: x86_64-pc-windows-msvc + - os: windows-latest + lib: x86_64-windows + target: x86_64-pc-windows-gnu - - os: macos-13 - lib: x86_64-darwin - target: x86_64-apple-darwin + - os: macos-13 + lib: x86_64-darwin + target: x86_64-apple-darwin - - os: macos-14 - lib: aarch64-darwin - target: aarch64-apple-darwin + - os: macos-14 + lib: aarch64-darwin + target: aarch64-apple-darwin + name: test-release-${{ matrix.config.target }} + needs: + - build-ffi + - build-ffi-darwin + - build-wasm runs-on: ${{ matrix.config.os }} steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: passthrough + path: lib + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: west-${{ matrix.config.target }} + - run: mv lib/libwest_sys.a "lib/${{ matrix.config.lib }}/libwest.a" - uses: actions/setup-go@v5 with: go-version-file: 'go.mod' - - uses: cargo-bins/cargo-binstall@v1.10.5 - run: rustup show - #- run: cargo test --workspace --all-targets + - uses: Swatinem/rust-cache@v2.7.3 + - uses: cargo-bins/cargo-binstall@v1.10.5 - run: cargo binstall -y wasm-tools@1.217 - - run: go generate ./... + - run: go generate ./tests/go/... - run: go test ./... - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + env: + GOGC: 1 + WEST_LOG: trace + continue-on-error: ${{ matrix.config.os == 'ubuntu-latest' || matrix.config.os == 'windows-latest' }} # TODO: remove + - run: git diff --exit-code + + test-dev: + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-13 + - macos-14 + + name: test-dev-${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/setup-go@v5 with: - name: west-${{ matrix.config.target }} - path: lib/${{ matrix.config.lib }}/libwest.a - if-no-files-found: error + go-version-file: 'go.mod' + - run: rustup show + - uses: Swatinem/rust-cache@v2.7.3 + - uses: cargo-bins/cargo-binstall@v1.10.5 + - run: cargo binstall -y wasm-tools@1.217 + - run: cargo test --workspace --all-targets + - run: go generate -tags=dev ./... + - run: go test -tags=dev ./... + env: + GOGC: 1 + WEST_LOG: trace + continue-on-error: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest' }} # TODO: remove + - run: git diff --exit-code + + gofmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + - run: gofmt -w -s **/*.go + - run: git diff --exit-code cargo: strategy: @@ -64,8 +182,8 @@ jobs: check: - audit - fmt - #- nextest - #- clippy + - nextest + - clippy name: cargo ${{ matrix.check }} runs-on: ubuntu-latest @@ -84,7 +202,8 @@ jobs: strategy: matrix: include: - #- crate: passthrough + - crate: passthrough + workspace-dependencies: false - crate: sys workspace-dependencies: true @@ -167,7 +286,7 @@ jobs: release: if: startsWith(github.ref, 'refs/tags/v') needs: - - build + - test-release - cargo - crates runs-on: ubuntu-latest @@ -202,13 +321,10 @@ jobs: path: artifacts - run: | + mkdir -p ./libwest for dir in ./artifacts/west-*; do target=${dir#./artifacts/west-} - for lib_path in $(find ${dir}/lib -type f); do - lib=$(basename ${lib_path}) - mkdir -p ./${lib} - mv ${lib_path} ./${lib}/${lib}-${target}.a - done + mv ${dir}/lib/libwest_sys.a ./libwest/libwest-${target}.a done - uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8 diff --git a/build.go b/build.go index 2f5c2da..9510afd 100644 --- a/build.go +++ b/build.go @@ -6,10 +6,14 @@ package west -// #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-darwin -lwest -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-darwin -lwest -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-linux -lwest -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-linux -lwest -// #cgo windows,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-windows -lwest -// #cgo windows,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-windows -lwest +// #cgo LDFLAGS: -lwest +// #cgo linux LDFLAGS: -lm +// #cgo android,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-android +// #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-darwin +// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-darwin +// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-linux +// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-linux +// #cgo linux,riscv64 LDFLAGS: -L${SRCDIR}/lib/riscv64-linux +// #cgo windows,amd64 LDFLAGS: -L${SRCDIR}/lib/x86_64-windows +// #cgo windows,arm64 LDFLAGS: -L${SRCDIR}/lib/aarch64-windows import "C" diff --git a/build_dev.go b/build_dev.go index 44032ae..c71c840 100644 --- a/build_dev.go +++ b/build_dev.go @@ -6,5 +6,6 @@ package west -// #cgo LDFLAGS: -L${SRCDIR}/target/debug -lwest_sys +// #cgo LDFLAGS: -L${SRCDIR}/target/debug -lwest_sys +// #cgo linux LDFLAGS: -lm import "C" diff --git a/cmd/west-bindgen-go/main.go b/cmd/west-bindgen-go/main.go index e569cfe..42f76c9 100644 --- a/cmd/west-bindgen-go/main.go +++ b/cmd/west-bindgen-go/main.go @@ -243,6 +243,9 @@ func generate(path string) error { pos := pkg.Fset.Position(dir.Pos()) return fmt.Errorf("%s:%d: unexpected `go:wasmimport` directive format: %s", pos.Filename, pos.Line, dir.Text) } + if instance == "gojs" { + continue + } var callArgs []ast.Expr appendArg := func(arg *ast.Field) error { diff --git a/crates/sys/src/ffi.rs b/crates/sys/src/ffi.rs index 6cc8920..64940f6 100644 --- a/crates/sys/src/ffi.rs +++ b/crates/sys/src/ffi.rs @@ -4,7 +4,7 @@ use core::ptr::{self, null_mut}; use std::ffi::CString; use std::sync::{LazyLock, Mutex}; -use crate::{call, instantiate, Config}; +use crate::{call, instantiate, Config, Instance}; static ERROR: LazyLock>> = LazyLock::new(Mutex::default); @@ -48,7 +48,7 @@ pub extern "C" fn instance_new(config: Config) -> *mut c_void { #[no_mangle] pub extern "C" fn instance_free(instance: *mut c_void) { - unsafe { drop(Box::from_raw(instance)) } + unsafe { drop(Box::from_raw(instance.cast::())) } } #[no_mangle] diff --git a/crates/sys/west.h b/crates/sys/west.h deleted file mode 100644 index 8ed096b..0000000 --- a/crates/sys/west.h +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include - -typedef struct List_u8 { - const uint8_t *ptr; - uintptr_t len; -} List_u8; - -typedef struct Config { - struct List_u8 wasm; -} Config; - -struct Config default_config(void); - -uintptr_t error_take(char *buf, uintptr_t len); - -uintptr_t error_len(void); - -void *instance_new(struct Config config); - -void instance_free(void *instance); - -bool instance_call(void *instance_ptr, const char *instance, const char *name, void *const *args); diff --git a/lib/aarch64-android/lib_android_arm64.go b/lib/aarch64-android/lib_android_arm64.go new file mode 100644 index 0000000..55c21f8 --- /dev/null +++ b/lib/aarch64-android/lib_android_arm64.go @@ -0,0 +1 @@ +package lib diff --git a/lib/riscv64-linux/lib_linux_riscv64.go b/lib/riscv64-linux/lib_linux_riscv64.go new file mode 100644 index 0000000..55c21f8 --- /dev/null +++ b/lib/riscv64-linux/lib_linux_riscv64.go @@ -0,0 +1 @@ +package lib diff --git a/src/lib.rs b/src/lib.rs index 788e958..6df2eee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ use wasi_preview1_component_adapter_provider::{ WASI_SNAPSHOT_PREVIEW1_ADAPTER_NAME, WASI_SNAPSHOT_PREVIEW1_REACTOR_ADAPTER, }; use wasmtime::component::{Component, Linker, Resource, ResourceTable, Type, TypedFunc, Val}; -use wasmtime::{Engine, Store}; +use wasmtime::{AsContext as _, AsContextMut as _, Engine, Store}; use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiView}; use wasmtime_wasi_http::types::HostIncomingRequest; use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView}; @@ -182,25 +182,27 @@ pub struct Func<'a> { } impl Func<'_> { + #[must_use] pub fn params(&self) -> Box<[Type]> { - self.func.params(&self.store) + self.func.params(self.store.as_context()) } + #[must_use] pub fn results(&self) -> Box<[Type]> { - self.func.results(&self.store) + self.func.results(self.store.as_context()) } pub fn call(&mut self, params: &[Val], results: &mut [Val]) -> anyhow::Result<()> { self.func - .call(&mut self.store, params, results) + .call(self.store.as_context_mut(), params, results) .context("failed to call function")?; self.func - .post_return(&mut self.store) + .post_return(self.store.as_context_mut()) .context("failed to invoke `post-return`") } pub fn store(&mut self) -> &mut Store { - &mut self.store + self.store } } @@ -265,9 +267,9 @@ impl Instance { } pub fn instantiate(Config { engine, wasm }: Config) -> anyhow::Result { - let wasm = if wasmparser::Parser::is_core_wasm(&wasm) { + let wasm = if wasmparser::Parser::is_core_wasm(wasm) { let wasm = wit_component::ComponentEncoder::default() - .module(&wasm) + .module(wasm) .context("failed to set core component module")? .adapter( WASI_SNAPSHOT_PREVIEW1_ADAPTER_NAME, diff --git a/tests/components/wasi/src/lib.rs b/tests/components/wasi/src/lib.rs index bcda695..5a32ee8 100644 --- a/tests/components/wasi/src/lib.rs +++ b/tests/components/wasi/src/lib.rs @@ -39,21 +39,20 @@ impl bindings::exports::west_test::leftpad::leftpad::Guest for Handler { let rx: InputStream = in_.into_inner(); let tx: &OutputStream = out.get(); - let mut cs = zip(0..len, iter::repeat(c)).map(|(_, c)| c); + let mut cs = zip(0..len, iter::repeat(c)).flat_map(|(_, c)| String::from(c).into_bytes()); + let mut buf = Vec::default(); loop { let mut n = tx.check_write()?; if n == 0 { tx.subscribe().block(); n = tx.check_write()?; } - let s: Box = cs - .by_ref() - .take(n.try_into().unwrap_or(usize::MAX) / c.len_utf8()) - .collect(); - if s.is_empty() { + buf.extend(cs.by_ref().take(n.try_into().unwrap_or(usize::MAX))); + if buf.is_empty() { break; } - tx.write(s.as_bytes())?; + tx.write(&buf)?; + buf.clear(); } loop { let n = tx.splice(&rx, 4096)?; diff --git a/west.go b/west.go index 98efadf..d96a587 100644 --- a/west.go +++ b/west.go @@ -157,7 +157,7 @@ func NewInstance(conf *Config) (*Instance, error) { ptr := C.instance_new(C.Config{ wasm: C.List_u8{ ptr: (*C.uchar)(wasmPtr), - len: C.ulong(len(wasm)), + len: C.uintptr_t(len(wasm)), }, }) if ptr == nil { diff --git a/west_android_arm64.go b/west_android_arm64.go new file mode 100644 index 0000000..a12e633 --- /dev/null +++ b/west_android_arm64.go @@ -0,0 +1,5 @@ +//go:build !dev + +//go:generate cp ./target/release/libwest_sys.a ./lib/aarch64-android/libwest.a + +package west diff --git a/west_linux_riscv64.go b/west_linux_riscv64.go new file mode 100644 index 0000000..8bb832d --- /dev/null +++ b/west_linux_riscv64.go @@ -0,0 +1,5 @@ +//go:build !dev + +//go:generate cp ./target/release/libwest_sys.a ./lib/riscv64-linux/libwest.a + +package west