repl_test: update build.rs to work with Zig 0.9 (like test_gen)

This commit is contained in:
Brian Carroll 2022-04-11 14:19:56 +01:00
parent 249925cb23
commit a663d335fc
3 changed files with 91 additions and 27 deletions

View file

@ -115,7 +115,7 @@ fn section_size(bytes: &[u8]) -> usize {
} }
fn parse_section<'a>(id: SectionId, module_bytes: &'a [u8], cursor: &mut usize) -> (u32, &'a [u8]) { fn parse_section<'a>(id: SectionId, module_bytes: &'a [u8], cursor: &mut usize) -> (u32, &'a [u8]) {
if module_bytes[*cursor] != id as u8 { if (*cursor >= module_bytes.len()) || (module_bytes[*cursor] != id as u8) {
return (0, &[]); return (0, &[]);
} }
*cursor += 1; *cursor += 1;

View file

@ -39,13 +39,13 @@ fn build_wasm() {
&platform_path, &platform_path,
&compiler_rt_path, &compiler_rt_path,
"-L", "-L",
&libc_dir, libc_dir,
"-lc", "-lc",
"-o", "-o",
&format!("{}/{}.o", out_dir, PLATFORM_FILENAME), &format!("{}/{}.o", out_dir, PLATFORM_FILENAME),
"--export-all", "--export-all",
"--no-entry", "--no-entry",
// "--emit-relocs", // TODO: resize stack by relocating __heap_base (issue #2480) // "--emit-relocs", // TODO: resize stack by relocating __heap_base (issue #2480) here and in repl_test build
]; ];
let zig = zig_executable(); let zig = zig_executable();

View file

@ -1,6 +1,6 @@
use std::env; use std::env;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::path::Path; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
use roc_builtins::bitcode; use roc_builtins::bitcode;
@ -10,7 +10,8 @@ const PRE_LINKED_BINARY: &str = "data/pre_linked_binary.o";
fn main() { fn main() {
println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=src/{}.c", PLATFORM_FILENAME); let source_path = format!("src/{}.c", PLATFORM_FILENAME);
println!("cargo:rerun-if-changed={}", source_path);
// When we build on Netlify, zig is not installed (but also not used, // When we build on Netlify, zig is not installed (but also not used,
// since all we're doing is generating docs), so we can skip the steps // since all we're doing is generating docs), so we can skip the steps
@ -23,26 +24,38 @@ fn main() {
std::fs::create_dir_all("./data").unwrap(); std::fs::create_dir_all("./data").unwrap();
// Build a pre-linked binary with platform, builtins and all their libc dependencies // Zig can produce *either* an object containing relocations OR an object containing libc code
// This builds a library file that exports all symbols. It has no linker data but we don't need it. // But we want both, so we have to compile twice with different flags, then link them
// See discussion with Luuk de Gram (Zig contributor)
// https://github.com/rtfeldman/roc/pull/2181#pullrequestreview-839608063 // Create an object file with relocations
let args = [ let out_dir = env::var("OUT_DIR").unwrap();
"build-lib", let platform_obj = build_wasm_platform(&out_dir, &source_path);
"-target",
"wasm32-wasi", // Compile again to get libc path
"-lc", let (libc_archive, compiler_rt_obj) = build_wasm_libc_compilerrt(&out_dir, &source_path);
"-dynamic", // -dynamic ensures libc code goes into the binary let mut libc_pathbuf = PathBuf::from(&libc_archive);
libc_pathbuf.pop();
let libc_dir = libc_pathbuf.to_str().unwrap();
let args = &[
"wasm-ld",
bitcode::BUILTINS_WASM32_OBJ_PATH, bitcode::BUILTINS_WASM32_OBJ_PATH,
&format!("src/{}.c", PLATFORM_FILENAME), &platform_obj,
&format!("-femit-bin={}", PRE_LINKED_BINARY), &compiler_rt_obj,
"-L",
libc_dir,
"-lc",
"-o",
PRE_LINKED_BINARY,
"--export-all",
"--no-entry",
]; ];
let zig = zig_executable(); let zig = zig_executable();
// println!("{} {}", zig, args.join(" ")); // println!("{} {}", zig, args.join(" "));
run_command(Path::new("."), &zig, args); run_command(&zig, args);
} }
fn zig_executable() -> String { fn zig_executable() -> String {
@ -52,26 +65,77 @@ fn zig_executable() -> String {
} }
} }
fn run_command<S, I, P: AsRef<Path>>(path: P, command_str: &str, args: I) -> String fn build_wasm_platform(out_dir: &str, source_path: &str) -> String {
where let platform_obj = format!("{}/{}.o", out_dir, PLATFORM_FILENAME);
I: IntoIterator<Item = S>,
S: AsRef<OsStr>, run_command(
{ &zig_executable(),
&[
"build-lib",
"-target",
"wasm32-wasi",
"-lc",
source_path,
&format!("-femit-bin={}", &platform_obj),
],
);
platform_obj
}
fn build_wasm_libc_compilerrt(out_dir: &str, source_path: &str) -> (String, String) {
let zig_cache_dir = format!("{}/zig-cache-wasm32", out_dir);
run_command(
&zig_executable(),
&[
"build-lib",
"-dynamic", // ensure libc code is actually generated (not just linked against header)
"-target",
"wasm32-wasi",
"-lc",
source_path,
"-femit-bin=/dev/null",
"--global-cache-dir",
&zig_cache_dir,
],
);
(
run_command("find", &[&zig_cache_dir, "-name", "libc.a"]),
run_command("find", &[&zig_cache_dir, "-name", "compiler_rt.o"]),
)
}
fn run_command(command_str: &str, args: &[&str]) -> String {
let output_result = Command::new(OsStr::new(&command_str)) let output_result = Command::new(OsStr::new(&command_str))
.current_dir(path) .current_dir(Path::new("."))
.args(args) .args(args)
.output(); .output();
let fail = |err: String| {
panic!(
"\n\nFailed command:\n\t{} {}\n\n{}",
command_str,
args.join(" "),
err
);
};
match output_result { match output_result {
Ok(output) => match output.status.success() { Ok(output) => match output.status.success() {
true => std::str::from_utf8(&output.stdout).unwrap().to_string(), true => std::str::from_utf8(&output.stdout)
.unwrap()
.trim()
.to_string(),
false => { false => {
let error_str = match std::str::from_utf8(&output.stderr) { let error_str = match std::str::from_utf8(&output.stderr) {
Ok(stderr) => stderr.to_string(), Ok(stderr) => stderr.to_string(),
Err(_) => format!("Failed to run \"{}\"", command_str), Err(_) => format!("Failed to run \"{}\"", command_str),
}; };
panic!("{} failed: {}", command_str, error_str); fail(error_str)
} }
}, },
Err(reason) => panic!("{} failed: {}", command_str, reason), Err(reason) => fail(reason.to_string()),
} }
} }