Merge branch 'master' into wasix-core-changes

This commit is contained in:
ptitSeb
2023-01-05 21:32:17 +01:00
committed by GitHub
36 changed files with 3109 additions and 2217 deletions

View File

@ -334,7 +334,7 @@ jobs:
env:
CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross
CROSS_DOCKER_IN_DOCKER: true
CARGO_TARGET: --target aarch64-unknown-linux-gnu
CARGO_TARGET: aarch64-unknown-linux-gnu
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
PKG_CONFIG_ALLOW_CROSS: true
ENABLE_LLVM: 0
@ -345,7 +345,7 @@ jobs:
env:
CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross
CROSS_DOCKER_IN_DOCKER: true
CARGO_TARGET: --target aarch64-unknown-linux-gnu
CARGO_TARGET: aarch64-unknown-linux-gnu
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
PKG_CONFIG_ALLOW_CROSS: true
ENABLE_LLVM: 0
@ -357,7 +357,7 @@ jobs:
env:
CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross
CROSS_DOCKER_IN_DOCKER: true
CARGO_TARGET: --target aarch64-unknown-linux-gnu
CARGO_TARGET: aarch64-unknown-linux-gnu
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
PKG_CONFIG_ALLOW_CROSS: true
ENABLE_LLVM: 0
@ -367,7 +367,7 @@ jobs:
env:
CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross
CROSS_DOCKER_IN_DOCKER: true
CARGO_TARGET: --target aarch64-unknown-linux-gnu
CARGO_TARGET: aarch64-unknown-linux-gnu
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
PKG_CONFIG_ALLOW_CROSS: true
TARGET: aarch64-unknown-linux-gnu

View File

@ -155,7 +155,7 @@ jobs:
env:
CARGO_BINARY: docker run -v /var/run/docker.sock:/var/run/docker.sock -v ${GITHUB_WORKSPACE}:/project -w /project wasmer/aarch64 cross
CROSS_DOCKER_IN_DOCKER: true
CARGO_TARGET: --target aarch64-unknown-linux-gnu
CARGO_TARGET: aarch64-unknown-linux-gnu
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
PKG_CONFIG_ALLOW_CROSS: true
ENABLE_LLVM: 0
@ -207,7 +207,7 @@ jobs:
build: windows-x64,
os: windows-2019,
target: x86_64-pc-windows-msvc,
llvm_choco_version: 13.0.0
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/13.x/llvm-windows-amd64.tar.xz'
},
{
build: windows-gnu,
@ -225,7 +225,7 @@ jobs:
if: matrix.metadata.build == 'linux-x64'
run: |
sudo apt-get update -y
sudo apt-get install -y --allow-downgrades libstdc++6
sudo apt-get install -y --allow-downgrades libstdc++6 libtinfo5
sudo apt-get install --reinstall g++
- name: Set up base deps on musl
if: matrix.metadata.build == 'linux-musl'
@ -275,18 +275,6 @@ jobs:
mkdir -p package
mkdir -p package/winsdk
cp -r /tmp/winsdk/* package/winsdk
- name: Choco install LLVM
uses: crazy-max/ghaction-chocolatey@v2
if: matrix.metadata.llvm_choco_version
with:
args: install llvm --version ${{ matrix.metadata.llvm_choco_version }} --allow-downgrade
- name: Install LLVM (Choco - Windows)
if: matrix.metadata.llvm_choco_version
shell: bash
run: |
cd 'C:\Program Files\LLVM\'
LLVM_DIR=$(pwd)
echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
- name: Install LLVM (macOS Apple Silicon)
if: matrix.metadata.os == 'macos-11.0' && !matrix.metadata.llvm_url
run: |
@ -299,6 +287,7 @@ jobs:
LLVM_DIR=$(pwd)/${{ env.LLVM_DIR }}
mkdir ${LLVM_DIR}
tar xf llvm.tar.xz --strip-components=1 -C ${LLVM_DIR}
echo "ENABLE_LLVM=1" >> $GITHUB_ENV
echo "${LLVM_DIR}/bin" >> $GITHUB_PATH
echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
env:
@ -343,7 +332,7 @@ jobs:
env:
TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: --target ${{ matrix.metadata.target }}
CARGO_TARGET: ${{ matrix.metadata.target }}
- name: Build Wasmer
shell: bash
if: ${{ matrix.build-what.key == 'wasmer' && matrix.metadata.build != 'windows-gnu' }}
@ -351,7 +340,7 @@ jobs:
env:
TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: --target ${{ matrix.metadata.target }}
CARGO_TARGET: ${{ matrix.metadata.target }}
- name: Test C-API
shell: bash
if: ${{ matrix.build-what.key == 'capi' && !(matrix.metadata.build == 'linux-musl' || matrix.metadata.build == 'macos-arm' || matrix.metadata.build == 'windows-gnu') }}
@ -359,7 +348,7 @@ jobs:
env:
TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: --target ${{ matrix.metadata.target }}
CARGO_TARGET: ${{ matrix.metadata.target }}
# C-API tests were disabled for linux-musl and macos-arm (we can't run them)
- name: Test C-API integration
shell: bash
@ -368,7 +357,7 @@ jobs:
env:
TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: --target ${{ matrix.metadata.target }}
CARGO_TARGET: ${{ matrix.metadata.target }}
- name: Archive production artifacts
uses: actions/upload-artifact@v3
with:
@ -435,7 +424,7 @@ jobs:
build: windows-x64,
os: windows-2019,
target: x86_64-pc-windows-msvc,
llvm_choco_version: 13.0.0
llvm_url: 'https://github.com/wasmerio/llvm-custom-builds/releases/download/13.x/llvm-windows-amd64.tar.xz'
},
{
build: linux-musl,
@ -472,18 +461,6 @@ jobs:
with:
toolchain: 1.64
target: ${{ matrix.metadata.target }}
- name: Choco install LLVM
uses: crazy-max/ghaction-chocolatey@v2
if: matrix.metadata.llvm_choco_version
with:
args: install llvm --version ${{ matrix.metadata.llvm_choco_version }} --allow-downgrade
- name: Install LLVM (Choco - Windows)
if: matrix.metadata.llvm_choco_version
shell: bash
run: |
cd 'C:\Program Files\LLVM\'
LLVM_DIR=$(pwd)
echo "LLVM_SYS_120_PREFIX=${LLVM_DIR}" >> $GITHUB_ENV
- name: Install LLVM (macOS Apple Silicon)
if: matrix.metadata.os == 'macos-11.0' && !matrix.metadata.llvm_url
run: |
@ -528,7 +505,7 @@ jobs:
env:
TARGET: ${{ matrix.metadata.target }}
TARGET_DIR: target/${{ matrix.metadata.target }}/release
CARGO_TARGET: --target ${{ matrix.metadata.target }}
CARGO_TARGET: ${{ matrix.metadata.target }}
test_integration_cli:
name: CLI integration tests on ${{ matrix.build }}
@ -554,6 +531,9 @@ jobs:
target: x86_64-unknown-linux-musl
os: ubuntu-22.04
container: alpine:latest
- build: windows-x64
os: windows-2019
target: x86_64-pc-windows-msvc
container: ${{ matrix.container }}
env:
SCCACHE_AZURE_BLOB_CONTAINER: wasmerstoragesccacheblob
@ -610,6 +590,6 @@ jobs:
env:
TARGET: ${{ matrix.target }}
TARGET_DIR: target/${{ matrix.target }}/release
CARGO_TARGET: --target ${{ matrix.target }}
CARGO_TARGET: ${{ matrix.target }}
WAPM_DEV_TOKEN: ${{ secrets.WAPM_DEV_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

20
Cargo.lock generated
View File

@ -2253,6 +2253,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "object"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239da7f290cfa979f43f85a8efeee9a8a76d0827c356d37f9d3d7254d6b537fb"
dependencies = [
"flate2",
"memchr",
]
[[package]]
name = "once_cell"
version = "1.16.0"
@ -2333,6 +2343,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd"
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "pbkdf2"
version = "0.11.0"
@ -4313,6 +4329,8 @@ dependencies = [
"log",
"minisign",
"nuke-dir",
"object 0.30.0",
"pathdiff",
"prettytable-rs",
"regex",
"reqwest",
@ -4321,6 +4339,7 @@ dependencies = [
"semver 1.0.14",
"serde",
"serde_json",
"sha2",
"spinoff",
"tar",
"target-lexicon 0.12.5",
@ -4522,6 +4541,7 @@ version = "3.1.0"
dependencies = [
"anyhow",
"flate2",
"object 0.30.0",
"pretty_assertions",
"rand 0.8.5",
"tar",

107
Makefile
View File

@ -95,6 +95,11 @@ endif
CARGO_BINARY ?= cargo
CARGO_TARGET ?=
CARGO_TARGET_FLAG ?=
ifneq ($(CARGO_TARGET),)
CARGO_TARGET_FLAG := --target $(CARGO_TARGET)
endif
# Variables that can be overridden by the users to force to enable or
# to disable a specific compiler.
@ -358,24 +363,24 @@ all: build-wasmer build-capi
check: check-wasmer check-wasmer-wasm check-capi
check-wasmer:
$(CARGO_BINARY) check $(CARGO_TARGET) --manifest-path lib/cli/Cargo.toml $(compiler_features) --bin wasmer
$(CARGO_BINARY) check $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --bin wasmer
check-wasmer-wasm:
$(CARGO_BINARY) check --manifest-path lib/cli-compiler/Cargo.toml --target wasm32-wasi --features singlepass,cranelift --bin wasmer-compiler
check-capi:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) check $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) check $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml \
--no-default-features --features wat,compiler,wasi,middlewares $(capi_compiler_features)
build-wasmer:
$(CARGO_BINARY) build $(CARGO_TARGET) --release --manifest-path lib/cli/Cargo.toml $(compiler_features) --features="webc_runner" --bin wasmer
$(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --release --manifest-path lib/cli/Cargo.toml $(compiler_features) --features="webc_runner" --bin wasmer
build-wasmer-debug:
$(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/cli/Cargo.toml $(compiler_features) --features "webc_runner,debug" --bin wasmer
$(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --features "webc_runner,debug" --bin wasmer
bench:
$(CARGO_BINARY) bench $(CARGO_TARGET) $(compiler_features)
$(CARGO_BINARY) bench $(CARGO_TARGET_FLAG) $(compiler_features)
build-wasmer-wasm:
$(CARGO_BINARY) build --release --manifest-path lib/cli-compiler/Cargo.toml --target wasm32-wasi --features singlepass,cranelift --bin wasmer-compiler
@ -404,58 +409,58 @@ else
endif
build-docs:
$(CARGO_BINARY) doc $(CARGO_TARGET) --release $(compiler_features) --document-private-items --no-deps --workspace --exclude wasmer-c-api
$(CARGO_BINARY) doc $(CARGO_TARGET_FLAG) --release $(compiler_features) --document-private-items --no-deps --workspace --exclude wasmer-c-api
build-docs-capi:
# `wasmer-c-api` lib's name is `wasmer`. To avoid a conflict
# when generating the documentation, we rename it to its
# crate's name. Then we restore the lib's name.
sed "$(SEDI)" -e 's/name = "wasmer" # ##lib.name##/name = "wasmer_c_api" # ##lib.name##/' lib/c-api/Cargo.toml
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) doc $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,compiler,cranelift,wasi
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) doc $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --no-deps --features wat,compiler,cranelift,wasi
sed "$(SEDI)" -e 's/name = "wasmer_c_api" # ##lib.name##/name = "wasmer" # ##lib.name##/' lib/c-api/Cargo.toml
build-capi:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features)
build-capi-singlepass:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,singlepass,wasi,middlewares,webc_runner
build-capi-singlepass-universal:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,singlepass,wasi,middlewares,webc_runner
build-capi-cranelift:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,cranelift,wasi,middlewares,webc_runner
build-capi-cranelift-universal:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,cranelift,wasi,middlewares,webc_runner
build-capi-llvm:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,llvm,wasi,middlewares,webc_runner
build-capi-llvm-universal:
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
RUSTFLAGS="${RUSTFLAGS}" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,llvm,wasi,middlewares,webc_runner
# Headless (we include the minimal to be able to run)
build-capi-headless:
ifeq ($(CARGO_TARGET),)
ifeq ($(CARGO_TARGET_FLAG),)
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build --target $(HOST_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi
--no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET_FLAG)/headless
else
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi
RUSTFLAGS="${RUSTFLAGS} -C panic=abort -C link-dead-code -C lto -O -C embed-bitcode=yes" $(CARGO_BINARY) build $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET_FLAG)/headless
endif
build-capi-headless-ios:
RUSTFLAGS="${RUSTFLAGS} -C panic=abort" cargo lipo --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features compiler-headless,wasi
--no-default-features --features compiler-headless,wasi,webc_runner --target-dir target/$(CARGO_TARGET_FLAG)/headless
#####
#
@ -465,27 +470,27 @@ build-capi-headless-ios:
# test compilers
test-stage-0-wast:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features)
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --tests $(compiler_features)
# test packages
test-stage-1-test-all:
$(CARGO_BINARY) test $(CARGO_TARGET) --all --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --all --release $(exclude_tests) --exclude wasmer-c-api-test-runner --exclude wasmer-capi-examples-runner
test-stage-2-test-compiler-cranelift-nostd:
$(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/compiler-cranelift/Cargo.toml --release --no-default-features --features=std
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/compiler-cranelift/Cargo.toml --release --no-default-features --features=std
test-stage-3-test-compiler-singlepass-nostd:
$(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/compiler-singlepass/Cargo.toml --release --no-default-features --features=std
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/compiler-singlepass/Cargo.toml --release --no-default-features --features=std
test-stage-4-wasmer-cli:
$(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/cli/Cargo.toml $(compiler_features) --release
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/cli/Cargo.toml $(compiler_features) --release
# test examples
test-stage-5-test-examples:
$(CARGO_BINARY) test $(CARGO_TARGET) $(compiler_features) --features wasi --examples
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) $(compiler_features) --features wasi --examples
test-stage-6-test-examples-release:
$(CARGO_BINARY) test $(CARGO_TARGET) --release $(compiler_features) --features wasi --examples
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release $(compiler_features) --features wasi --examples
test-stage-7-capi-integration-tests:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --package wasmer-c-api-test-runner
$(CARGO_BINARY) test $(CARGO_TARGET) --release --package wasmer-capi-examples-runner
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-c-api-test-runner
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --package wasmer-capi-examples-runner
test: test-compilers test-packages test-examples
@ -517,13 +522,13 @@ test-js-wasi:
test-compilers-compat: $(foreach compiler,$(compilers),test-$(compiler))
test-singlepass-universal:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- singlepass::universal
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --tests $(compiler_features) -- singlepass::universal
test-cranelift-universal:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- cranelift::universal
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --tests $(compiler_features) -- cranelift::universal
test-llvm-universal:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- llvm::universal
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --tests $(compiler_features) -- llvm::universal
test-singlepass: $(foreach singlepass_engine,$(filter singlepass-%,$(compilers_engines)),test-$(singlepass_engine))
@ -540,7 +545,7 @@ test-capi: build-capi package-capi test-capi-ci
test-capi-crate-%:
WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-crate-//) $(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/c-api/Cargo.toml --release \
WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-crate-//) $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/c-api/Cargo.toml --release \
--no-default-features --features wat,compiler,wasi,middlewares,webc_runner $(capi_compiler_features) -- --nocapture
test-capi-integration-%:
@ -551,26 +556,26 @@ test-capi-integration-%:
cd lib/c-api/examples; WASMER_CAPI_CONFIG=$(shell echo $@ | sed -e s/test-capi-integration-//) WASMER_DIR=`pwd`/../../../package make run
test-wasi-unit:
$(CARGO_BINARY) test $(CARGO_TARGET) --manifest-path lib/wasi/Cargo.toml --release
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --manifest-path lib/wasi/Cargo.toml --release
test-wasi:
$(CARGO_BINARY) test $(CARGO_TARGET) --release --tests $(compiler_features) -- wasi::wasitests
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --release --tests $(compiler_features) -- wasi::wasitests
test-integration-cli:
rustup target add wasm32-wasi
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1
test-integration-cli-ci:
rustup target add wasm32-wasi
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner -p wasmer-integration-tests-cli -- --nocapture || $(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-cli -- --nocapture --test-threads=1 || $(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner --no-fail-fast -p wasmer-integration-tests-cli -- --nocapture --test-threads=1
test-integration-ios:
$(CARGO_BINARY) test $(CARGO_TARGET) --features webc_runner -p wasmer-integration-tests-ios
$(CARGO_BINARY) test $(CARGO_TARGET_FLAG) --features webc_runner -p wasmer-integration-tests-ios
generate-wasi-tests:
# Uncomment the following for installing the toolchain
# cargo run -p wasi-test-generator -- -s
$(CARGO_BINARY) run $(CARGO_TARGET) -p wasi-test-generator -- -g
$(CARGO_BINARY) run $(CARGO_TARGET_FLAG) -p wasi-test-generator -- -g
#####
#
# Packaging.
@ -621,24 +626,50 @@ package-capi:
cp $(TARGET_DIR)/wasmer.dll package/lib/wasmer.dll ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/wasmer.dll ]; then \
cp target/headless/$(CARGO_TARGET)/release/wasmer.dll package/lib/wasmer-headless.dll ;\
fi
if [ -f $(TARGET_DIR)/wasmer.dll.lib ]; then \
cp $(TARGET_DIR)/wasmer.dll.lib package/lib/wasmer.dll.lib ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/wasmer.dll.lib ]; then \
cp target/headless/$(CARGO_TARGET)/release/wasmer.dll.lib package/lib/wasmer-headless.dll.lib ;\
fi
if [ -f $(TARGET_DIR)/wasmer.lib ]; then \
cp $(TARGET_DIR)/wasmer.lib package/lib/wasmer.lib ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/wasmer.lib ]; then \
cp target/headless/$(CARGO_TARGET)/release/wasmer.lib package/lib/wasmer-headless.lib ;\
fi
if [ -f $(TARGET_DIR)/libwasmer.dylib ]; then \
cp $(TARGET_DIR)/libwasmer.dylib package/lib/libwasmer.dylib ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/libwasmer.dylib ]; then \
cp target/headless/$(CARGO_TARGET)/release/libwasmer.dylib package/lib/libwasmer-headless.dylib ;\
fi
if [ -f $(TARGET_DIR)/libwasmer.so ]; then \
cp $(TARGET_DIR)/libwasmer.so package/lib/libwasmer.so ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/libwasmer.so ]; then \
cp target/headless/$(CARGO_TARGET)/release/libwasmer.so package/lib/libwasmer-headless.so ;\
fi
if [ -f $(TARGET_DIR)/libwasmer.a ]; then \
cp $(TARGET_DIR)/libwasmer.a package/lib/libwasmer.a ;\
fi
if [ -f target/headless/$(CARGO_TARGET)/release/libwasmer.a ]; then \
cp target/headless/$(CARGO_TARGET)/release/libwasmer.a package/lib/libwasmer-headless.a ;\
fi
if [ -f target/$(HOST_TARGET)/release/wasmer.dll ]; then \
cp target/$(HOST_TARGET)/release/wasmer.dll package/lib/wasmer.dll ;\
fi

View File

@ -29,10 +29,10 @@ fn main() -> anyhow::Result<()> {
let module = Module::new(&store, &module_wat)?;
// The module doesn't import anything, so we create an empty import object.
let import_object = imports! {};
let instance = Instance::new(&module, &import_object)?;
let instance = Instance::new(&mut store, &module, &import_object)?;
let add_one = instance.exports.get_function("add_one")?;
let result = add_one.call(&[Value::I32(42)])?;
let result = add_one.call(&mut store, &[Value::I32(42)])?;
assert_eq!(result[0], Value::I32(43));
Ok(())

View File

@ -69,7 +69,7 @@ mod tests {
let sz = 18 * WASM_PAGE_SIZE;
let mut memory = Vec::new();
memory.resize(sz, 0);
let mut ret = VMTinyMemory {
let mut ret = Self {
mem: memory,
memory_definition: None,
};

Binary file not shown.

View File

@ -184,17 +184,17 @@ fn test_run() {
let newpath = format!("{wasmer_dll_dir};{path}");
let exe_dir = match std::path::Path::new(&manifest_dir).parent() {
Some(parent) => format!("{}", parent.display()),
None => format!("{manifest_dir}"),
None => manifest_dir.to_string(),
};
for test in TESTS.iter() {
let mut manifest_dir_parent = std::path::Path::new(&manifest_dir);
let mut manifest_dir_parent = manifest_dir_parent.parent().unwrap();
let manifest_dir_parent = std::path::Path::new(&manifest_dir);
let manifest_dir_parent = manifest_dir_parent.parent().unwrap();
let c_file_path = manifest_dir_parent.join(&format!("{test}.c"));
if target.contains("msvc") {
let mut build = cc::Build::new();
let mut build = build
let build = build
.cargo_metadata(false)
.warnings(true)
.static_crt(true)
@ -216,12 +216,12 @@ fn test_run() {
fixup_symlinks(
&[
format!("{}/include", config.wasmer_dir),
format!("{}", config.root_dir),
config.root_dir.to_string(),
],
&mut log,
&config.root_dir,
)
.expect(&format!("failed to fix symlinks: {log}"));
.unwrap_or_else(|_| panic!("failed to fix symlinks: {log}"));
println!("{log}");
}
@ -243,11 +243,11 @@ fn test_run() {
let vcvars_bat_path = find_vcvarsall(&compiler).expect("no vcvarsall.bat");
let vcvars_bat_path_parent = std::path::Path::new(&vcvars_bat_path).parent().unwrap();
let vcvars_modified_output = vcvars_bat_path_parent.join("compile-windows.bat");
let _vcvars_modified_output = vcvars_bat_path_parent.join("compile-windows.bat");
let vcvars_bat_file = std::fs::read_to_string(&vcvars_bat_path).unwrap();
let batch_formatted = format!("{}\\", vcvars_bat_path_parent.display());
let vcvars_bat_file = vcvars_bat_file
.replace("%~dp0", &batch_formatted.replace("\\", "\\\\"))
.replace("%~dp0", &batch_formatted.replace('\\', "\\\\"))
.replace("\"%1\"", "\"x64\"");
let vcvars_modified = format!("{vcvars_bat_file}\r\n{command:?}");
let path = std::path::Path::new(&manifest_dir).join("compile-windows.bat");
@ -291,7 +291,7 @@ fn test_run() {
println!("setting current dir = {exe_dir}");
let output = command
.output()
.expect(&format!("failed to run {command:#?}"));
.unwrap_or_else(|_| panic!("failed to run {command:#?}"));
if !output.status.success() {
println!("{output:#?}");
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
@ -314,18 +314,18 @@ fn test_run() {
fixup_symlinks(
&[
format!("{}/include", config.wasmer_dir),
format!("{}", config.root_dir),
config.root_dir.to_string(),
],
&mut log,
&config.root_dir,
)
.expect(&format!("failed to fix symlinks: {log}"));
.unwrap_or_else(|_| panic!("failed to fix symlinks: {log}"));
}
command.arg(&c_file_path);
if !config.wasmer_dir.is_empty() {
command.arg("-L");
command.arg(&format!("{}/lib/", config.wasmer_dir));
command.arg(&format!("-lwasmer"));
command.arg("-lwasmer");
command.arg(&format!("-Wl,-rpath,{}/lib/", config.wasmer_dir));
}
command.arg("-o");
@ -364,7 +364,7 @@ fn test_run() {
println!("execute: {command:#?}");
let output = command
.output()
.expect(&format!("failed to run {command:#?}"));
.unwrap_or_else(|_| panic!("failed to run {command:#?}"));
if !output.status.success() {
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stdout: {}", String::from_utf8_lossy(&output.stderr));
@ -433,7 +433,7 @@ fn fixup_symlinks(
let entry = entry?;
let path = entry.path();
let path_display = format!("{}", path.display());
if path_display.ends_with("h") {
if path_display.ends_with('h') {
paths_headers.push(path_display);
}
}
@ -487,7 +487,7 @@ fn find_vcvarsall(compiler: &cc::Tool) -> Option<String> {
let path = compiler.path();
let path = format!("{}", path.display());
let split = path.split("VC").nth(0)?;
let split = path.split("VC").next()?;
Some(format!("{split}VC\\Auxiliary\\Build\\vcvarsall.bat"))
}

View File

@ -125,12 +125,12 @@ fn test_ok() {
let libwasmer_so_path = format!("{}/lib/libwasmer.so", config.wasmer_dir);
let exe_dir = format!("{manifest_dir}/../wasm-c-api/example");
let path = std::env::var("PATH").unwrap_or_default();
let newpath = format!("{};{path}", format!("{wasmer_dll_dir}").replace("/", "\\"));
let newpath = format!("{};{path}", wasmer_dll_dir.replace('/', "\\"));
if target.contains("msvc") {
for test in CAPI_BASE_TESTS.iter() {
let mut build = cc::Build::new();
let mut build = build
let build = build
.cargo_metadata(false)
.warnings(true)
.static_crt(true)
@ -178,12 +178,12 @@ fn test_ok() {
&[
format!("{}/include/", config.wasmer_dir),
format!("{}/wasm-c-api/include/", config.root_dir),
format!("{}", config.root_dir),
config.root_dir.to_string(),
],
&mut log,
&config.root_dir,
)
.expect(&format!("failed to fix symlinks: {log}"));
.unwrap_or_else(|_| panic!("failed to fix symlinks: {log}"));
println!("{log}");
}
command.arg("/link");
@ -198,7 +198,7 @@ fn test_ok() {
// compile
let output = command
.output()
.expect(&format!("failed to compile {command:#?}"));
.unwrap_or_else(|_| panic!("failed to compile {command:#?}"));
if !output.status.success() {
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
@ -220,7 +220,7 @@ fn test_ok() {
println!("setting current dir = {exe_dir}");
let output = command
.output()
.expect(&format!("failed to run {command:#?}"));
.unwrap_or_else(|_| panic!("failed to run {command:#?}"));
if !output.status.success() {
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
@ -258,18 +258,18 @@ fn test_ok() {
&[
format!("{}/include/", config.wasmer_dir),
format!("{}/wasm-c-api/include/", config.root_dir),
format!("{}", config.root_dir),
config.root_dir.to_string(),
],
&mut log,
&config.root_dir,
)
.expect(&format!("failed to fix symlinks: {log}"));
.unwrap_or_else(|_| panic!("failed to fix symlinks: {log}"));
}
command.arg(&format!("{manifest_dir}/../{test}.c"));
if !config.wasmer_dir.is_empty() {
command.arg("-L");
command.arg(&format!("{}/lib/", config.wasmer_dir));
command.arg(&format!("-lwasmer"));
command.arg("-lwasmer");
command.arg(&format!("-Wl,-rpath,{}/lib/", config.wasmer_dir));
}
command.arg("-o");
@ -284,7 +284,7 @@ fn test_ok() {
.stderr(Stdio::inherit())
.current_dir(find_wasmer_base_dir())
.output()
.expect(&format!("failed to compile {command:#?}"));
.unwrap_or_else(|_| panic!("failed to compile {command:#?}"));
if !output.status.success() {
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
@ -299,7 +299,7 @@ fn test_ok() {
println!("execute: {command:#?}");
let output = command
.output()
.expect(&format!("failed to run {command:#?}"));
.unwrap_or_else(|_| panic!("failed to run {command:#?}"));
if !output.status.success() {
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
@ -391,7 +391,7 @@ fn fixup_symlinks(
let entry = entry?;
let path = entry.path();
let path_display = format!("{}", path.display());
if path_display.ends_with("h") {
if path_display.ends_with('h') {
paths_headers.push(path_display);
}
}
@ -445,7 +445,7 @@ fn find_vcvars64(compiler: &cc::Tool) -> Option<String> {
let path = compiler.path();
let path = format!("{}", path.display());
let split = path.split("VC").nth(0)?;
let split = path.split("VC").next()?;
Some(format!("{split}VC\\Auxiliary\\Build\\vcvars64.bat"))
}

View File

@ -36,7 +36,7 @@ wasmer-wasi = { version = "=3.1.0", path = "../wasi", optional = true }
wasmer-wasi-experimental-io-devices = { version = "=3.1.0", path = "../wasi-experimental-io-devices", optional = true, features = ["link_external_libs"] }
wasmer-wast = { version = "=3.1.0", path = "../../tests/lib/wast", optional = true }
wasmer-cache = { version = "=3.1.0", path = "../cache", optional = true }
wasmer-types = { version = "=3.1.0", path = "../types" }
wasmer-types = { version = "=3.1.0", path = "../types", features = ["enable-serde"] }
wasmer-registry = { version = "=4.0.0", path = "../registry" }
wasmer-object = { version = "=3.1.0", path = "../object", optional = true }
wasmer-vfs = { version = "=3.1.0", path = "../vfs", default-features = false, features = ["host-fs"] }
@ -85,6 +85,9 @@ log = "0.4.17"
minisign = "0.7.2"
semver = "1.0.14"
rpassword = "7.2.0"
pathdiff = "0.2.1"
sha2 = "0.10.6"
object = "0.30.0"
[build-dependencies]
chrono = { version = "^0.4", default-features = false, features = [ "std", "clock" ] }
@ -104,6 +107,7 @@ default = [
"compiler",
"wasmer-artifact-create",
"static-artifact-create",
"webc_runner",
]
cache = ["wasmer-cache"]
cache-blake3-pure = ["wasmer-cache/blake3-pure"]
@ -165,7 +169,6 @@ enable-serde = [
"wasmer/enable-serde",
"wasmer-vm/enable-serde",
"wasmer-compiler/enable-serde",
"wasmer-types/enable-serde",
"wasmer-wasi/enable-serde",
]

View File

@ -5,71 +5,74 @@ use wasmer_types::ModuleInfo;
use wasmer_types::{Symbol, SymbolRegistry};
/// Helper functions to simplify the usage of the static artifact.
const HELPER_FUNCTIONS: &str = r#"
wasm_byte_vec_t generate_serialized_data() {
fn gen_helper_functions(atom_name: &str, module_name: &str) -> String {
format!("
wasm_byte_vec_t generate_serialized_data_{atom_name}() {{
// We need to pass all the bytes as one big buffer so we have to do all this logic to memcpy
// the various pieces together from the generated header file.
//
// We should provide a `deseralize_vectored` function to avoid requiring this extra work.
char* byte_ptr = (char*)&WASMER_METADATA[0];
char* byte_ptr = (char*)&{module_name}[0];
size_t num_function_pointers
= sizeof(function_pointers) / sizeof(void*);
= sizeof(function_pointers_{atom_name}) / sizeof(void*);
size_t num_function_trampolines
= sizeof(function_trampolines) / sizeof(void*);
= sizeof(function_trampolines_{atom_name}) / sizeof(void*);
size_t num_dynamic_function_trampoline_pointers
= sizeof(dynamic_function_trampoline_pointers) / sizeof(void*);
= sizeof(dynamic_function_trampoline_pointers_{atom_name}) / sizeof(void*);
size_t buffer_size = module_bytes_len
+ sizeof(size_t) + sizeof(function_pointers)
+ sizeof(size_t) + sizeof(function_trampolines)
+ sizeof(size_t) + sizeof(dynamic_function_trampoline_pointers);
size_t buffer_size = module_bytes_len_{atom_name}
+ sizeof(size_t) + sizeof(function_pointers_{atom_name})
+ sizeof(size_t) + sizeof(function_trampolines_{atom_name})
+ sizeof(size_t) + sizeof(dynamic_function_trampoline_pointers_{atom_name});
char* memory_buffer = (char*) malloc(buffer_size);
size_t current_offset = 0;
memcpy(memory_buffer + current_offset, byte_ptr, module_bytes_len);
current_offset += module_bytes_len;
memcpy(memory_buffer + current_offset, byte_ptr, module_bytes_len_{atom_name});
current_offset += module_bytes_len_{atom_name};
memcpy(memory_buffer + current_offset, (void*)&num_function_pointers, sizeof(size_t));
current_offset += sizeof(size_t);
memcpy(memory_buffer + current_offset, (void*)&function_pointers[0], sizeof(function_pointers));
current_offset += sizeof(function_pointers);
memcpy(memory_buffer + current_offset, (void*)&function_pointers_{atom_name}[0], sizeof(function_pointers_{atom_name}));
current_offset += sizeof(function_pointers_{atom_name});
memcpy(memory_buffer + current_offset, (void*)&num_function_trampolines, sizeof(size_t));
current_offset += sizeof(size_t);
memcpy(memory_buffer + current_offset, (void*)&function_trampolines[0], sizeof(function_trampolines));
current_offset += sizeof(function_trampolines);
memcpy(memory_buffer + current_offset, (void*)&function_trampolines_{atom_name}[0], sizeof(function_trampolines_{atom_name}));
current_offset += sizeof(function_trampolines_{atom_name});
memcpy(memory_buffer + current_offset, (void*)&num_dynamic_function_trampoline_pointers, sizeof(size_t));
current_offset += sizeof(size_t);
memcpy(memory_buffer + current_offset, (void*)&dynamic_function_trampoline_pointers[0], sizeof(dynamic_function_trampoline_pointers));
current_offset += sizeof(dynamic_function_trampoline_pointers);
memcpy(memory_buffer + current_offset, (void*)&dynamic_function_trampoline_pointers_{atom_name}[0], sizeof(dynamic_function_trampoline_pointers_{atom_name}));
current_offset += sizeof(dynamic_function_trampoline_pointers_{atom_name});
wasm_byte_vec_t module_byte_vec = {
wasm_byte_vec_t module_byte_vec = {{
.size = buffer_size,
.data = memory_buffer,
};
}};
return module_byte_vec;
}
}}
wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* wasm_name) {
wasm_module_t* wasmer_object_module_new_{atom_name}(wasm_store_t* store, const char* wasm_name) {{
// wasm_name intentionally unused for now: will be used in the future.
wasm_byte_vec_t module_byte_vec = generate_serialized_data();
wasm_byte_vec_t module_byte_vec = generate_serialized_data_{atom_name}();
wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec);
free(module_byte_vec.data);
return module;
}}
")
}
"#;
/// Generate the header file that goes with the generated object file.
pub fn generate_header_file(
atom_name: &str,
module_info: &ModuleInfo,
symbol_registry: &dyn SymbolRegistry,
metadata_length: usize,
@ -83,7 +86,7 @@ pub fn generate_header_file(
value: "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n".to_string(),
},
CStatement::Declaration {
name: "module_bytes_len".to_string(),
name: format!("module_bytes_len_{atom_name}"),
is_extern: false,
is_const: true,
ctype: CType::U32,
@ -92,7 +95,7 @@ pub fn generate_header_file(
})),
},
CStatement::Declaration {
name: "WASMER_METADATA".to_string(),
name: symbol_registry.symbol_to_name(Symbol::Metadata),
is_extern: true,
is_const: true,
ctype: CType::Array {
@ -154,7 +157,7 @@ pub fn generate_header_file(
.collect::<Vec<_>>();
c_statements.push(CStatement::Declaration {
name: "function_pointers".to_string(),
name: format!("function_pointers_{atom_name}"),
is_extern: false,
is_const: true,
ctype: CType::Array {
@ -210,7 +213,7 @@ pub fn generate_header_file(
.collect::<Vec<_>>();
c_statements.push(CStatement::Declaration {
name: "function_trampolines".to_string(),
name: format!("function_trampolines_{atom_name}"),
is_extern: false,
is_const: true,
ctype: CType::Array {
@ -274,7 +277,7 @@ pub fn generate_header_file(
})
.collect::<Vec<_>>();
c_statements.push(CStatement::Declaration {
name: "dynamic_function_trampoline_pointers".to_string(),
name: format!("dynamic_function_trampoline_pointers_{atom_name}"),
is_extern: false,
is_const: true,
ctype: CType::Array {
@ -287,7 +290,7 @@ pub fn generate_header_file(
}
c_statements.push(CStatement::LiteralConstant {
value: HELPER_FUNCTIONS.to_string(),
value: gen_helper_functions(atom_name, &symbol_registry.symbol_to_name(Symbol::Metadata)),
});
c_statements.push(CStatement::LiteralConstant {

View File

@ -11,7 +11,8 @@ use crate::commands::CreateObj;
#[cfg(feature = "wast")]
use crate::commands::Wast;
use crate::commands::{
Add, Cache, Config, Init, Inspect, List, Login, Publish, Run, SelfUpdate, Validate, Whoami,
Add, Cache, Config, GenCHeader, Init, Inspect, List, Login, Publish, Run, SelfUpdate, Validate,
Whoami,
};
use crate::error::PrettyError;
use clap::{CommandFactory, ErrorKind, Parser};
@ -128,6 +129,9 @@ enum WasmerCLIOptions {
#[structopt(name = "create-obj", verbatim_doc_comment)]
CreateObj(CreateObj),
/// Generate the C static_defs.h header file for the input .wasm module
GenCHeader(GenCHeader),
/// Get various configuration information needed
/// to compile programs which use Wasmer
Config(Config),
@ -177,6 +181,7 @@ impl WasmerCLIOptions {
Self::List(list) => list.execute(),
Self::Login(login) => login.execute(),
Self::Publish(publish) => publish.execute(),
Self::GenCHeader(gen_heder) => gen_heder.execute(),
#[cfg(feature = "wast")]
Self::Wast(wast) => wast.execute(),
#[cfg(target_os = "linux")]
@ -234,9 +239,9 @@ fn wasmer_main_inner() -> Result<(), anyhow::Error> {
WasmerCLIOptions::Run(Run::from_binfmt_args())
} else {
match command.unwrap_or(&"".to_string()).as_ref() {
"add" | "cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "init"
| "run" | "self-update" | "validate" | "wast" | "binfmt" | "list" | "login"
| "publish" => WasmerCLIOptions::parse(),
"add" | "cache" | "compile" | "config" | "create-obj" | "create-exe" | "help"
| "gen-c-header" | "inspect" | "init" | "run" | "self-update" | "validate" | "wast"
| "binfmt" | "list" | "login" | "publish" => WasmerCLIOptions::parse(),
_ => {
WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| {
match e.kind() {

View File

@ -10,6 +10,7 @@ mod config;
mod create_exe;
#[cfg(feature = "static-artifact-create")]
mod create_obj;
mod gen_c_header;
mod init;
mod inspect;
mod list;
@ -30,15 +31,16 @@ pub use compile::*;
pub use create_exe::*;
#[cfg(feature = "static-artifact-create")]
pub use create_obj::*;
use serde::{Deserialize, Serialize};
#[cfg(feature = "wast")]
pub use wast::*;
pub use {
add::*, cache::*, config::*, init::*, inspect::*, list::*, login::*, publish::*, run::*,
self_update::*, validate::*, whoami::*,
add::*, cache::*, config::*, gen_c_header::*, init::*, inspect::*, list::*, login::*,
publish::*, run::*, self_update::*, validate::*, whoami::*,
};
/// The kind of object format to emit.
#[derive(Debug, Copy, Clone, clap::Parser)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, clap::Parser, Serialize, Deserialize)]
#[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))]
pub enum ObjectFormat {
/// Serialize the entire module into an object file.
@ -47,6 +49,12 @@ pub enum ObjectFormat {
Symbols,
}
impl Default for ObjectFormat {
fn default() -> Self {
ObjectFormat::Symbols
}
}
#[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))]
impl std::str::FromStr for ObjectFormat {
type Err = &'static str;

File diff suppressed because it is too large Load Diff

View File

@ -2,23 +2,18 @@
//! Create a standalone native executable for a given Wasm file.
use super::ObjectFormat;
use crate::{commands::PrefixerFn, store::CompilerOptions};
use crate::store::CompilerOptions;
use anyhow::{Context, Result};
use clap::Parser;
use std::env;
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
use std::path::PathBuf;
use std::process::Command;
use wasmer::*;
use wasmer_object::{emit_serialized, get_object_for_target};
#[cfg(feature = "webc_runner")]
use webc::{ParseOptions, WebCMmap};
const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_create_exe.h");
#[derive(Debug, Parser)]
/// The options for the `wasmer create-exe` subcommand
pub struct CreateObj {
@ -26,17 +21,24 @@ pub struct CreateObj {
#[clap(name = "FILE", parse(from_os_str))]
path: PathBuf,
/// Output file
/// Output file or directory if the input is a pirita file
#[clap(name = "OUTPUT_PATH", short = 'o', parse(from_os_str))]
output: PathBuf,
/// Header output file
#[clap(
name = "OUTPUT_HEADER_PATH",
long = "output-header-path",
parse(from_os_str)
)]
header_output: Option<PathBuf>,
/// Optional directorey used for debugging: if present, will
/// output the files to a debug instead of a temp directory
#[clap(long, name = "DEBUG PATH", parse(from_os_str))]
debug_dir: Option<PathBuf>,
/// Prefix for the function names in the input file in the compiled object file.
///
/// Default value = sha256 of the input file
#[clap(long, name = "PREFIX")]
prefix: Option<String>,
/// Atom name to compile when compiling multi-atom pirita files
#[clap(long, name = "ATOM")]
atom: Option<String>,
/// Compilation Target triple
///
@ -49,6 +51,7 @@ pub struct CreateObj {
/// - "aarch64-linux-gnu"
/// - "x86_64-apple-darwin"
/// - "arm64-apple-darwin"
/// - "x86_64-windows-gnu"
#[clap(long = "target")]
target_triple: Option<Triple>,
@ -57,10 +60,10 @@ pub struct CreateObj {
/// This flag accepts two options: `symbols` or `serialized`.
/// - (default) `symbols` creates an object where all functions and metadata of the module are regular object symbols
/// - `serialized` creates an object where the module is zero-copy serialized as raw data
#[clap(name = "OBJECT_FORMAT", long = "object-format", verbatim_doc_comment)]
#[clap(long = "object-format", name = "OBJECT_FORMAT", verbatim_doc_comment)]
object_format: Option<ObjectFormat>,
#[clap(short = 'm', multiple = true, number_of_values = 1)]
#[clap(long, short = 'm', multiple = true, number_of_values = 1)]
cpu_features: Vec<CpuFeature>,
#[clap(flatten)]
@ -70,191 +73,116 @@ pub struct CreateObj {
impl CreateObj {
/// Runs logic for the `create-obj` subcommand
pub fn execute(&self) -> Result<()> {
let target = self
.target_triple
.as_ref()
.map(|target_triple| {
let mut features = self
.cpu_features
.clone()
.into_iter()
.fold(CpuFeature::set(), |a, b| a | b);
// Cranelift requires SSE2, so we have this "hack" for now to facilitate
// usage
if target_triple.architecture == Architecture::X86_64 {
features |= CpuFeature::SSE2;
}
Target::new(target_triple.clone(), features)
})
.unwrap_or_default();
let path = crate::commands::create_exe::normalize_path(&format!("{}", self.path.display()));
let target_triple = self.target_triple.clone().unwrap_or_else(Triple::host);
let starting_cd = env::current_dir()?;
let wasm_module_path = starting_cd.join(&self.path);
let output_path = starting_cd.join(&self.output);
let object_format = self.object_format.unwrap_or(ObjectFormat::Symbols);
#[cfg(feature = "webc_runner")]
{
if let Ok(pirita) = WebCMmap::parse(wasm_module_path.clone(), &ParseOptions::default())
{
return self.execute_pirita(&pirita, target, output_path, object_format);
}
}
let (store, compiler_type) = self.compiler.get_store_for_target(target.clone())?;
let input_path = starting_cd.join(&path);
let temp_dir = tempfile::tempdir();
let output_directory_path = match self.debug_dir.as_ref() {
Some(s) => s.clone(),
None => temp_dir?.path().to_path_buf(),
};
std::fs::create_dir_all(&output_directory_path)?;
let object_format = self.object_format.unwrap_or_default();
let prefix = match self.prefix.as_ref() {
Some(s) => vec![s.clone()],
None => Vec::new(),
};
let target = crate::commands::create_exe::utils::target_triple_to_target(
&target_triple,
&self.cpu_features,
);
let (_, compiler_type) = self.compiler.get_store_for_target(target.clone())?;
println!("Compiler: {}", compiler_type.to_string());
println!("Target: {}", target.triple());
println!("Format: {:?}", object_format);
let header_output = self.header_output.clone().unwrap_or_else(|| {
let mut retval = self.output.clone();
retval.set_extension("h");
retval
});
let header_output_path = starting_cd.join(&header_output);
match object_format {
ObjectFormat::Serialized => {
let module = Module::from_file(&store, &wasm_module_path)
.context("failed to compile Wasm")?;
let bytes = module.serialize()?;
let mut obj = get_object_for_target(target.triple())?;
emit_serialized(&mut obj, &bytes, target.triple(), "WASMER_MODULE")?;
let mut writer = BufWriter::new(File::create(&output_path)?);
obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?;
let mut writer = BufWriter::new(File::create(&header_output_path)?);
writer.write_all(WASMER_SERIALIZED_HEADER)?;
writer.flush()?;
}
ObjectFormat::Symbols => {
let engine = store.engine();
let engine_inner = engine.inner();
let compiler = engine_inner.compiler()?;
let features = engine_inner.features();
let tunables = store.tunables();
let data: Vec<u8> = fs::read(wasm_module_path)?;
let prefixer: Option<PrefixerFn> = None;
let (module_info, obj, metadata_length, symbol_registry) =
Artifact::generate_object(
compiler, &data, prefixer, &target, tunables, features,
)?;
let header_file_src = crate::c_gen::staticlib_header::generate_header_file(
&module_info,
&*symbol_registry,
metadata_length,
);
let mut writer = BufWriter::new(File::create(&output_path)?);
obj.write_stream(&mut writer)
.map_err(|err| anyhow::anyhow!(err.to_string()))?;
writer.flush()?;
let mut writer = BufWriter::new(File::create(&header_output_path)?);
writer.write_all(header_file_src.as_bytes())?;
writer.flush()?;
}
}
eprintln!(
"✔ Object compiled successfully to `{}` and the header file was generated at `{}`.",
self.output.display(),
header_output.display(),
);
Ok(())
}
#[cfg(feature = "webc_runner")]
fn execute_pirita(
&self,
file: &WebCMmap,
target: Target,
output_path: PathBuf,
object_format: ObjectFormat,
) -> Result<()> {
if output_path.exists() {
if output_path.is_dir() {
nuke_dir::nuke_dir(&output_path)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
}
} else {
let _ = std::fs::create_dir_all(&output_path)?;
}
println!(
"outputting create-obj to directory {}",
output_path.display()
);
let (store, _) = self.compiler.get_store_for_target(target.clone())?;
crate::commands::create_exe::CreateExe::create_objs_pirita(
&store,
file,
&target,
&output_path,
let atoms =
if let Ok(pirita) = WebCMmap::parse(input_path.clone(), &ParseOptions::default()) {
crate::commands::create_exe::compile_pirita_into_directory(
&pirita,
&output_directory_path,
&self.compiler,
&self.cpu_features,
&target_triple,
object_format,
)?;
Ok(())
}
&prefix,
crate::commands::AllowMultiWasm::Reject(self.atom.clone()),
self.debug_dir.is_some(),
)
} else {
crate::commands::create_exe::prepare_directory_from_single_wasm_file(
&input_path,
&output_directory_path,
&self.compiler,
&target_triple,
&self.cpu_features,
object_format,
&prefix,
self.debug_dir.is_some(),
)
}?;
// Copy output files into target path, depending on whether
// there are one or many files being compiled
let file_paths = std::fs::read_dir(output_directory_path.join("atoms"))
.map_err(|e| {
anyhow::anyhow!(
"could not read {}: {e}",
output_directory_path.join("atoms").display()
)
})?
.filter_map(|path| path.ok()?.path().canonicalize().ok())
.collect::<Vec<_>>();
if file_paths.is_empty() {
return Err(anyhow::anyhow!(
"could not compile object file: no output objects in {}",
output_directory_path.join("atoms").display()
));
}
fn link(
output_path: PathBuf,
object_path: PathBuf,
header_code_path: PathBuf,
) -> anyhow::Result<()> {
let libwasmer_path = get_libwasmer_path()?
.canonicalize()
.context("Failed to find libwasmer")?;
println!(
"link output {:?}",
Command::new("cc")
.arg(&header_code_path)
.arg(&format!("-L{}", libwasmer_path.display()))
//.arg(&format!("-I{}", header_code_path.display()))
.arg("-pie")
.arg("-o")
.arg("header_obj.o")
.output()?
);
//ld -relocatable a.o b.o -o c.o
println!(
"link output {:?}",
Command::new("ld")
.arg("-relocatable")
.arg(&object_path)
.arg("header_obj.o")
.arg("-o")
.arg(&output_path)
.output()?
);
Ok(())
if file_paths.len() == 1 {
if let Some(parent) = self.output.parent() {
std::fs::create_dir_all(parent)?;
}
/// path to the static libwasmer
fn get_libwasmer_path() -> anyhow::Result<PathBuf> {
let mut path = get_wasmer_dir()?;
path.push("lib");
// TODO: prefer headless Wasmer if/when it's a separate library.
#[cfg(not(windows))]
path.push("libwasmer.a");
#[cfg(windows)]
path.push("wasmer.lib");
Ok(path)
}
fn get_wasmer_dir() -> anyhow::Result<PathBuf> {
Ok(PathBuf::from(
env::var("WASMER_DIR")
.or_else(|e| {
option_env!("WASMER_INSTALL_PREFIX")
.map(str::to_string)
.ok_or(e)
})
.context("Trying to read env var `WASMER_DIR`")?,
std::fs::copy(
std::env::current_dir().unwrap().join(&file_paths[0]),
std::env::current_dir().unwrap().join(&self.output),
)
.map_err(|e| {
anyhow::anyhow!(
"{} -> {}: {e}",
&file_paths[0].display(),
self.output.display()
)
})?;
} else {
let keys = atoms
.iter()
.map(|(name, _)| name.clone())
.collect::<Vec<_>>();
return Err(anyhow::anyhow!(
"where <ATOM> is one of: {}",
keys.join(", ")
))
.context(anyhow::anyhow!(
"note: use --atom <ATOM> to specify which atom to compile"
))
.context(anyhow::anyhow!(
"cannot compile more than one atom at a time"
));
}
let output_file = self.output.canonicalize().unwrap().display().to_string();
let output_file = output_file
.strip_prefix(r"\\?\")
.unwrap_or(&output_file)
.to_string();
eprintln!("✔ Object compiled successfully to `{output_file}`");
Ok(())
}
}

View File

@ -0,0 +1,137 @@
use crate::store::CompilerOptions;
use anyhow::Context;
use clap::Parser;
use std::path::PathBuf;
use wasmer_compiler::Artifact;
use wasmer_types::compilation::symbols::ModuleMetadataSymbolRegistry;
use wasmer_types::{CpuFeature, MetadataHeader, Triple};
use webc::WebC;
use super::normalize_path;
#[derive(Debug, Parser)]
/// The options for the `wasmer gen-c-header` subcommand
pub struct GenCHeader {
/// Input file
#[clap(name = "FILE", parse(from_os_str))]
path: PathBuf,
/// Prefix hash (default: SHA256 of input .wasm file)
#[clap(long)]
prefix: Option<String>,
/// For pirita files: optional atom name to compile
#[clap(long)]
atom: Option<String>,
/// Output file
#[clap(name = "OUTPUT PATH", short = 'o', parse(from_os_str))]
output: PathBuf,
/// Compilation Target triple
///
/// Accepted target triple values must follow the
/// ['target_lexicon'](https://crates.io/crates/target-lexicon) crate format.
///
/// The recommended targets we try to support are:
///
/// - "x86_64-linux-gnu"
/// - "aarch64-linux-gnu"
/// - "x86_64-apple-darwin"
/// - "arm64-apple-darwin"
/// - "x86_64-windows-gnu"
#[clap(long = "target")]
target_triple: Option<Triple>,
#[clap(long, short = 'm', multiple = true, number_of_values = 1)]
cpu_features: Vec<CpuFeature>,
}
impl GenCHeader {
/// Runs logic for the `gen-c-header` subcommand
pub fn execute(&self) -> Result<(), anyhow::Error> {
let path = crate::commands::normalize_path(&format!("{}", self.path.display()));
let mut file = std::fs::read(&path)
.map_err(|e| anyhow::anyhow!("{e}"))
.with_context(|| anyhow::anyhow!("{path}"))?;
let prefix = match self.prefix.as_deref() {
Some(s) => s.to_string(),
None => crate::commands::PrefixMapCompilation::hash_for_bytes(&file),
};
if let Ok(pirita) = WebC::parse(&file, &webc::ParseOptions::default()) {
let atoms = pirita
.manifest
.atoms
.iter()
.map(|a| a.0.clone())
.collect::<Vec<_>>();
if atoms.len() == 1 {
file = pirita
.get_atom(&pirita.get_package_name(), &atoms[0])
.unwrap()
.to_vec();
} else if self.atom.is_none() {
return Err(anyhow::anyhow!("-> note: available atoms are: {}", atoms.join(", ")))
.context(anyhow::anyhow!("file has multiple atoms, please specify which atom to generate the header file for"))?;
} else {
file = pirita
.get_atom(&pirita.get_package_name(), &atoms[0])
.map_err(|_| {
anyhow::anyhow!("-> note: available atoms are: {}", atoms.join(", "))
})
.context(anyhow::anyhow!(
"could not get atom {} from file (invalid atom name)",
&atoms[0]
))?
.to_vec();
}
}
let target_triple = self.target_triple.clone().unwrap_or_else(Triple::host);
let target = crate::commands::create_exe::utils::target_triple_to_target(
&target_triple,
&self.cpu_features,
);
let (store, _) = CompilerOptions::default().get_store_for_target(target.clone())?;
let engine = store.engine();
let engine_inner = engine.inner();
let compiler = engine_inner.compiler()?;
let features = engine_inner.features();
let tunables = store.tunables();
let (metadata, _, _) = Artifact::metadata(
compiler,
&file,
Some(prefix.as_str()),
&target,
tunables,
features,
)
.map_err(|e| anyhow::anyhow!("could not generate metadata: {e}"))?;
let serialized_data = metadata
.serialize()
.map_err(|e| anyhow::anyhow!("failed to serialize: {e}"))?;
let mut metadata_binary = vec![];
metadata_binary.extend(MetadataHeader::new(serialized_data.len()).into_bytes());
metadata_binary.extend(serialized_data);
let metadata_length = metadata_binary.len();
let header_file_src = crate::c_gen::staticlib_header::generate_header_file(
&prefix,
&metadata.compile_info.module,
&ModuleMetadataSymbolRegistry {
prefix: prefix.clone(),
},
metadata_length,
);
let output = normalize_path(&self.output.display().to_string());
std::fs::write(&output, &header_file_src)
.map_err(|e| anyhow::anyhow!("{e}"))
.with_context(|| anyhow::anyhow!("{output}"))?;
Ok(())
}
}

View File

@ -418,9 +418,7 @@ fn construct_manifest(
log::warn!("{msg}");
}
let modules = vec![wasmer_toml::Module {
name: package_name.to_string(),
source: cargo_toml
let module_source = cargo_toml
.as_ref()
.map(|p| {
// Normalize the path to /target/release to be relative to the parent of the Cargo.toml
@ -429,16 +427,29 @@ fn construct_manifest(
.join("release")
.join(&format!("{package_name}.wasm"));
let canonicalized_outpath = outpath.canonicalize().unwrap_or(outpath);
let outpath_str = format!("{}", canonicalized_outpath.display());
let manifest_canonicalized = manifest_path
let outpath_str =
crate::commands::normalize_path(&canonicalized_outpath.display().to_string());
let manifest_canonicalized = crate::commands::normalize_path(
&manifest_path
.parent()
.and_then(|p| p.canonicalize().ok())
.unwrap_or_else(|| manifest_path.to_path_buf());
let manifest_str = format!("{}/", manifest_canonicalized.display());
let relative_str = outpath_str.replacen(&manifest_str, "", 1);
.unwrap_or_else(|| manifest_path.to_path_buf())
.display()
.to_string(),
);
let diff = outpath_str
.strip_prefix(&manifest_canonicalized)
.unwrap_or(&outpath_str)
.replace('\\', "/");
// Format in UNIX fashion (forward slashes)
let relative_str = diff.strip_prefix('/').unwrap_or(&diff);
Path::new(&relative_str).to_path_buf()
})
.unwrap_or_else(|| Path::new(&format!("{package_name}.wasm")).to_path_buf()),
.unwrap_or_else(|| Path::new(&format!("{package_name}.wasm")).to_path_buf());
let modules = vec![wasmer_toml::Module {
name: package_name.to_string(),
source: module_source,
kind: None,
abi: default_abi,
bindings: bindings.as_ref().and_then(|b| b.first_binding()),

View File

@ -1,25 +0,0 @@
#include "wasmer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");
wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* wasm_name) {
wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH,
.data = (const char*)&WASMER_MODULE_DATA,
};
wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec);
return module;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,24 +1,16 @@
#include "wasmer.h"
//#include "my_wasm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// EXTRA_HEADERS
#define own
#define WASI
#ifdef WASI_PIRITA
extern size_t VOLUMES_LENGTH asm("VOLUMES_LENGTH");
extern char VOLUMES_DATA asm("VOLUMES_DATA");
// DECLARE_VOLUMES
// DECLARE_MODULES
#else
extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");
#endif
static void print_wasmer_error() {
int error_len = wasmer_last_error_length();
@ -54,8 +46,13 @@ static void pass_mapdir_arg(wasi_config_t *wasi_config, char *mapdir) {
// We try to parse out `--dir` and `--mapdir` ahead of time and process those
// specially. All other arguments are passed to the guest program.
static void handle_arguments(wasi_config_t *wasi_config, int argc,
char *argv[]) {
static void handle_arguments(
wasi_config_t *wasi_config,
int argc,
char *argv[],
bool command_was_invoked,
int dash_dash_position
) {
for (int i = 1; i < argc; ++i) {
// We probably want special args like `--dir` and `--mapdir` to not be
// passed directly
@ -88,6 +85,16 @@ static void handle_arguments(wasi_config_t *wasi_config, int argc,
// this arg is a mapdir
char *mapdir = argv[i] + strlen("--mapdir=");
pass_mapdir_arg(wasi_config, mapdir);
} else if (command_was_invoked && i == dash_dash_position && strcmp(argv[i], "--") == 0) {
continue;
} else if (command_was_invoked && dash_dash_position > i && (strcmp(argv[i], "--command") == 0 || strcmp(argv[i], "-c") == 0)) {
// next arg is a command
if ((i + 1) < argc) {
i++;
} else {
fprintf(stderr, "--command expects a commmand name\n");
exit(-1);
}
} else {
// guest argument
wasi_config_arg(wasi_config, argv[i]);
@ -100,29 +107,47 @@ int main(int argc, char *argv[]) {
wasm_config_t *config = wasm_config_new();
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
wasm_module_t *module = NULL;
#ifdef WASI_PIRITA
// INSTANTIATE_MODULES
#else
wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH,
.data = &WASMER_MODULE_DATA,
};
wasm_module_t *module = wasm_module_deserialize(store, &module_byte_vec);
const char* selected_atom = "main";
bool command_was_invoked = false;
int dash_dash_position = argc + 1;
int number_of_commands = 1;
// SET_NUMBER_OF_COMMANDS
if (!module) {
fprintf(stderr, "Failed to create module\n");
print_wasmer_error();
return -1;
if (number_of_commands > 1) {
// check if arguments contain "--" earlier than "--command" or "-c"
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--") == 0) {
dash_dash_position = i;
break;
}
#endif
}
// select the --command only if if was given before a "--", such
for (int i = 1; i < argc; i++) {
if ((strcmp(argv[i], "--command") == 0 || strcmp(argv[i], "-c") == 0) && dash_dash_position > i) {
// next arg is a command
if ((i + 1) < argc) {
selected_atom = argv[i + 1];
command_was_invoked = true;
break;
} else {
fprintf(stderr, "--command expects a commmand name\n");
exit(-1);
}
}
}
}
// INSTANTIATE_MODULES
// We have now finished the memory buffer book keeping and we have a valid
// Module.
#ifdef WASI_PIRITA
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
handle_arguments(wasi_config, argc, argv, command_was_invoked,dash_dash_position);
wasm_byte_vec_t volume_bytes = {
.size = VOLUMES_LENGTH,
@ -142,7 +167,7 @@ int main(int argc, char *argv[]) {
module,
filesystem,
&imports,
"##atom-name##"
selected_atom
);
if (!wasi_env) {
printf("Error setting filesystem\n");
@ -150,7 +175,7 @@ int main(int argc, char *argv[]) {
}
#else
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
handle_arguments(wasi_config, argc, argv, command_was_invoked, dash_dash_position);
wasi_env_t *wasi_env = wasi_env_new(store, wasi_config);
if (!wasi_env) {
@ -216,9 +241,16 @@ int main(int argc, char *argv[]) {
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t *trap = wasm_func_call(start_function, &args, &results);
if (trap) {
fprintf(stderr, "Trap is not NULL: TODO:\n");
wasm_message_t retrieved_message;
// TODO: this is a shitty solution, but it's good enough for now
wasm_trap_message(trap, &retrieved_message);
if (strcmp(retrieved_message.data, "WASI exited with code: 0") == 0) {
wasm_trap_delete(trap);
} else {
fprintf(stderr, "%s", retrieved_message.data);
return -1;
}
}
#endif
// TODO: handle non-WASI start (maybe with invoke?)

View File

@ -1,25 +0,0 @@
#include "wasmer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
extern size_t WASMER_MODULE_LENGTH asm("WASMER_MODULE_LENGTH");
extern char WASMER_MODULE_DATA asm("WASMER_MODULE_DATA");
wasm_module_t* wasmer_object_module_new(wasm_store_t* store, const char* wasm_name) {
wasm_byte_vec_t module_byte_vec = {
.size = WASMER_MODULE_LENGTH,
.data = (const char*)&WASMER_MODULE_DATA,
};
wasm_module_t* module = wasm_module_deserialize(store, &module_byte_vec);
return module;
}
#ifdef __cplusplus
}
#endif

View File

@ -1,230 +0,0 @@
#include "wasmer.h"
#include "static_defs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define own
// TODO: make this define templated so that the Rust code can toggle it on/off
#define WASI
#ifdef WASI_PIRITA
extern size_t VOLUMES_LENGTH asm("VOLUMES_LENGTH");
extern char VOLUMES_DATA asm("VOLUMES_DATA");
#endif
extern wasm_module_t* wasmer_object_module_new(wasm_store_t* store,const char* wasm_name) asm("wasmer_object_module_new");
static void print_wasmer_error() {
int error_len = wasmer_last_error_length();
printf("Error len: `%d`\n", error_len);
char *error_str = (char *)malloc(error_len);
wasmer_last_error_message(error_str, error_len);
printf("%s\n", error_str);
free(error_str);
}
#ifdef WASI
static void pass_mapdir_arg(wasi_config_t *wasi_config, char *mapdir) {
int colon_location = strchr(mapdir, ':') - mapdir;
if (colon_location == 0) {
// error malformed argument
fprintf(stderr, "Expected mapdir argument of the form alias:directory\n");
exit(-1);
}
char *alias = (char *)malloc(colon_location + 1);
memcpy(alias, mapdir, colon_location);
alias[colon_location] = '\0';
int dir_len = strlen(mapdir) - colon_location;
char *dir = (char *)malloc(dir_len + 1);
memcpy(dir, &mapdir[colon_location + 1], dir_len);
dir[dir_len] = '\0';
wasi_config_mapdir(wasi_config, alias, dir);
free(alias);
free(dir);
}
// We try to parse out `--dir` and `--mapdir` ahead of time and process those
// specially. All other arguments are passed to the guest program.
static void handle_arguments(wasi_config_t *wasi_config, int argc,
char *argv[]) {
for (int i = 1; i < argc; ++i) {
// We probably want special args like `--dir` and `--mapdir` to not be
// passed directly
if (strcmp(argv[i], "--dir") == 0) {
// next arg is a preopen directory
if ((i + 1) < argc) {
i++;
wasi_config_preopen_dir(wasi_config, argv[i]);
} else {
fprintf(stderr, "--dir expects a following argument specifying which "
"directory to preopen\n");
exit(-1);
}
} else if (strcmp(argv[i], "--mapdir") == 0) {
// next arg is a mapdir
if ((i + 1) < argc) {
i++;
pass_mapdir_arg(wasi_config, argv[i]);
} else {
fprintf(stderr,
"--mapdir expects a following argument specifying which "
"directory to preopen in the form alias:directory\n");
exit(-1);
}
} else if (strncmp(argv[i], "--dir=", strlen("--dir=")) == 0) {
// this arg is a preopen dir
char *dir = argv[i] + strlen("--dir=");
wasi_config_preopen_dir(wasi_config, dir);
} else if (strncmp(argv[i], "--mapdir=", strlen("--mapdir=")) == 0) {
// this arg is a mapdir
char *mapdir = argv[i] + strlen("--mapdir=");
pass_mapdir_arg(wasi_config, mapdir);
} else {
// guest argument
wasi_config_arg(wasi_config, argv[i]);
}
}
}
#endif
int main(int argc, char *argv[]) {
wasm_config_t *config = wasm_config_new();
wasm_engine_t *engine = wasm_engine_new_with_config(config);
wasm_store_t *store = wasm_store_new(engine);
#ifdef WASI_PIRITA
// INSTANTIATE_MODULES
#else
wasm_module_t *module = wasmer_object_module_new(store, "module");
#endif
if (!module) {
fprintf(stderr, "Failed to create module\n");
print_wasmer_error();
return -1;
}
// We have now finished the memory buffer book keeping and we have a valid
// Module.
#ifdef WASI_PIRITA
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
wasm_byte_vec_t volume_bytes = {
.size = VOLUMES_LENGTH,
.data = &VOLUMES_DATA,
};
wasi_filesystem_t* filesystem = wasi_filesystem_init_static_memory(&volume_bytes);
if (!filesystem) {
printf("Error parsing filesystem from bytes\n");
return 1;
}
wasm_extern_vec_t imports;
wasi_env_t* wasi_env = wasi_env_with_filesystem(
wasi_config,
store,
module,
filesystem,
&imports,
"##atom-name##"
);
if (!wasi_env) {
printf("Error setting filesystem\n");
return 1;
}
#else
wasi_config_t *wasi_config = wasi_config_new(argv[0]);
handle_arguments(wasi_config, argc, argv);
wasi_env_t *wasi_env = wasi_env_new(store, wasi_config);
if (!wasi_env) {
fprintf(stderr, "Error building WASI env!\n");
print_wasmer_error();
return 1;
}
wasm_importtype_vec_t import_types;
wasm_module_imports(module, &import_types);
wasm_extern_vec_t imports;
wasm_extern_vec_new_uninitialized(&imports, import_types.size);
wasm_importtype_vec_delete(&import_types);
#ifdef WASI
bool get_imports_result = wasi_get_imports(store, wasi_env, module, &imports);
if (!get_imports_result) {
fprintf(stderr, "Error getting WASI imports!\n");
print_wasmer_error();
return 1;
}
#endif
#endif
wasm_instance_t *instance = wasm_instance_new(store, module, &imports, NULL);
if (!instance) {
fprintf(stderr, "Failed to create instance\n");
print_wasmer_error();
return -1;
}
#ifdef WASI
// Read the exports.
wasm_extern_vec_t exports;
wasm_instance_exports(instance, &exports);
wasm_memory_t* mem = NULL;
for (size_t i = 0; i < exports.size; i++) {
mem = wasm_extern_as_memory(exports.data[i]);
if (mem) {
break;
}
}
if (!mem) {
fprintf(stderr, "Failed to create instance: Could not find memory in exports\n");
print_wasmer_error();
return -1;
}
wasi_env_set_memory(wasi_env, mem);
own wasm_func_t *start_function = wasi_get_start_function(instance);
if (!start_function) {
fprintf(stderr, "`_start` function not found\n");
print_wasmer_error();
return -1;
}
wasm_val_vec_t args = WASM_EMPTY_VEC;
wasm_val_vec_t results = WASM_EMPTY_VEC;
own wasm_trap_t *trap = wasm_func_call(start_function, &args, &results);
if (trap) {
fprintf(stderr, "Trap is not NULL: TODO:\n");
return -1;
}
#endif
// TODO: handle non-WASI start (maybe with invoke?)
#ifdef WASI_PIRITA
wasi_filesystem_delete(filesystem);
#endif
#ifdef WASI
wasi_env_delete(wasi_env);
wasm_extern_vec_delete(&exports);
#endif
wasm_instance_delete(instance);
wasm_module_delete(module);
wasm_store_delete(store);
wasm_engine_delete(engine);
return 0;
}

View File

@ -30,7 +30,7 @@ pub fn parse_mapdir(entry: &str) -> Result<(String, PathBuf)> {
retrieve_alias_pathbuf(alias, real_dir)
}
// And then we try splitting by `:` (for compatibility with previous API)
else if let [alias, real_dir] = entry.split(':').collect::<Vec<&str>>()[..] {
else if let [alias, real_dir] = entry.splitn(2, ':').collect::<Vec<&str>>()[..] {
retrieve_alias_pathbuf(alias, real_dir)
} else {
bail!(

View File

@ -43,6 +43,7 @@ struct ShortNames {}
impl SymbolRegistry for ShortNames {
fn symbol_to_name(&self, symbol: Symbol) -> String {
match symbol {
Symbol::Metadata => "M".to_string(),
Symbol::LocalFunction(index) => format!("f{}", index.index()),
Symbol::Section(index) => format!("s{}", index.index()),
Symbol::FunctionCallTrampoline(index) => format!("t{}", index.index()),
@ -55,6 +56,10 @@ impl SymbolRegistry for ShortNames {
return None;
}
let (ty, idx) = name.split_at(1);
if ty.starts_with('M') {
return Some(Symbol::Metadata);
}
let idx = idx.parse::<u32>().ok()?;
match ty.chars().next().unwrap() {
'f' => Some(Symbol::LocalFunction(LocalFunctionIndex::from_u32(idx))),
@ -164,8 +169,11 @@ impl LLVMCompiler {
.collect::<Vec<_>>()
.as_slice(),
);
let metadata_gv =
merged_module.add_global(metadata_init.get_type(), None, "WASMER_METADATA");
let metadata_gv = merged_module.add_global(
metadata_init.get_type(),
None,
&symbol_registry.symbol_to_name(wasmer_types::Symbol::Metadata),
);
metadata_gv.set_initializer(&metadata_init);
metadata_gv.set_linkage(Linkage::DLLExport);
metadata_gv.set_dll_storage_class(DLLStorageClass::Export);
@ -310,17 +318,9 @@ impl Compiler for LLVMCompiler {
let dwarf = Some(Dwarf::new(SectionIndex::from_u32(
module_custom_sections.len() as u32,
)));
// Terminating zero-length CIE.
frame_section_bytes.extend(vec![
0x00, 0x00, 0x00, 0x00, // Length
0x00, 0x00, 0x00, 0x00, // CIE ID
0x10, // Version (must be 1)
0x00, // Augmentation data
0x00, // Code alignment factor
0x00, // Data alignment factor
0x00, // Return address register
0x00, 0x00, 0x00, // Padding to a multiple of 4 bytes
]);
// Do not terminate dwarf info with a zero-length CIE.
// Because more info will be added later
// in lib/object/src/module.rs emit_compilation
module_custom_sections.push(CustomSection {
protection: CustomSectionProtection::Read,
bytes: SectionBody::new_with_vec(frame_section_bytes),

View File

@ -739,10 +739,13 @@ macro_rules! sse_fn {
|emitter: &mut AssemblerX64, precision: Precision, src1: XMM, src2: XMMOrMemory, dst: XMM| {
match src2 {
XMMOrMemory::XMM(x) => {
assert_ne!(x, dst);
if x == dst {
dynasm!(emitter ; $ins Rx((dst as u8)), Rx((src1 as u8)))
} else {
move_src_to_dst(emitter, precision, src1, dst);
dynasm!(emitter ; $ins Rx((dst as u8)), Rx((x as u8)))
}
}
XMMOrMemory::Memory(base, disp) => {
move_src_to_dst(emitter, precision, src1, dst);
dynasm!(emitter ; $ins Rx((dst as u8)), [Rq((base as u8)) + disp])

View File

@ -48,12 +48,6 @@ pub struct Artifact {
finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
}
#[cfg(feature = "static-artifact-create")]
pub type PrefixerFn = Box<dyn Fn(&[u8]) -> String + Send>;
#[cfg(feature = "static-artifact-create")]
const WASMER_METADATA_SYMBOL: &[u8] = b"WASMER_METADATA";
impl Artifact {
/// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
#[cfg(feature = "compiler")]
@ -416,7 +410,7 @@ impl Artifact {
#[allow(clippy::type_complexity)]
#[cfg(feature = "static-artifact-create")]
/// Generate a compilation
fn generate_metadata<'data>(
pub fn generate_metadata<'data>(
data: &'data [u8],
compiler: &dyn Compiler,
tunables: &dyn Tunables,
@ -464,16 +458,65 @@ impl Artifact {
))
}
/// Generate the metadata object for the module
#[cfg(feature = "static-artifact-create")]
#[allow(clippy::type_complexity)]
pub fn metadata<'data, 'a>(
compiler: &dyn Compiler,
data: &'a [u8],
metadata_prefix: Option<&str>,
target: &'data Target,
tunables: &dyn Tunables,
features: &Features,
) -> Result<
(
ModuleMetadata,
Option<ModuleTranslationState>,
PrimaryMap<LocalFunctionIndex, FunctionBodyData<'a>>,
),
CompileError,
> {
#[allow(dead_code)]
let (compile_info, function_body_inputs, data_initializers, module_translation) =
Self::generate_metadata(data, compiler, tunables, features)?;
let data_initializers = data_initializers
.iter()
.map(OwnedDataInitializer::new)
.collect::<Vec<_>>()
.into_boxed_slice();
// TODO: we currently supply all-zero function body lengths.
// We don't know the lengths until they're compiled, yet we have to
// supply the metadata as an input to the compile.
let function_body_lengths = function_body_inputs
.keys()
.map(|_function_body| 0u64)
.collect::<PrimaryMap<LocalFunctionIndex, u64>>();
let metadata = ModuleMetadata {
compile_info,
prefix: metadata_prefix.map(|s| s.to_string()).unwrap_or_default(),
data_initializers,
function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
};
Ok((metadata, module_translation, function_body_inputs))
}
/// Compile a module into an object file, which can be statically linked against.
///
/// The `prefixer` returns the a String to prefix each of the
/// functions in the static object generated by the
/// so we can assure no collisions.
/// The `metadata_prefix` is an optional prefix for the object name to make the
/// function names in the object file unique. When set, the function names will
/// be `wasmer_function_{prefix}_{id}` and the object metadata will be addressable
/// using `WASMER_METADATA_{prefix}_LENGTH` and `WASMER_METADATA_{prefix}_DATA`.
///
#[cfg(feature = "static-artifact-create")]
pub fn generate_object<'data>(
compiler: &dyn Compiler,
data: &[u8],
prefixer: Option<PrefixerFn>,
metadata_prefix: Option<&str>,
target: &'data Target,
tunables: &dyn Tunables,
features: &Features,
@ -486,37 +529,16 @@ impl Artifact {
),
CompileError,
> {
use wasmer_types::{compilation::symbols::ModuleMetadataSymbolRegistry, SymbolRegistry};
fn to_compile_error(err: impl std::error::Error) -> CompileError {
CompileError::Codegen(format!("{}", err))
}
#[allow(dead_code)]
let (compile_info, function_body_inputs, data_initializers, module_translation) =
Self::generate_metadata(data, compiler, tunables, features)?;
let data_initializers = data_initializers
.iter()
.map(OwnedDataInitializer::new)
.collect::<Vec<_>>()
.into_boxed_slice();
let target_triple = target.triple();
// TODO: we currently supply all-zero function body lengths.
// We don't know the lengths until they're compiled, yet we have to
// supply the metadata as an input to the compile.
let function_body_lengths = function_body_inputs
.keys()
.map(|_function_body| 0u64)
.collect::<PrimaryMap<LocalFunctionIndex, u64>>();
let mut metadata = ModuleMetadata {
compile_info,
prefix: prefixer.as_ref().map(|p| p(data)).unwrap_or_default(),
data_initializers,
function_body_lengths,
cpu_features: target.cpu_features().as_u64(),
};
let (mut metadata, module_translation, function_body_inputs) =
Self::metadata(compiler, data, metadata_prefix, target, tunables, features)
.map_err(to_compile_error)?;
/*
In the C file we need:
@ -551,7 +573,12 @@ impl Artifact {
)?;
let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
emit_data(&mut obj, WASMER_METADATA_SYMBOL, &metadata_binary, 1)
let object_name = ModuleMetadataSymbolRegistry {
prefix: metadata_prefix.unwrap_or_default().to_string(),
}
.symbol_to_name(wasmer_types::Symbol::Metadata);
emit_data(&mut obj, object_name.as_bytes(), &metadata_binary, 1)
.map_err(to_compile_error)?;
emit_compilation(&mut obj, compilation, &symbol_registry, target_triple)

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
/// possible after translation (such as the features used for compiling,
/// or the `MemoryStyle` and `TableStyle`).
#[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))]
#[derive(Debug, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
#[derive(Debug, Clone, PartialEq, Eq, RkyvSerialize, RkyvDeserialize, Archive)]
pub struct CompileModuleInfo {
/// The features used for compiling the module
pub features: Features,

View File

@ -14,21 +14,15 @@ use serde::{Deserialize, Serialize};
/// The kinds of wasmer_types objects that might be found in a native object file.
#[derive(
RkyvSerialize,
RkyvDeserialize,
Archive,
Copy,
Clone,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Debug,
RkyvSerialize, RkyvDeserialize, Archive, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug,
)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[archive(as = "Self")]
pub enum Symbol {
/// A metadata section, indexed by a unique prefix
/// (usually the wasm file SHA256 hash)
Metadata,
/// A function defined in the wasm.
LocalFunction(LocalFunctionIndex),
@ -154,6 +148,9 @@ impl ModuleMetadata {
impl SymbolRegistry for ModuleMetadataSymbolRegistry {
fn symbol_to_name(&self, symbol: Symbol) -> String {
match symbol {
Symbol::Metadata => {
format!("WASMER_METADATA_{}", self.prefix.to_uppercase())
}
Symbol::LocalFunction(index) => {
format!("wasmer_function_{}_{}", self.prefix, index.index())
}
@ -176,7 +173,10 @@ impl SymbolRegistry for ModuleMetadataSymbolRegistry {
}
fn name_to_symbol(&self, name: &str) -> Option<Symbol> {
if let Some(index) = name.strip_prefix(&format!("wasmer_function_{}_", self.prefix)) {
if name == self.symbol_to_name(Symbol::Metadata) {
Some(Symbol::Metadata)
} else if let Some(index) = name.strip_prefix(&format!("wasmer_function_{}_", self.prefix))
{
index
.parse::<u32>()
.ok()

View File

@ -67,6 +67,34 @@ impl From<(String, String, u32)> for ImportKey {
}
}
#[cfg(feature = "enable-serde")]
mod serde_imports {
use crate::ImportIndex;
use crate::ImportKey;
use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
type InitialType = IndexMap<ImportKey, ImportIndex>;
type SerializedType = Vec<(ImportKey, ImportIndex)>;
// IndexMap<ImportKey, ImportIndex>
// Vec<
pub fn serialize<S: Serializer>(s: &InitialType, serializer: S) -> Result<S::Ok, S::Error> {
let vec: SerializedType = s
.iter()
.map(|(a, b)| (a.clone(), b.clone()))
.collect::<Vec<_>>();
vec.serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<InitialType, D::Error> {
let serialized = <SerializedType as Deserialize>::deserialize(deserializer)?;
Ok(serialized.into_iter().collect())
}
}
/// A translated WebAssembly module, excluding the function bodies and
/// memory initializers.
#[derive(Debug, Clone, Default)]
@ -89,6 +117,7 @@ pub struct ModuleInfo {
/// Keeping the `index_of_the_import` is important, as there can be
/// two same references to the same import, and we don't want to confuse
/// them.
#[cfg_attr(feature = "enable-serde", serde(with = "serde_imports"))]
pub imports: IndexMap<ImportKey, ImportIndex>,
/// Exported entities.

View File

@ -13,7 +13,7 @@ use wasmer_emscripten::{
};
use webc::{Command, WebCMmap};
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct EmscriptenRunner {
args: Vec<String>,
}

View File

@ -11,7 +11,7 @@ use wasmer::{Cranelift, Instance, Module, Store};
use wasmer_vfs::webc_fs::WebcFileSystem;
use webc::{Command, WebCMmap};
#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Hash, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct WasiRunner {
args: Vec<String>,
}

View File

@ -13,6 +13,7 @@ tar = "0.4.38"
flate2 = "1.0.24"
target-lexicon = "0.12.4"
pretty_assertions = "1.3.0"
object = "0.30.0"
[dependencies]
anyhow = "1"

View File

@ -23,13 +23,14 @@ pub fn run_code(
operating_dir: &Path,
executable_path: &Path,
args: &[String],
stderr: bool,
) -> anyhow::Result<String> {
let output = Command::new(executable_path.canonicalize()?)
.current_dir(operating_dir)
.args(args)
.output()?;
if !output.status.success() {
if !output.status.success() && !stderr {
bail!(
"running executable failed: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout)
@ -38,8 +39,12 @@ pub fn run_code(
.expect("stderr is not utf8! need to handle arbitrary bytes")
);
}
let output =
std::str::from_utf8(&output.stdout).expect("output from running executable is not utf-8");
let output = std::str::from_utf8(if stderr {
&output.stderr
} else {
&output.stdout
})
.expect("output from running executable is not utf-8");
Ok(output.to_owned())
}

View File

@ -1,5 +1,4 @@
use anyhow::bail;
use std::path::{Path, PathBuf};
use std::path::Path;
use std::process::Command;
use wasmer_integration_tests_cli::get_wasmer_path;
@ -42,11 +41,16 @@ fn wasmer_config_error() -> anyhow::Result<()> {
.lines()
.map(|s| s.trim().to_string())
.collect::<Vec<_>>();
#[cfg(not(windows))]
let expected_1 = "wasmer config --bindir --cflags";
#[cfg(windows)]
let expected_1 = "wasmer.exe config --bindir --cflags";
let expected = vec![
"error: The argument '--bindir' cannot be used with '--pkg-config'",
"",
"USAGE:",
"wasmer config --bindir --cflags",
expected_1,
"",
"For more information try --help",
];
@ -212,7 +216,7 @@ fn config_works() -> anyhow::Result<()> {
assert_eq!(
String::from_utf8_lossy(&output.stdout),
format!("{}\n", original_token.to_string().trim().to_string())
format!("{}\n", original_token.to_string().trim())
);
let output = Command::new(get_wasmer_path())

View File

@ -5,8 +5,17 @@ use std::fs;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
use wasmer_integration_tests_cli::*;
fn create_exe_wabt_path() -> String {
format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer")
}
fn create_exe_python_wasmer() -> String {
format!("{}/{}", C_ASSET_PATH, "python-0.1.0.wasmer")
}
fn create_exe_test_wasm_path() -> String {
format!("{}/{}", C_ASSET_PATH, "qjs.wasm")
}
@ -27,7 +36,7 @@ struct WasmerCreateExe {
/// Compiler with which to compile the Wasm.
compiler: Compiler,
/// Extra CLI flags
extra_cli_flags: Vec<&'static str>,
extra_cli_flags: Vec<String>,
}
impl Default for WasmerCreateExe {
@ -49,19 +58,23 @@ impl Default for WasmerCreateExe {
impl WasmerCreateExe {
fn run(&self) -> anyhow::Result<Vec<u8>> {
let output = Command::new(&self.wasmer_path)
.current_dir(&self.current_dir)
.arg("create-exe")
.arg(&self.wasm_path.canonicalize()?)
.arg(&self.compiler.to_flag())
.args(self.extra_cli_flags.iter())
.arg("-o")
.arg(&self.native_executable_path)
.output()?;
let mut output = Command::new(&self.wasmer_path);
output.current_dir(&self.current_dir);
output.arg("create-exe");
output.arg(&self.wasm_path.canonicalize()?);
output.arg(&self.compiler.to_flag());
output.args(self.extra_cli_flags.iter());
output.arg("-o");
output.arg(&self.native_executable_path);
let cmd = format!("{:?}", output);
println!("(integration-test) running create-exe: {cmd}");
let output = output.output()?;
if !output.status.success() {
bail!(
"wasmer create-exe failed with: stdout: {}\n\nstderr: {}",
"{cmd}\r\n failed with: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout)
.expect("stdout is not utf8! need to handle arbitrary bytes"),
std::str::from_utf8(&output.stderr)
@ -86,7 +99,7 @@ struct WasmerCreateObj {
/// Compiler with which to compile the Wasm.
compiler: Compiler,
/// Extra CLI flags
extra_cli_flags: Vec<&'static str>,
extra_cli_flags: Vec<String>,
}
impl Default for WasmerCreateObj {
@ -108,19 +121,24 @@ impl Default for WasmerCreateObj {
impl WasmerCreateObj {
fn run(&self) -> anyhow::Result<Vec<u8>> {
let output = Command::new(&self.wasmer_path)
.current_dir(&self.current_dir)
.arg("create-obj")
.arg(&self.wasm_path.canonicalize()?)
.arg(&self.compiler.to_flag())
.args(self.extra_cli_flags.iter())
.arg("-o")
.arg(&self.output_object_path)
.output()?;
let mut output = Command::new(&self.wasmer_path);
output.current_dir(&self.current_dir);
output.arg("create-obj");
output.arg(&self.wasm_path.canonicalize()?);
output.arg(&self.compiler.to_flag());
output.args(self.extra_cli_flags.iter());
output.arg("-o");
output.arg(&self.output_object_path);
let cmd = format!("{:?}", output);
println!("(integration-test) running create-obj: {cmd}");
let output = output.output()?;
if !output.status.success() {
bail!(
"wasmer create-obj failed with: stdout: {}\n\nstderr: {}",
"{cmd}\r\n failed with: stdout: {}\n\nstderr: {}",
std::str::from_utf8(&output.stdout)
.expect("stdout is not utf8! need to handle arbitrary bytes"),
std::str::from_utf8(&output.stderr)
@ -131,6 +149,115 @@ impl WasmerCreateObj {
}
}
#[test]
fn test_create_exe_with_pirita_works_1() {
let tempdir = TempDir::new().unwrap();
let path = tempdir.path();
let wasm_out = path.join("out.obj");
let cmd = Command::new(get_wasmer_path())
.arg("create-obj")
.arg(create_exe_wabt_path())
.arg("-o")
.arg(&wasm_out)
.output()
.unwrap();
let stderr = String::from_utf8_lossy(&cmd.stderr);
assert_eq!(stderr.lines().map(|s| s.trim().to_string()).collect::<Vec<_>>(), vec![
format!("error: cannot compile more than one atom at a time"),
format!("│ 1: note: use --atom <ATOM> to specify which atom to compile"),
format!("╰─▶ 2: where <ATOM> is one of: wabt, wasm-interp, wasm-strip, wasm-validate, wasm2wat, wast2json, wat2wasm"),
]);
assert!(!cmd.status.success());
let cmd = Command::new(get_wasmer_path())
.arg("create-obj")
.arg(create_exe_wabt_path())
.arg("--atom")
.arg("wasm2wat")
.arg("-o")
.arg(&wasm_out)
.output()
.unwrap();
let stderr = String::from_utf8_lossy(&cmd.stderr);
let real_out = wasm_out.canonicalize().unwrap().display().to_string();
let real_out = real_out
.strip_prefix(r"\\?\")
.unwrap_or(&real_out)
.to_string();
assert_eq!(
stderr
.lines()
.map(|s| s.trim().to_string())
.collect::<Vec<_>>(),
vec![format!("✔ Object compiled successfully to `{real_out}`"),]
);
assert!(cmd.status.success());
}
#[test]
fn test_create_exe_with_precompiled_works_1() {
use object::{Object, ObjectSymbol};
let tempdir = TempDir::new().unwrap();
let path = tempdir.path();
let wasm_out = path.join("out.obj");
let _ = Command::new(get_wasmer_path())
.arg("create-obj")
.arg(create_exe_test_wasm_path())
.arg("--prefix")
.arg("sha123123")
.arg("-o")
.arg(&wasm_out)
.output()
.unwrap();
let file = std::fs::read(&wasm_out).unwrap();
let obj_file = object::File::parse(&*file).unwrap();
let names = obj_file
.symbols()
.filter_map(|s| Some(s.name().ok()?.to_string()))
.collect::<Vec<_>>();
assert!(
names.contains(&"_wasmer_function_sha123123_1".to_string())
|| names.contains(&"wasmer_function_sha123123_1".to_string())
);
let _ = Command::new(get_wasmer_path())
.arg("create-obj")
.arg(create_exe_test_wasm_path())
.arg("-o")
.arg(&wasm_out)
.output()
.unwrap();
let file = std::fs::read(&wasm_out).unwrap();
let obj_file = object::File::parse(&*file).unwrap();
let names = obj_file
.symbols()
.filter_map(|s| Some(s.name().ok()?.to_string()))
.collect::<Vec<_>>();
assert!(
names.contains(
&"_wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_1"
.to_string()
) || names.contains(
&"wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_1"
.to_string()
)
);
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_works() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
@ -156,6 +283,7 @@ fn create_exe_works() -> anyhow::Result<()> {
&operating_dir,
&executable_path,
&["--eval".to_string(), "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));".to_string()],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
@ -164,6 +292,133 @@ fn create_exe_works() -> anyhow::Result<()> {
Ok(())
}
/// Tests that "-c" and "-- -c" are treated differently
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_works_multi_command_args_handling() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_wabt_path());
#[cfg(not(windows))]
let executable_path = operating_dir.join("multicommand.out");
#[cfg(windows)]
let executable_path = operating_dir.join("multicommand.exe");
WasmerCreateExe {
current_dir: operating_dir.clone(),
wasm_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
..Default::default()
}
.run()
.context("Failed to create-exe wasm with Wasmer")?;
let result = run_code(
&operating_dir,
&executable_path,
&[
"--command".to_string(),
"wasm-strip".to_string(),
"--".to_string(),
"-c".to_string(),
],
true,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(
result_lines,
vec![
"wasm-strip: unknown option '-c'",
"Try '--help' for more information.",
"WASI exited with code: 1"
]
);
let result = run_code(
&operating_dir,
&executable_path,
&["-c".to_string(), "wasm-strip".to_string()],
true,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(
result_lines,
vec![
"wasm-strip: expected filename argument.",
"Try '--help' for more information.",
"WASI exited with code: 1"
]
);
Ok(())
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_works_multi_command() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_wabt_path());
#[cfg(not(windows))]
let executable_path = operating_dir.join("multicommand.out");
#[cfg(windows)]
let executable_path = operating_dir.join("multicommand.exe");
WasmerCreateExe {
current_dir: operating_dir.clone(),
wasm_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
..Default::default()
}
.run()
.context("Failed to create-exe wasm with Wasmer")?;
let result = run_code(
&operating_dir,
&executable_path,
&[
"--command".to_string(),
"wasm2wat".to_string(),
"--version".to_string(),
],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(result_lines, vec!["1.0.37 (git~v1.0.37)"]);
let result = run_code(
&operating_dir,
&executable_path,
&[
"-c".to_string(),
"wasm-validate".to_string(),
"--version".to_string(),
],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
assert_eq!(result_lines, vec!["1.0.37 (git~v1.0.37)"]);
Ok(())
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_works_with_file() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
@ -202,6 +457,7 @@ fn create_exe_works_with_file() -> anyhow::Result<()> {
"--script".to_string(),
"test.js".to_string(),
],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
@ -216,6 +472,7 @@ fn create_exe_works_with_file() -> anyhow::Result<()> {
"--script".to_string(),
"abc/test.js".to_string(),
],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
@ -224,6 +481,9 @@ fn create_exe_works_with_file() -> anyhow::Result<()> {
Ok(())
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_serialized_works() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
@ -236,11 +496,11 @@ fn create_exe_serialized_works() -> anyhow::Result<()> {
let executable_path = operating_dir.join("wasm.exe");
let output: Vec<u8> = WasmerCreateExe {
current_dir: operating_dir.clone(),
current_dir: std::env::current_dir().unwrap(),
wasm_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: vec!["--object-format", "serialized"],
extra_cli_flags: vec!["--object-format".to_string(), "serialized".to_string()],
..Default::default()
}
.run()
@ -250,6 +510,7 @@ fn create_exe_serialized_works() -> anyhow::Result<()> {
&operating_dir,
&executable_path,
&["--eval".to_string(), "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));".to_string()],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
@ -265,17 +526,13 @@ fn create_exe_serialized_works() -> anyhow::Result<()> {
Ok(())
}
fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> anyhow::Result<()> {
fn create_obj(args: Vec<String>, keyword_needle: &str, keyword: &str) -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
#[cfg(not(windows))]
let object_path = operating_dir.join("wasm.o");
#[cfg(windows)]
let object_path = operating_dir.join("wasm.obj");
let wasm_path = operating_dir.as_path().join(create_exe_test_wasm_path());
let object_path = operating_dir.as_path().join("wasm");
let output: Vec<u8> = WasmerCreateObj {
current_dir: operating_dir,
wasm_path,
@ -292,13 +549,6 @@ fn create_obj(args: Vec<&'static str>, keyword_needle: &str, keyword: &str) -> a
"create-obj successfully completed but object output file `{}` missing",
object_path.display()
);
let mut object_header_path = object_path;
object_header_path.set_extension("h");
assert!(
object_header_path.exists(),
"create-obj successfully completed but object output header file `{}` missing",
object_header_path.display()
);
let output_str = String::from_utf8_lossy(&output);
assert!(
@ -318,19 +568,23 @@ fn create_obj_default() -> anyhow::Result<()> {
#[test]
fn create_obj_symbols() -> anyhow::Result<()> {
create_obj(vec!["--object-format", "symbols"], "Symbols", "symbols")
create_obj(
vec!["--object-format".to_string(), "symbols".to_string()],
"Symbols",
"symbols",
)
}
#[test]
fn create_obj_serialized() -> anyhow::Result<()> {
create_obj(
vec!["--object-format", "serialized"],
vec!["--object-format".to_string(), "serialized".to_string()],
"Serialized",
"serialized",
)
}
fn create_exe_with_object_input(args: Vec<&'static str>) -> anyhow::Result<()> {
fn create_exe_with_object_input(args: Vec<String>) -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
@ -341,12 +595,21 @@ fn create_exe_with_object_input(args: Vec<&'static str>) -> anyhow::Result<()> {
#[cfg(windows)]
let object_path = operating_dir.join("wasm.obj");
let mut create_obj_args = args.clone();
create_obj_args.push("--prefix".to_string());
create_obj_args.push("abc123".to_string());
create_obj_args.push("--debug-dir".to_string());
create_obj_args.push(format!(
"{}",
operating_dir.join("compile-create-obj").display()
));
WasmerCreateObj {
current_dir: operating_dir.clone(),
wasm_path,
wasm_path: wasm_path.clone(),
output_object_path: object_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: args,
extra_cli_flags: create_obj_args,
..Default::default()
}
.run()
@ -357,34 +620,43 @@ fn create_exe_with_object_input(args: Vec<&'static str>) -> anyhow::Result<()> {
"create-obj successfully completed but object output file `{}` missing",
object_path.display()
);
let mut object_header_path = object_path.clone();
object_header_path.set_extension("h");
assert!(
object_header_path.exists(),
"create-obj successfully completed but object output header file `{}` missing",
object_header_path.display()
);
#[cfg(not(windows))]
let executable_path = operating_dir.join("wasm.out");
#[cfg(windows)]
let executable_path = operating_dir.join("wasm.exe");
WasmerCreateExe {
current_dir: operating_dir.clone(),
wasm_path: object_path,
let mut create_exe_args = args.clone();
create_exe_args.push("--precompiled-atom".to_string());
create_exe_args.push(format!("qjs:abc123:{}", object_path.display()));
create_exe_args.push("--debug-dir".to_string());
create_exe_args.push(format!(
"{}",
operating_dir.join("compile-create-exe").display()
));
let create_exe_stdout = WasmerCreateExe {
current_dir: std::env::current_dir().unwrap(),
wasm_path,
native_executable_path: executable_path.clone(),
compiler: Compiler::Cranelift,
extra_cli_flags: vec!["--header", "wasm.h"],
extra_cli_flags: create_exe_args,
..Default::default()
}
.run()
.context("Failed to create-exe wasm with Wasmer")?;
let create_exe_stdout = std::str::from_utf8(&create_exe_stdout).unwrap();
assert!(
create_exe_stdout.contains("Using cached object file for atom \"qjs\"."),
"missed cache hit"
);
let result = run_code(
&operating_dir,
&executable_path,
&["--eval".to_string(), "function greet(name) { return JSON.stringify('Hello, ' + name); }; print(greet('World'));".to_string()],
false,
)
.context("Failed to run generated executable")?;
let result_lines = result.lines().collect::<Vec<&str>>();
@ -393,17 +665,29 @@ fn create_exe_with_object_input(args: Vec<&'static str>) -> anyhow::Result<()> {
Ok(())
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_with_object_input_default() -> anyhow::Result<()> {
create_exe_with_object_input(vec![])
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_with_object_input_symbols() -> anyhow::Result<()> {
create_exe_with_object_input(vec!["--object-format", "symbols"])
create_exe_with_object_input(vec!["--object-format".to_string(), "symbols".to_string()])
}
// Ignored because of -lunwind linker issue on Windows
// see https://github.com/wasmerio/wasmer/issues/3459
#[cfg_attr(target_os = "windows", ignore)]
#[test]
fn create_exe_with_object_input_serialized() -> anyhow::Result<()> {
create_exe_with_object_input(vec!["--object-format", "serialized"])
create_exe_with_object_input(vec![
"--object-format".to_string(),
"serialized".to_string(),
])
}

View File

@ -0,0 +1,84 @@
use std::path::PathBuf;
use std::process::Command;
use wasmer_integration_tests_cli::get_wasmer_path;
use wasmer_integration_tests_cli::C_ASSET_PATH;
fn create_exe_wabt_path() -> String {
format!("{}/{}", C_ASSET_PATH, "wabt-1.0.37.wasmer")
}
fn create_exe_test_wasm_path() -> String {
format!("{}/{}", C_ASSET_PATH, "qjs.wasm")
}
#[test]
fn gen_c_header_works() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_test_wasm_path());
let out_path = temp_dir.path().join("header.h");
let _ = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.output()
.unwrap();
let file = std::fs::read_to_string(&out_path).expect("no header.h file");
assert!(file.contains("wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_0"), "no wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_0 in file");
let _ = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.arg("--prefix")
.arg("abc123")
.output()
.unwrap();
let file = std::fs::read_to_string(&out_path).expect("no header.h file");
assert!(
file.contains("wasmer_function_abc123_0"),
"no wasmer_function_abc123_0 in file"
);
Ok(())
}
#[test]
fn gen_c_header_works_pirita() -> anyhow::Result<()> {
let temp_dir = tempfile::tempdir()?;
let operating_dir: PathBuf = temp_dir.path().to_owned();
let wasm_path = operating_dir.join(create_exe_wabt_path());
let out_path = temp_dir.path().join("header.h");
let _ = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.arg("--atom")
.arg("wasm-validate")
.output()
.unwrap();
let file = std::fs::read_to_string(&out_path).expect("no header.h file");
assert!(file.contains("wasmer_function_0f41d38dcfb5abc1fadb5e9acbc5c645e53fe4d0dd86270b72a09bfeee04d055_0"), "no wasmer_function_6f62a6bc5c8f8e3e12a54e2ecbc5674ccfe1c75f91d8e4dd6ebb3fec422a4d6c_0 in file");
let cmd = Command::new(get_wasmer_path())
.arg("gen-c-header")
.arg(&wasm_path)
.arg("-o")
.arg(&out_path)
.output()
.unwrap();
assert!(!cmd.status.success());
Ok(())
}

View File

@ -2,7 +2,7 @@
use anyhow::{bail, Context};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::process::{Command, Stdio};
use wasmer_integration_tests_cli::{get_repo_root_path, get_wasmer_path, ASSET_PATH, C_ASSET_PATH};
fn wasi_test_python_path() -> PathBuf {
@ -25,6 +25,7 @@ fn test_no_start_wat_path() -> PathBuf {
fn test_cross_compile_python_windows() -> anyhow::Result<()> {
let temp_dir = tempfile::TempDir::new()?;
#[cfg(not(windows))]
let targets = &[
"aarch64-darwin",
"x86_64-darwin",
@ -33,6 +34,14 @@ fn test_cross_compile_python_windows() -> anyhow::Result<()> {
"x86_64-windows-gnu",
];
#[cfg(windows)]
let targets = &[
"aarch64-darwin",
"x86_64-darwin",
"x86_64-linux-gnu",
"aarch64-linux-gnu",
];
// MUSL has no support for LLVM in C-API
#[cfg(target_env = "musl")]
let compilers = &["cranelift", "singlepass"];
@ -202,14 +211,17 @@ fn package_directory(in_dir: &PathBuf, out: &PathBuf) {
/// TODO: on linux-musl, the packaging of libwasmer.a doesn't work properly
/// Tracked in https://github.com/wasmerio/wasmer/issues/3271
#[cfg(not(target_env = "musl"))]
#[cfg(not(any(target_env = "musl", target_os = "windows")))]
#[cfg(feature = "webc_runner")]
#[test]
fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> {
// let temp_dir = Path::new("debug");
// std::fs::create_dir_all(&temp_dir);
let temp_dir = tempfile::TempDir::new()?;
let python_wasmer_path = temp_dir.path().join("python.wasmer");
let temp_dir = temp_dir.path().to_path_buf();
let python_wasmer_path = temp_dir.join("python.wasmer");
std::fs::copy(wasi_test_python_path(), &python_wasmer_path)?;
let python_exe_output_path = temp_dir.path().join("python");
let python_exe_output_path = temp_dir.join("python");
let native_target = target_lexicon::HOST;
let root_path = get_repo_root_path().unwrap();
@ -217,8 +229,7 @@ fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> {
if !package_path.exists() {
panic!("package path {} does not exist", package_path.display());
}
let tmp_targz_path = tempfile::TempDir::new()?;
let tmp_targz_path = tmp_targz_path.path().join("link.tar.gz");
let tmp_targz_path = temp_dir.join("link.tar.gz");
println!("compiling to target {native_target}");
println!(
"packaging /package to .tar.gz: {}",
@ -241,10 +252,17 @@ fn test_wasmer_create_exe_pirita_works() -> anyhow::Result<()> {
cmd.arg(format!("{native_target}"));
cmd.arg("-o");
cmd.arg(&python_exe_output_path);
// change temp_dir to a local path and run this test again
// to output the compilation files into a debug folder
//
// cmd.arg("--debug-dir");
// cmd.arg(&temp_dir);
println!("running: {cmd:?}");
let output = cmd.output()?;
let output = cmd
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
let stdout = std::str::from_utf8(&output.stdout)