diff --git a/Cargo.toml b/Cargo.toml index 706c467a3a..2dbc0b867d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ exclude = [ "compiler/test_mono_macros", # `cargo build` would cause roc_std to be built with default features which errors on windows "roc_std", + "wasi-libc-sys", ] # Needed to be able to run `cargo run -p roc_cli --no-default-features` - # see www/build.sh for more. diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 3acb21720d..bcee333e6e 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -72,16 +72,12 @@ fn find_zig_str_path() -> PathBuf { } fn find_wasi_libc_path() -> PathBuf { - let wasi_libc_path = PathBuf::from("compiler/builtins/bitcode/wasi-libc.a"); - - if std::path::Path::exists(&wasi_libc_path) { - return wasi_libc_path; - } - - // when running the tests, we start in the /cli directory - let wasi_libc_path = PathBuf::from("../compiler/builtins/bitcode/wasi-libc.a"); - if std::path::Path::exists(&wasi_libc_path) { - return wasi_libc_path; + // Environment variable defined in wasi-libc-sys/build.rs + if let Ok(wasi_libc_path) = std::env::var("WASI_LIBC_SYS_PATH") { + let wasi_libc_pathbuf = PathBuf::from(&wasi_libc_path); + if std::path::Path::exists(&wasi_libc_pathbuf) { + return wasi_libc_pathbuf; + } } panic!("cannot find `wasi-libc.a`") diff --git a/compiler/builtins/bitcode/wasi-libc.a b/compiler/builtins/bitcode/wasi-libc.a deleted file mode 100644 index 70378bcf13..0000000000 Binary files a/compiler/builtins/bitcode/wasi-libc.a and /dev/null differ diff --git a/wasi-libc-sys/Cargo.toml b/wasi-libc-sys/Cargo.toml new file mode 100644 index 0000000000..1732300332 --- /dev/null +++ b/wasi-libc-sys/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["The Roc Contributors"] +description = "Rust wrapper for a WebAssembly test platform built on libc" +edition = "2018" +license = "UPL-1.0" +name = "wasi_libc_sys" +repository = "https://github.com/rtfeldman/roc" +version = "0.1.0" diff --git a/wasi-libc-sys/build.rs b/wasi-libc-sys/build.rs new file mode 100644 index 0000000000..b4d00f815d --- /dev/null +++ b/wasi-libc-sys/build.rs @@ -0,0 +1,70 @@ +use std::env; +use std::fs; + +// Environment variable that can be used from other build scripts +const WASI_LIBC_SYS_PATH: &str = "WASI_LIBC_SYS_PATH"; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=src/dummy.c"); + + let out_dir = env::var("OUT_DIR").unwrap(); + let zig_cache_dir = format!("{}/zig-cache", out_dir); + let out_file = format!("{}/wasi-libc.a", out_dir); + println!("cargo:rustc-env={}={}", WASI_LIBC_SYS_PATH, &out_file); + + // Compile a dummy C program with Zig, putting libc into our own private cache directory + let args = [ + "build-exe", + "-target", + "wasm32-wasi", + "-lc", + "-O", + "ReleaseSmall", + "--global-cache-dir", + &zig_cache_dir, + "src/dummy.c", + &format!("-femit-bin={}/dummy.wasm", out_dir), + ]; + + let zig = zig_executable(); + + // println!("{} {}", zig, args.join(" ")); + + run_command(Path::new("."), &zig, args); + let zig_libc_path = run_command(Path::new("."), "find", [&zig_cache_dir, "-name", "libc.a"]); + + // Copy libc out of Zig's cache, to where Cargo expects it + fs::copy(&zig_libc_path, &out_file); +} + +fn zig_executable() -> String { + match std::env::var("ROC_ZIG") { + Ok(path) => path, + Err(_) => "zig".into(), + } +} + +fn run_command>(path: P, command_str: &str, args: I) -> String +where + I: IntoIterator, + S: AsRef, +{ + let output_result = Command::new(OsStr::new(&command_str)) + .current_dir(path) + .args(args) + .output(); + match output_result { + Ok(output) => match output.status.success() { + true => std::str::from_utf8(&output.stdout).unwrap().to_string(), + false => { + let error_str = match std::str::from_utf8(&output.stderr) { + Ok(stderr) => stderr.to_string(), + Err(_) => format!("Failed to run \"{}\"", command_str), + }; + panic!("{} failed: {}", command_str, error_str); + } + }, + Err(reason) => panic!("{} failed: {}", command_str, reason), + } +} diff --git a/wasi-libc-sys/src/dummy.c b/wasi-libc-sys/src/dummy.c new file mode 100644 index 0000000000..5f247ac932 --- /dev/null +++ b/wasi-libc-sys/src/dummy.c @@ -0,0 +1,6 @@ +#include + +int main(int argc, char **argv) +{ + printf("I am a dummy C program. I only exist to help the build script to find libc.a and copy it"); +} diff --git a/wasi-libc-sys/src/lib.rs b/wasi-libc-sys/src/lib.rs new file mode 100644 index 0000000000..5fcf78879c --- /dev/null +++ b/wasi-libc-sys/src/lib.rs @@ -0,0 +1,11 @@ +use core::ffi::c_void; + +// Rust's libc crate doesn't support Wasm, so we provide an implementation from Zig +// We define Rust signatures here as we need them, rather than trying to cover all of libc +extern "C" { + pub fn malloc(size: usize) -> *mut c_void; + pub fn free(p: *mut c_void); + pub fn realloc(p: *mut c_void, size: usize) -> *mut c_void; + pub fn memcpy(dst: *mut c_void, src: *mut c_void, n: usize) -> *mut c_void; + pub fn memset(dst: *mut c_void, ch: i32, n: usize) -> *mut c_void; +}