diff --git a/Cargo.lock b/Cargo.lock index cc3119b45..90ca7c28a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3054,6 +3054,14 @@ dependencies = [ "wasmer-compiler-singlepass", ] +[[package]] +name = "wasmer-capi-examples-runner" +version = "0.1.0" +dependencies = [ + "cc", + "target-lexicon 0.11.2", +] + [[package]] name = "wasmer-cli" version = "3.0.0-beta" diff --git a/Cargo.toml b/Cargo.toml index 06ecf49d7..bed30b218 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ members = [ "lib/wasi-experimental-io-devices", "lib/wasi-local-networking", "lib/c-api/tests/wasmer-c-api-test-runner", + "lib/c-api/examples/wasmer-capi-examples-runner", "lib/types", "tests/wasi-wast", "tests/lib/wast", diff --git a/lib/c-api/examples/Makefile b/lib/c-api/examples/Makefile index 884619aca..192df90fb 100644 --- a/lib/c-api/examples/Makefile +++ b/lib/c-api/examples/Makefile @@ -4,14 +4,26 @@ $(info Using provided WASMER_DIR=$(WASMER_DIR)) ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +MSVC_CFLAGS:="" +MSVC_LDFLAGS:="" +MSVC_LDLIBS:="" + ifeq (,$(wildcard $(WASMER_DIR)/bin/wasmer)) - CFLAGS = -g -I$(ROOT_DIR)/../tests -I$(WASMER_DIR)/include + CFLAGS = -g -I$(ROOT_DIR)/ -I$(WASMER_DIR)/include LDFLAGS = -Wl,-rpath,$(WASMER_DIR)/lib LDLIBS = -L$(WASMER_DIR)/lib -lwasmer + + MSVC_CFLAGS:= /DEBUG /I $(ROOT_DIR)/ /I $(WASMER_DIR)/include + MSVC_LDFLAGS:= "" + MSVC_LDLIBS:= /LIBPATH:$(WASMER_DIR)/lib wasmer.dll.lib else - CFLAGS = -g -I$(ROOT_DIR)/../tests -I$(shell $(WASMER_DIR)/bin/wasmer config --includedir) + CFLAGS = -g -I$(ROOT_DIR)/ -I$(shell $(WASMER_DIR)/bin/wasmer config --includedir) LDFLAGS = -Wl,-rpath,$(shell $(WASMER_DIR)/bin/wasmer config --libdir) LDLIBS = $(shell $(WASMER_DIR)/bin/wasmer config --libs) + + MSVC_CFLAGS:= /DEBUG /I $(ROOT_DIR)/ /I $(shell $(WASMER_DIR)/bin/wasmer config --includedir) + MSVC_LDFLAGS:= "" + MSVC_LDLIBS:= /LIBPATH:$(shell $(WASMER_DIR)/bin/wasmer config --libs) wasmer.dll.lib endif $(info * CFLAGS: $(CFLAGS)) @@ -20,44 +32,10 @@ $(info * LDLIBS: $(LDLIBS)) ALL = deprecated-header early-exit instance imports-exports exports-function exports-global memory memory2 features wasi -.SILENT: deprecated-header deprecated-header.o -deprecated-header: deprecated-header.o - -.SILENT: early-exit early-exit.o -early-exit: early-exit.o - -.SILENT: instance instance.o -instance: instance.o - -.SILENT: imports-exports imports-exports.o -imports-exports: imports-exports.o - -.SILENT: exports-function exports-function.o -exports-function: exports-function.o - -.SILENT: exports-global exports-global.o -exports-global: exports-global.o - -.SILENT: memory memory.o -memory: memory.o - -.SILENT: memory2 memory2.o -memory2: memory2.o - -.SILENT: features features.o -features: features.o - -.SILENT: wasi wasi.o -wasi: wasi.o - -.PHONY: all -all: $(ALL) - .PHONY: run .SILENT: run -run: $(ALL) - set -o errexit; \ - $(foreach example,$?,echo Running \"$(example)\" example; ./$(example); echo;) +run: + WASMER_DIR="$(WASMER_DIR)" ROOT_DIR="$(ROOT_DIR)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LDLIBS="$(LDLIBS)" cargo test --manifest-path="./wasmer-capi-examples-runner/Cargo.toml" -- --nocapture .SILENT: clean .PHONY: clean diff --git a/lib/c-api/examples/early-exit.c b/lib/c-api/examples/early-exit.c index d2410ca8b..6c4bb0815 100644 --- a/lib/c-api/examples/early-exit.c +++ b/lib/c-api/examples/early-exit.c @@ -45,7 +45,7 @@ int main(int argc, const char *argv[]) { // Load binary. printf("Loading binary...\n"); - FILE *file = fopen("assets/call_trap.wasm", "r"); + FILE *file = fopen("assets/call_trap.wasm", "rb"); if (!file) { printf("> Error loading module!\n"); return 1; diff --git a/lib/c-api/examples/wasi.c b/lib/c-api/examples/wasi.c index 529268e85..7771560aa 100644 --- a/lib/c-api/examples/wasi.c +++ b/lib/c-api/examples/wasi.c @@ -38,7 +38,7 @@ int main(int argc, const char* argv[]) { // Load binary. printf("Loading binary...\n"); - FILE* file = fopen("assets/qjs.wasm", "r"); + FILE* file = fopen("assets/qjs.wasm", "rb"); if (!file) { printf("> Error loading module!\n"); return 1; @@ -49,7 +49,7 @@ int main(int argc, const char* argv[]) { wasm_byte_vec_t binary; wasm_byte_vec_new_uninitialized(&binary, file_size); if (fread(binary.data, file_size, 1, file) != 1) { - printf("> Error loading module!\n"); + printf("> Error initializing module!\n"); return 1; } fclose(file); @@ -137,12 +137,12 @@ int main(int argc, const char* argv[]) { } printf("Call completed\n"); - { - FILE *memory_stream; - char* stdout; - size_t stdout_size = 0; + if(true) { - memory_stream = open_memstream(&stdout, &stdout_size); + // NOTE: previously, this used open_memstream, + // which is not cross-platform + FILE *memory_stream = NULL; + memory_stream = tmpfile(); // stdio.h if (NULL == memory_stream) { printf("> Error creating a memory stream.\n"); @@ -161,15 +161,20 @@ int main(int argc, const char* argv[]) { } if (data_read_size > 0) { - stdout_size += data_read_size; fwrite(buffer, sizeof(char), data_read_size, memory_stream); } } while (BUF_SIZE == data_read_size); + // print memory_stream + rewind(memory_stream); + fputs("WASI Stdout: ", stdout); + char buffer2[256]; + while (!feof(memory_stream)) { + if (fgets(buffer2, 256, memory_stream) == NULL) break; + fputs(buffer2, stdout); + } + fputs("\n", stdout); fclose(memory_stream); - - printf("WASI Stdout: `%.*s`\n", (int) stdout_size, stdout); - free(stdout); } diff --git a/lib/c-api/tests/Makefile b/lib/c-api/tests/Makefile index 91ba07f6e..9c02b82c8 100644 --- a/lib/c-api/tests/Makefile +++ b/lib/c-api/tests/Makefile @@ -35,7 +35,7 @@ $(info * LDFLAGS: $(LDFLAGS)) $(info * LDLIBS: $(LDLIBS)) test: - cargo test --manifest-path="./wasmer-c-api-test-runner/Cargo.toml" -- --nocapture + WASMER_DIR="$(WASMER_DIR)" ROOT_DIR="$(ROOT_DIR)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LDLIBS="$(LDLIBS)" cargo test --manifest-path="./wasmer-c-api-test-runner/Cargo.toml" -- --nocapture .SILENT: clean .PHONY: clean diff --git a/lib/c-api/tests/wasmer-c-api-test-runner/command.bat b/lib/c-api/tests/wasmer-c-api-test-runner/command.bat deleted file mode 100644 index bc40c1eba..000000000 --- a/lib/c-api/tests/wasmer-c-api-test-runner/command.bat +++ /dev/null @@ -1 +0,0 @@ -"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.33.31629\\bin\\HostX64\\x64\\cl.exe" -nologo -MD -O1 -Brepro -W4 "C:\\Users\\felix\\Development\\wasmer\\lib\\c-api\\tests\\wasmer-c-api-test-runner/../wasm-c-api/example/callback.c" /I "C:/Users/felix/Development/wasmer/package/include" /link /LIBPATH:"C:/Users/felix/Development/wasmer/package/lib" "C:/Users/felix/Development/wasmer/package/lib/wasmer.dll.lib" /OUT:"C:\\Users\\felix\\Development\\wasmer\\lib\\c-api\\tests\\wasmer-c-api-test-runner/../wasm-c-api/example/callback.exe" \ No newline at end of file diff --git a/lib/c-api/tests/wasmer-c-api-test-runner/src/lib.rs b/lib/c-api/tests/wasmer-c-api-test-runner/src/lib.rs index b1bab4deb..86b3c1cdc 100644 --- a/lib/c-api/tests/wasmer-c-api-test-runner/src/lib.rs +++ b/lib/c-api/tests/wasmer-c-api-test-runner/src/lib.rs @@ -30,6 +30,36 @@ impl Config { } } + +#[derive(Default)] +pub struct RemoveTestsOnDrop { } + +impl Drop for RemoveTestsOnDrop { + fn drop(&mut self) { + let manifest_dir = env!("CARGO_MANIFEST_DIR"); + for entry in std::fs::read_dir(&manifest_dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + let extension = path.extension().and_then(|s| s.to_str()); + if extension == Some("obj") || extension == Some("exe") { + println!("removing {}", path.display()); + let _ = std::fs::remove_file(&path); + } + } + if let Some(parent) = std::path::Path::new(&manifest_dir).parent() { + for entry in std::fs::read_dir(&parent).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + let extension = path.extension().and_then(|s| s.to_str()); + if extension == Some("obj") || extension == Some("exe") { + println!("removing {}", path.display()); + let _ = std::fs::remove_file(&path); + } + } + } + } +} + const CAPI_BASE_TESTS: &[&str] = &[ "wasm-c-api/example/callback", "wasm-c-api/example/memory", @@ -56,136 +86,142 @@ const CAPI_BASE_TESTS_NOT_WORKING: &[&str] = &[ #[test] fn test_ok() { + let _drop = RemoveTestsOnDrop::default(); let config = Config::get(); println!("config: {:#?}", config); let manifest_dir = env!("CARGO_MANIFEST_DIR"); - let host = target_lexicon::HOST.to_string(); let target = &host; - #[cfg(target_os = "windows")] - for test in CAPI_BASE_TESTS.iter() { + if target.contains("msvc") { + for test in CAPI_BASE_TESTS.iter() { - let mut build = cc::Build::new(); - let mut build = build - .cargo_metadata(false) - .warnings(true) - .static_crt(true) - .extra_warnings(true) - .warnings_into_errors(false) - .debug(config.ldflags.contains("-g")) - .host(&host) - .target(target) - .opt_level(1); - - let compiler = build.try_get_compiler().unwrap(); - let mut command = compiler.to_command(); - - command.arg(&format!("{manifest_dir}/../{test}.c")); - if !config.msvc_cflags.is_empty() { - command.arg(config.msvc_cflags.clone()); - } else if !config.wasmer_dir.is_empty() { - command.arg("/I"); - command.arg(&format!("{}/include", config.wasmer_dir)); + let mut build = cc::Build::new(); + let mut build = build + .cargo_metadata(false) + .warnings(true) + .static_crt(true) + .extra_warnings(true) + .warnings_into_errors(false) + .debug(config.ldflags.contains("-g")) + .host(&host) + .target(target) + .opt_level(1); + + let compiler = build.try_get_compiler().unwrap(); + let mut command = compiler.to_command(); + + command.arg(&format!("{manifest_dir}/../{test}.c")); + if !config.msvc_cflags.is_empty() { + command.arg(config.msvc_cflags.clone()); + } else if !config.wasmer_dir.is_empty() { + command.arg("/I"); + command.arg(&format!("{}/include", config.wasmer_dir)); + } + command.arg("/link"); + if !config.msvc_ldlibs.is_empty() { + command.arg(config.msvc_ldlibs.clone()); + } else if !config.wasmer_dir.is_empty() { + command.arg(&format!("/LIBPATH:{}/lib", config.wasmer_dir)); + command.arg(&format!("{}/lib/wasmer.dll.lib", config.wasmer_dir)); + } + let wasmer_dll_dir = format!("{}/lib", config.wasmer_dir); + command.arg(&format!("/OUT:\"{manifest_dir}/../{test}.exe\"")); + + let exe_dir = format!("{manifest_dir}/../wasm-c-api/example"); + + // run vcvars + let vcvars_bat_path = find_vcvars64(&compiler).expect("no vcvars64.bat"); + let mut vcvars = std::process::Command::new("cmd"); + vcvars.arg("/C"); + vcvars.arg(vcvars_bat_path); + println!("running {vcvars:?}"); + + // cmd /C vcvars64.bat + let output = vcvars.output() + .expect("could not invoke vcvars64.bat at {vcvars_bat_path}"); + + if !output.status.success() { + println!(""); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + panic!("failed to invoke vcvars64.bat {test}"); + } + + println!("compiling {test}: {command:?}"); + + // compile + let output = command.output().expect(&format!("failed to compile {command:#?}")); + if !output.status.success() { + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); + panic!("failed to compile {test}"); + } + + let path = std::env::var("PATH").unwrap_or_default(); + let newpath = format!("{wasmer_dll_dir};{path}"); + + // execute + let mut command = std::process::Command::new(&format!("{manifest_dir}/../{test}.exe")); + command.env("PATH", newpath.clone()); + command.current_dir(exe_dir.clone()); + println!("executing {test}: {command:?}"); + println!("setting current dir = {exe_dir}"); + let output = command.output().expect(&format!("failed to run {command:#?}")); + if !output.status.success() { + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); + panic!("failed to execute {test}"); + } + + // cc -g -IC:/Users/felix/Development/wasmer/lib/c-api/tests/ + // -IC:/Users/felix/Development/wasmer/package/include + // + // -Wl,-rpath,C:/Users/felix/Development/wasmer/package/lib + // + // wasm-c-api/example/callback.c + // + // -LC:/Users/felix/Development/wasmer/package/lib -lwasmer + // + // -o wasm-c-api/example/callback + } - command.arg("/link"); - if !config.msvc_ldlibs.is_empty() { - command.arg(config.msvc_ldlibs.clone()); - } else if !config.wasmer_dir.is_empty() { - command.arg(&format!("/LIBPATH:{}/lib", config.wasmer_dir)); - command.arg(&format!("{}/lib/wasmer.dll.lib", config.wasmer_dir)); + } else { + for test in CAPI_BASE_TESTS.iter() { + + let mut command = std::process::Command::new("cc"); + + command.arg(config.cflags.clone()); + command.arg(config.ldflags.clone()); + command.arg(&format!("{manifest_dir}/../{test}.c")); + command.arg(config.ldlibs.clone()); + command.arg("-o"); + command.arg(&format!("{manifest_dir}/../{test}")); + + // compile + let output = command.output().expect(&format!("failed to compile {command:#?}")); + if !output.status.success() { + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); + panic!("failed to compile {test}"); + } + + // execute + let mut command = std::process::Command::new(&format!("{manifest_dir}/../{test}")); + let output = command.output().expect(&format!("failed to run {command:#?}")); + if !output.status.success() { + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); + panic!("failed to execute {test}"); + } } - let wasmer_dll_dir = format!("{}/lib", config.wasmer_dir); - command.arg(&format!("/OUT:\"{manifest_dir}/../{test}.exe\"")); - - let exe_dir = format!("{manifest_dir}/../wasm-c-api/example"); - - // run vcvars - let vcvars_bat_path = find_vcvars64(&compiler).expect("no vcvars64.bat"); - let mut vcvars = std::process::Command::new("cmd"); - vcvars.arg("/C"); - vcvars.arg(vcvars_bat_path); - println!("running {vcvars:?}"); - - // cmd /C vcvars64.bat - let output = vcvars.output() - .expect("could not invoke vcvars64.bat at {vcvars_bat_path}"); - - if !output.status.success() { - println!(""); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); - panic!("failed to invoke vcvars64.bat {test}"); - } - - println!("compiling {test}: {command:?}"); - - // compile - let output = command.output().expect(&format!("failed to compile {command:#?}")); - if !output.status.success() { - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); - panic!("failed to compile {test}"); - } - - let path = std::env::var("PATH").unwrap_or_default(); - let newpath = format!("{wasmer_dll_dir};{path}"); - - // execute - let mut command = std::process::Command::new(&format!("{manifest_dir}/../{test}.exe")); - command.env("PATH", newpath.clone()); - command.current_dir(exe_dir.clone()); - println!("executing {test}: {command:?}"); - println!("setting current dir = {exe_dir}"); - let output = command.output().expect(&format!("failed to run {command:#?}")); - if !output.status.success() { - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); - panic!("failed to execute {test}"); - } - - // cc -g -IC:/Users/felix/Development/wasmer/lib/c-api/tests/ - // -IC:/Users/felix/Development/wasmer/package/include - // - // -Wl,-rpath,C:/Users/felix/Development/wasmer/package/lib - // - // wasm-c-api/example/callback.c - // - // -LC:/Users/felix/Development/wasmer/package/lib -lwasmer - // - // -o wasm-c-api/example/callback - } - #[cfg(not(target_os = "windows"))] for test in CAPI_BASE_TESTS.iter() { - - let mut command = std::process::Command::new("cc"); - - command.arg(config.cflags.clone()); - command.arg(config.ldflags.clone()); - command.arg(&format!("{manifest_dir}/../{test}.c")); - command.arg(config.ldlibs.clone()); - command.arg("-o"); - command.arg(&format!("{manifest_dir}/../{test}")); - - // compile - let output = command.output().expect(&format!("failed to compile {command:#?}")); - if !output.status.success() { - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); - panic!("failed to compile {test}"); - } - - // execute - let mut command = std::process::Command::new(&format!("{manifest_dir}/../{test}")); - let output = command.output().expect(&format!("failed to run {command:#?}")); - if !output.status.success() { - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stdout: {}", String::from_utf8_lossy(&output.stderr)); - panic!("failed to compile {test}"); - } + let _ = std::fs::remove_file(&format!("{manifest_dir}/{test}.obj")); + let _ = std::fs::remove_file(&format!("{manifest_dir}/../{test}.exe")); + let _ = std::fs::remove_file(&format!("{manifest_dir}/../{test}")); } }