mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 14:54:47 +00:00
Merge branch 'trunk' into str_trim_left
This commit is contained in:
commit
eb1b6d97bf
16 changed files with 169 additions and 69 deletions
|
@ -240,7 +240,7 @@ pub fn build_file<'a>(
|
||||||
app_o_file.to_str().unwrap(),
|
app_o_file.to_str().unwrap(),
|
||||||
];
|
];
|
||||||
if matches!(opt_level, OptLevel::Development) {
|
if matches!(opt_level, OptLevel::Development) {
|
||||||
inputs.push(bitcode::OBJ_PATH);
|
inputs.push(bitcode::BUILTINS_HOST_OBJ_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut child, _) = // TODO use lld
|
let (mut child, _) = // TODO use lld
|
||||||
|
|
|
@ -97,7 +97,7 @@ pub fn build_zig_host_native(
|
||||||
"build-exe",
|
"build-exe",
|
||||||
"-fPIE",
|
"-fPIE",
|
||||||
shared_lib_path.to_str().unwrap(),
|
shared_lib_path.to_str().unwrap(),
|
||||||
bitcode::OBJ_PATH,
|
bitcode::BUILTINS_HOST_OBJ_PATH,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
command.args(&["build-obj", "-fPIC"]);
|
command.args(&["build-obj", "-fPIC"]);
|
||||||
|
@ -186,7 +186,7 @@ pub fn build_zig_host_native(
|
||||||
"build-exe",
|
"build-exe",
|
||||||
"-fPIE",
|
"-fPIE",
|
||||||
shared_lib_path.to_str().unwrap(),
|
shared_lib_path.to_str().unwrap(),
|
||||||
bitcode::OBJ_PATH,
|
bitcode::BUILTINS_HOST_OBJ_PATH,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
command.args(&["build-obj", "-fPIC"]);
|
command.args(&["build-obj", "-fPIC"]);
|
||||||
|
@ -282,7 +282,7 @@ pub fn build_c_host_native(
|
||||||
if let Some(shared_lib_path) = shared_lib_path {
|
if let Some(shared_lib_path) = shared_lib_path {
|
||||||
command.args(&[
|
command.args(&[
|
||||||
shared_lib_path.to_str().unwrap(),
|
shared_lib_path.to_str().unwrap(),
|
||||||
bitcode::OBJ_PATH,
|
bitcode::BUILTINS_HOST_OBJ_PATH,
|
||||||
"-fPIE",
|
"-fPIE",
|
||||||
"-pie",
|
"-pie",
|
||||||
"-lm",
|
"-lm",
|
||||||
|
@ -878,7 +878,7 @@ fn link_wasm32(
|
||||||
let zig_str_path = find_zig_str_path();
|
let zig_str_path = find_zig_str_path();
|
||||||
let wasi_libc_path = find_wasi_libc_path();
|
let wasi_libc_path = find_wasi_libc_path();
|
||||||
|
|
||||||
let child = Command::new("zig9")
|
let child = Command::new("zig")
|
||||||
// .env_clear()
|
// .env_clear()
|
||||||
// .env("PATH", &env_path)
|
// .env("PATH", &env_path)
|
||||||
.args(&["build-exe"])
|
.args(&["build-exe"])
|
||||||
|
|
|
@ -59,8 +59,9 @@ fn generateLlvmIrFile(
|
||||||
|
|
||||||
// Generate Object File
|
// Generate Object File
|
||||||
// TODO: figure out how to get this to emit symbols that are only scoped to linkage (global but hidden).
|
// TODO: figure out how to get this to emit symbols that are only scoped to linkage (global but hidden).
|
||||||
// Also, zig has -ffunction-sections, but I am not sure how to add it here.
|
// @bhansconnect: I believe anything with global scope will still be preserved by the linker even if it
|
||||||
// With both of those changes, unused zig functions will be cleaned up by the linker saving around 100k.
|
// is never called. I think it could theoretically be called by a dynamic lib that links to the executable
|
||||||
|
// or something similar.
|
||||||
fn generateObjectFile(
|
fn generateObjectFile(
|
||||||
b: *Builder,
|
b: *Builder,
|
||||||
mode: std.builtin.Mode,
|
mode: std.builtin.Mode,
|
||||||
|
@ -75,6 +76,7 @@ fn generateObjectFile(
|
||||||
obj.setOutputDir(".");
|
obj.setOutputDir(".");
|
||||||
obj.strip = true;
|
obj.strip = true;
|
||||||
obj.target = target;
|
obj.target = target;
|
||||||
|
obj.link_function_sections = true;
|
||||||
const obj_step = b.step(step_name, "Build object file for linking");
|
const obj_step = b.step(step_name, "Build object file for linking");
|
||||||
obj_step.dependOn(&obj.step);
|
obj_step.dependOn(&obj.step);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
|
|
||||||
pub const OBJ_PATH: &str = env!(
|
pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
|
||||||
"BUILTINS_HOST_O",
|
"BUILTINS_HOST_O",
|
||||||
"Env var BUILTINS_HOST_O not found. Is there a problem with the build script?"
|
"Env var BUILTINS_HOST_O not found. Is there a problem with the build script?"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pub const BUILTINS_WASM32_OBJ_PATH: &str = env!(
|
||||||
|
"BUILTINS_WASM32_O",
|
||||||
|
"Env var BUILTINS_WASM32_O not found. Is there a problem with the build script?"
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct IntrinsicName {
|
pub struct IntrinsicName {
|
||||||
pub options: [&'static str; 14],
|
pub options: [&'static str; 14],
|
||||||
|
|
|
@ -11,7 +11,8 @@ use roc_mono::layout::{Layout, LayoutIds};
|
||||||
use crate::layout::WasmLayout;
|
use crate::layout::WasmLayout;
|
||||||
use crate::storage::{Storage, StoredValue, StoredValueKind};
|
use crate::storage::{Storage, StoredValue, StoredValueKind};
|
||||||
use crate::wasm_module::linking::{
|
use crate::wasm_module::linking::{
|
||||||
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_UNDEFINED,
|
DataSymbol, LinkingSection, RelocationSection, WasmObjectSymbol, WASM_SYM_BINDING_WEAK,
|
||||||
|
WASM_SYM_UNDEFINED,
|
||||||
};
|
};
|
||||||
use crate::wasm_module::sections::{
|
use crate::wasm_module::sections::{
|
||||||
CodeSection, DataMode, DataSection, DataSegment, ExportSection, FunctionSection, GlobalSection,
|
CodeSection, DataMode, DataSection, DataSegment, ExportSection, FunctionSection, GlobalSection,
|
||||||
|
@ -21,7 +22,10 @@ use crate::wasm_module::{
|
||||||
code_builder, BlockType, CodeBuilder, ConstExpr, Export, ExportType, Global, GlobalType,
|
code_builder, BlockType, CodeBuilder, ConstExpr, Export, ExportType, Global, GlobalType,
|
||||||
LocalId, Signature, SymInfo, ValueType,
|
LocalId, Signature, SymInfo, ValueType,
|
||||||
};
|
};
|
||||||
use crate::{copy_memory, CopyMemoryConfig, Env, PTR_TYPE};
|
use crate::{
|
||||||
|
copy_memory, CopyMemoryConfig, Env, BUILTINS_IMPORT_MODULE_NAME, MEMORY_NAME, PTR_TYPE,
|
||||||
|
STACK_POINTER_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
/// The memory address where the constants data will be loaded during module instantiation.
|
/// The memory address where the constants data will be loaded during module instantiation.
|
||||||
/// We avoid address zero and anywhere near it. They're valid addresses but maybe bug-prone.
|
/// We avoid address zero and anywhere near it. They're valid addresses but maybe bug-prone.
|
||||||
|
@ -31,8 +35,6 @@ const CONST_SEGMENT_BASE_ADDR: u32 = 1024;
|
||||||
/// Index of the data segment where we store constants
|
/// Index of the data segment where we store constants
|
||||||
const CONST_SEGMENT_INDEX: usize = 0;
|
const CONST_SEGMENT_INDEX: usize = 0;
|
||||||
|
|
||||||
const IMPORT_MODULE_BUILTINS: &str = "builtins";
|
|
||||||
|
|
||||||
pub struct WasmBackend<'a> {
|
pub struct WasmBackend<'a> {
|
||||||
env: &'a Env<'a>,
|
env: &'a Env<'a>,
|
||||||
|
|
||||||
|
@ -66,7 +68,7 @@ impl<'a> WasmBackend<'a> {
|
||||||
let num_procs = proc_symbols.len();
|
let num_procs = proc_symbols.len();
|
||||||
|
|
||||||
exports.push(Export {
|
exports.push(Export {
|
||||||
name: "__linear_memory".to_string(),
|
name: MEMORY_NAME.to_string(),
|
||||||
ty: ExportType::Mem,
|
ty: ExportType::Mem,
|
||||||
index: 0,
|
index: 0,
|
||||||
});
|
});
|
||||||
|
@ -78,10 +80,17 @@ impl<'a> WasmBackend<'a> {
|
||||||
},
|
},
|
||||||
init: ConstExpr::I32(MEMORY_INIT_SIZE as i32),
|
init: ConstExpr::I32(MEMORY_INIT_SIZE as i32),
|
||||||
};
|
};
|
||||||
linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined {
|
|
||||||
flags: 0,
|
exports.push(Export {
|
||||||
|
name: STACK_POINTER_NAME.to_string(),
|
||||||
|
ty: ExportType::Global,
|
||||||
index: 0,
|
index: 0,
|
||||||
name: "__stack_pointer".to_string(),
|
});
|
||||||
|
|
||||||
|
linker_symbols.push(SymInfo::Global(WasmObjectSymbol::Defined {
|
||||||
|
flags: WASM_SYM_BINDING_WEAK,
|
||||||
|
index: 0,
|
||||||
|
name: STACK_POINTER_NAME.to_string(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let const_segment = DataSegment {
|
let const_segment = DataSegment {
|
||||||
|
@ -759,7 +768,7 @@ impl<'a> WasmBackend<'a> {
|
||||||
|
|
||||||
let import_index = self.module.import.entries.len() as u32;
|
let import_index = self.module.import.entries.len() as u32;
|
||||||
let import = Import {
|
let import = Import {
|
||||||
module: IMPORT_MODULE_BUILTINS,
|
module: BUILTINS_IMPORT_MODULE_NAME,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
description: ImportDesc::Func { signature_index },
|
description: ImportDesc::Func { signature_index },
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,9 @@ const PTR_TYPE: ValueType = ValueType::I32;
|
||||||
|
|
||||||
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
|
pub const STACK_POINTER_GLOBAL_ID: u32 = 0;
|
||||||
pub const FRAME_ALIGNMENT_BYTES: i32 = 16;
|
pub const FRAME_ALIGNMENT_BYTES: i32 = 16;
|
||||||
|
pub const MEMORY_NAME: &str = "memory";
|
||||||
|
pub const BUILTINS_IMPORT_MODULE_NAME: &str = "builtins";
|
||||||
|
pub const STACK_POINTER_NAME: &str = "__stack_pointer";
|
||||||
|
|
||||||
pub struct Env<'a> {
|
pub struct Env<'a> {
|
||||||
pub arena: &'a Bump,
|
pub arena: &'a Bump,
|
||||||
|
|
|
@ -2159,7 +2159,8 @@ fn list_literal_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, List<'a>>
|
||||||
min_indent,
|
min_indent,
|
||||||
List::Open,
|
List::Open,
|
||||||
List::Space,
|
List::Space,
|
||||||
List::IndentEnd
|
List::IndentEnd,
|
||||||
|
Expr::SpaceBefore
|
||||||
)
|
)
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
|
|
@ -1261,28 +1261,14 @@ macro_rules! collection_trailing_sep {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! collection_trailing_sep_e {
|
macro_rules! collection_trailing_sep_e {
|
||||||
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr) => {
|
($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $min_indent:expr, $open_problem:expr, $space_problem:expr, $indent_problem:expr, $space_before:expr) => {
|
||||||
skip_first!(
|
skip_first!(
|
||||||
$opening_brace,
|
$opening_brace,
|
||||||
skip_first!(
|
|
||||||
// We specifically allow space characters inside here, so that
|
|
||||||
// `[ ]` can be successfully parsed as an empty list, and then
|
|
||||||
// changed by the formatter back into `[]`.
|
|
||||||
//
|
|
||||||
// We don't allow newlines or comments in the middle of empty
|
|
||||||
// roc_collections because those are normally stored in an Expr,
|
|
||||||
// and there's no Expr in which to store them in an empty collection!
|
|
||||||
//
|
|
||||||
// We could change the AST to add extra storage specifically to
|
|
||||||
// support empty literals containing newlines or comments, but this
|
|
||||||
// does not seem worth even the tiniest regression in compiler performance.
|
|
||||||
zero_or_more!($crate::parser::word1(b' ', |row, col| $space_problem(
|
|
||||||
crate::parser::BadInputError::LineTooLong,
|
|
||||||
row,
|
|
||||||
col
|
|
||||||
))),
|
|
||||||
|arena, state| {
|
|arena, state| {
|
||||||
let (_, elements, state) =
|
let (_, spaces, state) = space0_e($min_indent, $space_problem, $indent_problem)
|
||||||
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
let (_, (mut parsed_elems, mut final_comments), state) =
|
||||||
and!(
|
and!(
|
||||||
$crate::parser::trailing_sep_by0(
|
$crate::parser::trailing_sep_by0(
|
||||||
$delimiter,
|
$delimiter,
|
||||||
|
@ -1298,16 +1284,23 @@ macro_rules! collection_trailing_sep_e {
|
||||||
).parse(arena, state)?;
|
).parse(arena, state)?;
|
||||||
|
|
||||||
let (_,_, state) =
|
let (_,_, state) =
|
||||||
if elements.0.is_empty() {
|
if parsed_elems.is_empty() {
|
||||||
one_of_with_error![$open_problem; $closing_brace].parse(arena, state)?
|
one_of_with_error![$open_problem; $closing_brace].parse(arena, state)?
|
||||||
} else {
|
} else {
|
||||||
$closing_brace.parse(arena, state)?
|
$closing_brace.parse(arena, state)?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !spaces.is_empty() {
|
||||||
Ok((MadeProgress, elements, state))
|
if let Some(first) = parsed_elems.first_mut() {
|
||||||
|
first.value = $space_before(arena.alloc(first.value), spaces)
|
||||||
|
} else {
|
||||||
|
assert!(final_comments.is_empty());
|
||||||
|
final_comments = spaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((MadeProgress, (parsed_elems, final_comments), state))
|
||||||
}
|
}
|
||||||
)
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -326,7 +326,8 @@ fn record_pattern_help<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>, PRec
|
||||||
min_indent,
|
min_indent,
|
||||||
PRecord::Open,
|
PRecord::Open,
|
||||||
PRecord::Space,
|
PRecord::Space,
|
||||||
PRecord::IndentEnd
|
PRecord::IndentEnd,
|
||||||
|
Pattern::SpaceBefore
|
||||||
)
|
)
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TT
|
||||||
min_indent,
|
min_indent,
|
||||||
TTagUnion::Open,
|
TTagUnion::Open,
|
||||||
TTagUnion::Space,
|
TTagUnion::Space,
|
||||||
TTagUnion::IndentEnd
|
TTagUnion::IndentEnd,
|
||||||
|
Tag::SpaceBefore
|
||||||
)
|
)
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
@ -276,7 +277,8 @@ fn record_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TReco
|
||||||
min_indent,
|
min_indent,
|
||||||
TRecord::Open,
|
TRecord::Open,
|
||||||
TRecord::Space,
|
TRecord::Space,
|
||||||
TRecord::IndentEnd
|
TRecord::IndentEnd,
|
||||||
|
AssignedField::SpaceBefore
|
||||||
)
|
)
|
||||||
.parse(arena, state)?;
|
.parse(arena, state)?;
|
||||||
|
|
||||||
|
|
|
@ -1193,6 +1193,30 @@ mod test_parse {
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newline_inside_empty_list() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let expected = List {
|
||||||
|
items: &[],
|
||||||
|
final_comments: &[Newline],
|
||||||
|
};
|
||||||
|
let actual = parse_expr_with(&arena, "[\n]");
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn comment_inside_empty_list() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let expected = List {
|
||||||
|
items: &[],
|
||||||
|
final_comments: &[LineComment("comment")],
|
||||||
|
};
|
||||||
|
let actual = parse_expr_with(&arena, "[#comment\n]");
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn packed_singleton_list() {
|
fn packed_singleton_list() {
|
||||||
let arena = Bump::new();
|
let arena = Bump::new();
|
||||||
|
@ -1219,6 +1243,24 @@ mod test_parse {
|
||||||
assert_eq!(Ok(expected), actual);
|
assert_eq!(Ok(expected), actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn newline_singleton_list() {
|
||||||
|
let arena = Bump::new();
|
||||||
|
let item = &*arena.alloc(Expr::SpaceAfter(
|
||||||
|
arena.alloc(Num("1")),
|
||||||
|
arena.alloc([Newline]),
|
||||||
|
));
|
||||||
|
let item = Expr::SpaceBefore(item, arena.alloc([Newline]));
|
||||||
|
let items = [&*arena.alloc(Located::new(1, 1, 0, 1, item))];
|
||||||
|
let expected = List {
|
||||||
|
items: &items,
|
||||||
|
final_comments: &[],
|
||||||
|
};
|
||||||
|
let actual = parse_expr_with(&arena, "[\n1\n]");
|
||||||
|
|
||||||
|
assert_eq!(Ok(expected), actual);
|
||||||
|
}
|
||||||
|
|
||||||
// FIELD ACCESS
|
// FIELD ACCESS
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1330,7 +1330,7 @@ fn pow_int() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
|
||||||
fn atan() {
|
fn atan() {
|
||||||
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
|
assert_evals_to!("Num.atan 10", 1.4711276743037347, f64);
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,10 @@ pub fn helper(
|
||||||
app_o_file.clone(),
|
app_o_file.clone(),
|
||||||
// Long term we probably want a smarter way to link in zig builtins.
|
// Long term we probably want a smarter way to link in zig builtins.
|
||||||
// With the current method all methods are kept and it adds about 100k to all outputs.
|
// With the current method all methods are kept and it adds about 100k to all outputs.
|
||||||
&[app_o_file.to_str().unwrap(), bitcode::OBJ_PATH],
|
&[
|
||||||
|
app_o_file.to_str().unwrap(),
|
||||||
|
bitcode::BUILTINS_HOST_OBJ_PATH,
|
||||||
|
],
|
||||||
LinkType::Dylib,
|
LinkType::Dylib,
|
||||||
)
|
)
|
||||||
.expect("failed to link dynamic library");
|
.expect("failed to link dynamic library");
|
||||||
|
|
|
@ -367,7 +367,7 @@ pub fn helper_wasm<'a>(
|
||||||
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
Command::new("zig9")
|
Command::new("zig")
|
||||||
.current_dir(dir_path)
|
.current_dir(dir_path)
|
||||||
.args(&[
|
.args(&[
|
||||||
"wasm-ld",
|
"wasm-ld",
|
||||||
|
|
|
@ -4,8 +4,12 @@ use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
|
use crate::helpers::from_wasm32_memory::FromWasm32Memory;
|
||||||
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
use crate::helpers::wasm32_test_result::Wasm32TestResult;
|
||||||
|
use roc_builtins::bitcode;
|
||||||
use roc_can::builtins::builtin_defs_map;
|
use roc_can::builtins::builtin_defs_map;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, MutSet};
|
||||||
|
use roc_gen_wasm::MEMORY_NAME;
|
||||||
|
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||||
|
|
||||||
|
@ -143,8 +147,43 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
||||||
use wasmer::{Instance, Module, Store};
|
use wasmer::{Instance, Module, Store};
|
||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
// let module = Module::from_file(&store, &test_wasm_path).unwrap();
|
|
||||||
let wasmer_module = Module::from_binary(&store, &module_bytes).unwrap();
|
let wasmer_module = {
|
||||||
|
let dir = tempdir().unwrap();
|
||||||
|
let dirpath = dir.path();
|
||||||
|
let final_wasm_file = dirpath.join("final.wasm");
|
||||||
|
let app_o_file = dirpath.join("app.o");
|
||||||
|
|
||||||
|
// write the module to a file so the linker can access it
|
||||||
|
std::fs::write(&app_o_file, &module_bytes).unwrap();
|
||||||
|
|
||||||
|
std::process::Command::new("zig")
|
||||||
|
.args(&[
|
||||||
|
"wasm-ld",
|
||||||
|
// input files
|
||||||
|
app_o_file.to_str().unwrap(),
|
||||||
|
bitcode::BUILTINS_WASM32_OBJ_PATH,
|
||||||
|
// output
|
||||||
|
"-o",
|
||||||
|
final_wasm_file.to_str().unwrap(),
|
||||||
|
// we don't define `_start`
|
||||||
|
"--no-entry",
|
||||||
|
// If you only specify test_wrapper, it will stop at the call to UserApp_main_1
|
||||||
|
// But if you specify both exports, you get all the dependencies.
|
||||||
|
//
|
||||||
|
// It seems that it will not write out an export you didn't explicitly specify,
|
||||||
|
// even if it's a dependency of another export!
|
||||||
|
// In our case we always export main and test_wrapper so that's OK.
|
||||||
|
"--export",
|
||||||
|
"test_wrapper",
|
||||||
|
"--export",
|
||||||
|
"#UserApp_main_1",
|
||||||
|
])
|
||||||
|
.output()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Module::from_file(&store, &final_wasm_file).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
// First, we create the `WasiEnv`
|
// First, we create the `WasiEnv`
|
||||||
use wasmer_wasi::WasiState;
|
use wasmer_wasi::WasiState;
|
||||||
|
@ -171,7 +210,7 @@ where
|
||||||
|
|
||||||
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &expected);
|
let instance = crate::helpers::wasm::helper_wasm(&arena, src, stdlib, &expected);
|
||||||
|
|
||||||
let memory = instance.exports.get_memory("__linear_memory").unwrap();
|
let memory = instance.exports.get_memory(MEMORY_NAME).unwrap();
|
||||||
|
|
||||||
let test_wrapper = instance.exports.get_function(TEST_WRAPPER_NAME).unwrap();
|
let test_wrapper = instance.exports.get_function(TEST_WRAPPER_NAME).unwrap();
|
||||||
|
|
||||||
|
|
2
examples/hello-web/.gitignore
vendored
2
examples/hello-web/.gitignore
vendored
|
@ -1,2 +1,2 @@
|
||||||
hello-web
|
hello-web.wasm
|
||||||
*.wat
|
*.wat
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue