Skip to content

Commit

Permalink
Merge pull request #263 from DelSkayn/wasi-build
Browse files Browse the repository at this point in the history
Add support for building for wasi.
  • Loading branch information
DelSkayn authored Feb 9, 2024
2 parents 8a82e87 + c4b1d98 commit 343b21b
Show file tree
Hide file tree
Showing 3 changed files with 2,941 additions and 11 deletions.
143 changes: 133 additions & 10 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 @@ -91,8 +173,17 @@ fn main() {
}
}

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
defines.push(("EMSCRIPTEN".into(), Some("1")));
defines.push(("FE_DOWNWARD".into(), Some("0")));
defines.push(("FE_UPWARD".into(), Some("0")));
}

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,12 +192,37 @@ 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")
;
Expand Down Expand Up @@ -149,7 +265,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 +303,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 +316,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,7 +328,9 @@ where
});
}

let bindings = bindgen_rs::Builder::default()
println!("Bindings for target: {}", target);

let mut builder = bindgen_rs::Builder::default()
.detect_include_paths(true)
.clang_arg("-xc")
.clang_arg("-v")
Expand All @@ -225,9 +344,13 @@ where
.allowlist_var("JS.*")
.opaque_type("FILE")
.blocklist_type("FILE")
.blocklist_function("JS_DumpMemoryUsage")
.generate()
.expect("Unable to generate bindings");
.blocklist_function("JS_DumpMemoryUsage");

if env::var("CARGO_CFG_TARGET_OS").unwrap() == "wasi" {
builder = builder.clang_arg("-fvisibility=default");
}

let bindings = builder.generate().expect("Unable to generate bindings");

let bindings_file = out_dir.join("bindings.rs");

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

0 comments on commit 343b21b

Please sign in to comment.