Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for wasm32-wasi #245

Merged
merged 6 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 126 additions & 6 deletions sys/build.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,92 @@
use std::{
env, fs,
io::Write,
path::Path,
process::{Command, Stdio},
path::{Path, PathBuf},
process::{self, Command, Stdio},
};

// WASI logic lifted from https://github.com/bytecodealliance/javy/blob/61616e1507d2bf896f46dc8d72687273438b58b2/crates/quickjs-wasm-sys/build.rs#L18

const WASI_SDK_VERSION_MAJOR: usize = 20;
const WASI_SDK_VERSION_MINOR: usize = 0;

fn download_wasi_sdk() -> PathBuf {
let mut wasi_sdk_dir: PathBuf = env::var("OUT_DIR").unwrap().into();
wasi_sdk_dir.push("wasi-sdk");

fs::create_dir_all(&wasi_sdk_dir).unwrap();

let major_version = WASI_SDK_VERSION_MAJOR;
let minor_version = WASI_SDK_VERSION_MINOR;

let mut archive_path = wasi_sdk_dir.clone();
archive_path.push(format!("wasi-sdk-{major_version}-{minor_version}.tar.gz"));

println!("SDK tar: {archive_path:?}");

// Download archive if necessary
if !archive_path.try_exists().unwrap() {
let file_suffix = match (env::consts::OS, env::consts::ARCH) {
("linux", "x86") | ("linux", "x86_64") => "linux",
("macos", "x86") | ("macos", "x86_64") | ("macos", "aarch64") => "macos",
("windows", "x86") => "mingw-x86",
("windows", "x86_64") => "mingw",
other => panic!("Unsupported platform tuple {:?}", other),
};

let uri = format!("https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-{major_version}/wasi-sdk-{major_version}.{minor_version}-{file_suffix}.tar.gz");

println!("Downloading WASI SDK archive from {uri} to {archive_path:?}");

let output = process::Command::new("curl")
.args([
"--location",
"-o",
archive_path.to_string_lossy().as_ref(),
uri.as_ref(),
])
.output()
.unwrap();
println!("curl output: {}", String::from_utf8_lossy(&output.stdout));
println!("curl err: {}", String::from_utf8_lossy(&output.stderr));
if !output.status.success() {
panic!(
"curl WASI SDK failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}

let mut test_binary = wasi_sdk_dir.clone();
test_binary.extend(["bin", "wasm-ld"]);
// Extract archive if necessary
if !test_binary.try_exists().unwrap() {
println!("Extracting WASI SDK archive {archive_path:?}");
let output = process::Command::new("tar")
.args([
"-zxf",
archive_path.to_string_lossy().as_ref(),
"--strip-components",
"1",
])
.current_dir(&wasi_sdk_dir)
.output()
.unwrap();
if !output.status.success() {
panic!(
"Unpacking WASI SDK failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}

wasi_sdk_dir
}

fn get_wasi_sdk_path() -> PathBuf {
download_wasi_sdk()
}

fn main() {
#[cfg(feature = "logging")]
pretty_env_logger::init();
Expand Down Expand Up @@ -92,7 +174,8 @@ fn main() {
}

for file in source_files.iter().chain(header_files.iter()) {
fs::copy(src_dir.join(file), out_dir.join(file)).expect("Unable to copy source");
fs::copy(src_dir.join(file), out_dir.join(file))
.expect("Unable to copy source; try 'git submodule update --init'");
}
fs::copy("quickjs.bind.h", out_dir.join("quickjs.bind.h")).expect("Unable to copy source");

Expand All @@ -101,16 +184,50 @@ fn main() {
patch(out_dir, patches_dir.join(file));
}

let mut add_cflags = vec![];
if env::var("CARGO_CFG_TARGET_OS").unwrap() == "wasi" {
let wasi_sdk_path = get_wasi_sdk_path();
if !wasi_sdk_path.try_exists().unwrap() {
panic!(
"wasi-sdk not installed in specified path of {}",
wasi_sdk_path.display()
);
}
env::set_var("CC", wasi_sdk_path.join("bin/clang").to_str().unwrap());
env::set_var("AR", wasi_sdk_path.join("bin/ar").to_str().unwrap());
let sysroot = format!(
"--sysroot={}",
wasi_sdk_path.join("share/wasi-sysroot").display()
);
env::set_var("CFLAGS", &sysroot);
add_cflags.push(sysroot);
}

// generating bindings
bindgen(out_dir, out_dir.join("quickjs.bind.h"), &defines);
bindgen(
out_dir,
out_dir.join("quickjs.bind.h"),
&defines,
add_cflags,
);

let mut builder = cc::Build::new();
builder
.extra_warnings(false)
.flag_if_supported("-Wno-implicit-const-int-float-conversion")
//.flag("-Wno-array-bounds")
//.flag("-Wno-format-truncation")
;

if env::var("CARGO_CFG_TARGET_OS").unwrap() == "wasi" {
// pretend we're emscripten - there are already ifdefs that match
// also, wasi doesn't ahve FE_DOWNWARD or FE_UPWARD
builder
.define("EMSCRIPTEN", "1")
.define("FE_DOWNWARD", "0")
.define("FE_UPWARD", "0");
}

for (name, value) in &defines {
builder.define(name, *value);
}
Expand Down Expand Up @@ -149,7 +266,7 @@ fn patch<D: AsRef<Path>, P: AsRef<Path>>(out_dir: D, patch: P) {
}

#[cfg(not(feature = "bindgen"))]
fn bindgen<'a, D, H, X, K, V>(out_dir: D, _header_file: H, _defines: X)
fn bindgen<'a, D, H, X, K, V>(out_dir: D, _header_file: H, _defines: X, _add_cflags: Vec<String>)
where
D: AsRef<Path>,
H: AsRef<Path>,
Expand Down Expand Up @@ -187,7 +304,7 @@ where
}

#[cfg(feature = "bindgen")]
fn bindgen<'a, D, H, X, K, V>(out_dir: D, header_file: H, defines: X)
fn bindgen<'a, D, H, X, K, V>(out_dir: D, header_file: H, defines: X, mut add_cflags: Vec<String>)
where
D: AsRef<Path>,
H: AsRef<Path>,
Expand All @@ -200,6 +317,7 @@ where
let header_file = header_file.as_ref();

let mut cflags = vec![format!("--target={}", target)];
cflags.append(&mut add_cflags);

//format!("-I{}", out_dir.parent().display()),

Expand All @@ -211,6 +329,8 @@ where
});
}

println!("Bindings for target: {}", target);

let bindings = bindgen_rs::Builder::default()
.detect_include_paths(true)
.clang_arg("-xc")
Expand Down
2 changes: 1 addition & 1 deletion sys/quickjs.bind.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// A header which imports the all symbols of the quickjs header but also exports the static atoms.

#include "quickjs.h";
#include "quickjs.h"


#if !defined(EMSCRIPTEN) && !defined(_MSC_VER)
Expand Down
Loading