mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Merge pull request #17815 from Luukdegram/wasm-no-entry
wasm-linker: implement `-fno-entry` and correctly pass `--shared` and `--pie` when given
This commit is contained in:
commit
702b809ea3
@ -11336,12 +11336,12 @@ all your base are belong to us{#end_shell_samp#}
|
||||
{#header_open|WebAssembly#}
|
||||
<p>Zig supports building for WebAssembly out of the box.</p>
|
||||
{#header_open|Freestanding#}
|
||||
<p>For host environments like the web browser and nodejs, build as a dynamic library using the freestanding
|
||||
<p>For host environments like the web browser and nodejs, build as an executable using the freestanding
|
||||
OS target. Here's an example of running Zig code compiled to WebAssembly with nodejs.</p>
|
||||
{#code_begin|lib|math#}
|
||||
{#code_begin|exe|math#}
|
||||
{#target_wasm#}
|
||||
{#link_mode_dynamic#}
|
||||
{#additonal_option|-rdynamic#}
|
||||
{#additonal_option|-fno-entry#}
|
||||
{#additonal_option|--export=add#}
|
||||
extern fn print(i32) void;
|
||||
|
||||
export fn add(a: i32, b: i32) void {
|
||||
|
||||
@ -189,7 +189,8 @@ dll_export_fns: ?bool = null,
|
||||
|
||||
subsystem: ?std.Target.SubSystem = null,
|
||||
|
||||
entry_symbol_name: ?[]const u8 = null,
|
||||
/// How the linker must handle the entry point of the executable.
|
||||
entry: Entry = .default,
|
||||
|
||||
/// List of symbols forced as undefined in the symbol table
|
||||
/// thus forcing their resolution by the linker.
|
||||
@ -304,6 +305,18 @@ const FrameworkLinkInfo = struct {
|
||||
weak: bool = false,
|
||||
};
|
||||
|
||||
const Entry = union(enum) {
|
||||
/// Let the compiler decide whether to make an entry point and what to name
|
||||
/// it.
|
||||
default,
|
||||
/// The executable will have no entry point.
|
||||
disabled,
|
||||
/// The executable will have an entry point with the default symbol name.
|
||||
enabled,
|
||||
/// The executable will have an entry point with the specified symbol name.
|
||||
symbol_name: []const u8,
|
||||
};
|
||||
|
||||
pub const IncludeDir = union(enum) {
|
||||
path: LazyPath,
|
||||
path_system: LazyPath,
|
||||
@ -1418,9 +1431,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||
try zig_args.append(try std.fmt.allocPrint(b.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
|
||||
}
|
||||
|
||||
if (self.entry_symbol_name) |entry| {
|
||||
try zig_args.append("--entry");
|
||||
try zig_args.append(entry);
|
||||
switch (self.entry) {
|
||||
.default => {},
|
||||
.disabled => try zig_args.append("-fno-entry"),
|
||||
.enabled => try zig_args.append("-fentry"),
|
||||
.symbol_name => |entry_name| {
|
||||
try zig_args.append(try std.fmt.allocPrint(b.allocator, "-fentry={s}", .{entry_name}));
|
||||
},
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@ -82,11 +82,15 @@ comptime {
|
||||
.reactor => "_initialize",
|
||||
.command => "_start",
|
||||
};
|
||||
if (!@hasDecl(root, wasm_start_sym)) {
|
||||
if (!@hasDecl(root, wasm_start_sym) and @hasDecl(root, "main")) {
|
||||
// Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
|
||||
// case it's not required to provide an entrypoint such as main.
|
||||
@export(wasi_start, .{ .name = wasm_start_sym });
|
||||
}
|
||||
} else if (native_arch.isWasm() and native_os == .freestanding) {
|
||||
if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
|
||||
// Only call main when defined. For WebAssembly it's allowed to pass `-fno-entry` in which
|
||||
// case it's not required to provide an entrypoint such as main.
|
||||
if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(wasm_freestanding_start, .{ .name = start_sym_name });
|
||||
} else if (native_os != .other and native_os != .freestanding) {
|
||||
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
|
||||
}
|
||||
|
||||
@ -2817,15 +2817,11 @@ fn setupExports(wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
fn setupStart(wasm: *Wasm) !void {
|
||||
const entry_name = wasm.base.options.entry orelse "_start";
|
||||
// do not export entry point if user set none or no default was set.
|
||||
const entry_name = wasm.base.options.entry orelse return;
|
||||
|
||||
const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
|
||||
if (wasm.base.options.output_mode == .Exe) {
|
||||
if (wasm.base.options.wasi_exec_model == .reactor) return; // Not required for reactors
|
||||
} else {
|
||||
return; // No entry point needed for non-executable wasm files
|
||||
}
|
||||
log.err("Entry symbol '{s}' missing", .{entry_name});
|
||||
log.err("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
|
||||
return error.MissingSymbol;
|
||||
};
|
||||
|
||||
@ -4535,6 +4531,8 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
|
||||
if (wasm.base.options.entry) |entry| {
|
||||
try argv.append("--entry");
|
||||
try argv.append(entry);
|
||||
} else {
|
||||
try argv.append("--no-entry");
|
||||
}
|
||||
|
||||
// Increase the default stack size to a more reasonable value of 1MB instead of
|
||||
@ -4544,24 +4542,17 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) !
|
||||
const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
|
||||
try argv.append(arg);
|
||||
|
||||
if (wasm.base.options.output_mode == .Exe) {
|
||||
if (wasm.base.options.wasi_exec_model == .reactor) {
|
||||
// Reactor execution model does not have _start so lld doesn't look for it.
|
||||
try argv.append("--no-entry");
|
||||
// Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor.
|
||||
// If rdynamic is true, it will already be appended, so only verify if the user did not specify
|
||||
// the flag in which case, we ensure `--export-dynamic` is called.
|
||||
if (!wasm.base.options.rdynamic) {
|
||||
try argv.append("--export-dynamic");
|
||||
}
|
||||
}
|
||||
} else if (wasm.base.options.entry == null) {
|
||||
try argv.append("--no-entry"); // So lld doesn't look for _start.
|
||||
}
|
||||
if (wasm.base.options.import_symbols) {
|
||||
try argv.append("--allow-undefined");
|
||||
}
|
||||
|
||||
if (wasm.base.options.output_mode == .Lib and wasm.base.options.link_mode == .Dynamic) {
|
||||
try argv.append("--shared");
|
||||
}
|
||||
if (wasm.base.options.pie) {
|
||||
try argv.append("--pie");
|
||||
}
|
||||
|
||||
// XXX - TODO: add when wasm-ld supports --build-id.
|
||||
// if (wasm.base.options.build_id) {
|
||||
// try argv.append("--build-id=tree");
|
||||
|
||||
57
src/main.zig
57
src/main.zig
@ -519,7 +519,9 @@ const usage_build_generic =
|
||||
\\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
|
||||
\\ --sysroot [path] Set the system root directory (usually /)
|
||||
\\ --version [ver] Dynamic library semver
|
||||
\\ --entry [name] Set the entrypoint symbol name
|
||||
\\ -fentry Enable entry point with default symbol name
|
||||
\\ -fentry=[name] Override the entry point symbol name
|
||||
\\ -fno-entry Do not output any entry point
|
||||
\\ --force_undefined [name] Specify the symbol must be defined for the link to succeed
|
||||
\\ -fsoname[=name] Override the default SONAME value
|
||||
\\ -fno-soname Disable emitting a SONAME
|
||||
@ -845,6 +847,7 @@ fn buildOutputType(
|
||||
var linker_import_symbols: bool = false;
|
||||
var linker_import_table: bool = false;
|
||||
var linker_export_table: bool = false;
|
||||
var linker_force_entry: ?bool = null;
|
||||
var linker_initial_memory: ?u64 = null;
|
||||
var linker_max_memory: ?u64 = null;
|
||||
var linker_shared_memory: bool = false;
|
||||
@ -1081,8 +1084,8 @@ fn buildOutputType(
|
||||
subsystem = try parseSubSystem(args_iter.nextOrFatal());
|
||||
} else if (mem.eql(u8, arg, "-O")) {
|
||||
optimize_mode_string = args_iter.nextOrFatal();
|
||||
} else if (mem.eql(u8, arg, "--entry")) {
|
||||
entry = args_iter.nextOrFatal();
|
||||
} else if (mem.startsWith(u8, arg, "-fentry=")) {
|
||||
entry = arg["-fentry=".len..];
|
||||
} else if (mem.eql(u8, arg, "--force_undefined")) {
|
||||
try force_undefined_symbols.put(gpa, args_iter.nextOrFatal(), {});
|
||||
} else if (mem.eql(u8, arg, "--stack")) {
|
||||
@ -1513,6 +1516,10 @@ fn buildOutputType(
|
||||
}
|
||||
} else if (mem.eql(u8, arg, "--import-memory")) {
|
||||
linker_import_memory = true;
|
||||
} else if (mem.eql(u8, arg, "-fentry")) {
|
||||
linker_force_entry = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-entry")) {
|
||||
linker_force_entry = false;
|
||||
} else if (mem.eql(u8, arg, "--export-memory")) {
|
||||
linker_export_memory = true;
|
||||
} else if (mem.eql(u8, arg, "--import-symbols")) {
|
||||
@ -2144,6 +2151,8 @@ fn buildOutputType(
|
||||
linker_import_table = true;
|
||||
} else if (mem.eql(u8, arg, "--export-table")) {
|
||||
linker_export_table = true;
|
||||
} else if (mem.eql(u8, arg, "--no-entry")) {
|
||||
linker_force_entry = false;
|
||||
} else if (mem.eql(u8, arg, "--initial-memory")) {
|
||||
const next_arg = linker_args_it.nextOrFatal();
|
||||
linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
|
||||
@ -2606,6 +2615,23 @@ fn buildOutputType(
|
||||
link_libcpp = true;
|
||||
}
|
||||
|
||||
if (linker_force_entry) |force| {
|
||||
if (!force) {
|
||||
entry = null;
|
||||
} else if (entry == null and output_mode == .Exe) {
|
||||
entry = switch (target_info.target.ofmt) {
|
||||
.coff => "wWinMainCRTStartup",
|
||||
.macho => "_main",
|
||||
.elf, .plan9 => "_start",
|
||||
.wasm => defaultWasmEntryName(wasi_exec_model),
|
||||
else => |tag| fatal("No default entry point available for output format {s}", .{@tagName(tag)}),
|
||||
};
|
||||
}
|
||||
} else if (entry == null and target_info.target.isWasm() and output_mode == .Exe) {
|
||||
// For WebAssembly the compiler defaults to setting the entry name when no flags are set.
|
||||
entry = defaultWasmEntryName(wasi_exec_model);
|
||||
}
|
||||
|
||||
if (target_info.target.ofmt == .coff) {
|
||||
// Now that we know the target supports resources,
|
||||
// we can add the res files as link objects.
|
||||
@ -2628,6 +2654,23 @@ fn buildOutputType(
|
||||
if (single_threaded == null) {
|
||||
single_threaded = true;
|
||||
}
|
||||
if (link_mode) |mode| {
|
||||
if (mode == .Dynamic) {
|
||||
if (linker_export_memory != null and linker_export_memory.?) {
|
||||
fatal("flags '-dynamic' and '--export-memory' are incompatible", .{});
|
||||
}
|
||||
// User did not supply `--export-memory` which is incompatible with -dynamic, therefore
|
||||
// set the flag to false to ensure it does not get enabled by default.
|
||||
linker_export_memory = false;
|
||||
}
|
||||
}
|
||||
if (wasi_exec_model != null and wasi_exec_model.? == .reactor) {
|
||||
if (entry) |entry_name| {
|
||||
if (!mem.eql(u8, "_initialize", entry_name)) {
|
||||
fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (linker_shared_memory) {
|
||||
if (output_mode == .Obj) {
|
||||
fatal("shared memory is not allowed in object files", .{});
|
||||
@ -7225,3 +7268,11 @@ fn createDependenciesModule(
|
||||
try main_mod.deps.put(arena, "@dependencies", deps_mod);
|
||||
return deps_mod;
|
||||
}
|
||||
|
||||
fn defaultWasmEntryName(exec_model: ?std.builtin.WasiExecModel) []const u8 {
|
||||
const model = exec_model orelse .command;
|
||||
if (model == .reactor) {
|
||||
return "_initialize";
|
||||
}
|
||||
return "_start";
|
||||
}
|
||||
|
||||
@ -658,7 +658,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
|
||||
const exe = addExecutable(b, "main", opts);
|
||||
exe.addObject(a_o);
|
||||
exe.addObject(b_o);
|
||||
exe.entry_symbol_name = "foo";
|
||||
exe.entry = .{ .symbol_name = "foo" };
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
@ -674,7 +674,7 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
|
||||
const exe = addExecutable(b, "other", opts);
|
||||
exe.addObject(a_o);
|
||||
exe.addObject(b_o);
|
||||
exe.entry_symbol_name = "bar";
|
||||
exe.entry = .{ .symbol_name = "bar" };
|
||||
|
||||
const check = exe.checkObject();
|
||||
check.checkStart();
|
||||
|
||||
@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
});
|
||||
exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
|
||||
exe.linkLibC();
|
||||
exe.entry_symbol_name = "_non_main";
|
||||
exe.entry = .{ .symbol_name = "_non_main" };
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
||||
exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
|
||||
exe.linkLibrary(lib);
|
||||
exe.linkLibC();
|
||||
exe.entry_symbol_name = "_bootstrap";
|
||||
exe.entry = .{ .symbol_name = "_bootstrap" };
|
||||
exe.forceUndefinedSymbol("_my_main");
|
||||
|
||||
const check_exe = exe.checkObject();
|
||||
|
||||
@ -15,12 +15,13 @@ pub fn build(b: *std.Build) void {
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
// The code in question will pull-in compiler-rt,
|
||||
// and therefore link with its archive file.
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "main",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = optimize,
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
@ -4,7 +4,7 @@ pub const requires_stage2 = true;
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Library with explicitly set cpu features
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = .Debug,
|
||||
@ -15,6 +15,7 @@ pub fn build(b: *std.Build) void {
|
||||
.os_tag = .freestanding,
|
||||
},
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
|
||||
|
||||
@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode, is_safe: bool) void {
|
||||
{
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize_mode,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
@ -60,12 +61,13 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
|
||||
|
||||
// verify zero'd declaration is stored in bss for all optimization modes.
|
||||
{
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib2.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize_mode,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
@ -9,12 +9,13 @@ pub fn build(b: *std.Build) void {
|
||||
return;
|
||||
}
|
||||
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.optimize = .ReleaseSafe, // to make the output deterministic in address positions
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_lld = false;
|
||||
lib.export_symbol_names = &.{ "foo", "bar" };
|
||||
lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse
|
||||
|
||||
@ -13,31 +13,34 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const no_export = b.addSharedLibrary(.{
|
||||
const no_export = b.addExecutable(.{
|
||||
.name = "no-export",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = optimize,
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
});
|
||||
no_export.entry = .disabled;
|
||||
no_export.use_llvm = false;
|
||||
no_export.use_lld = false;
|
||||
|
||||
const dynamic_export = b.addSharedLibrary(.{
|
||||
const dynamic_export = b.addExecutable(.{
|
||||
.name = "dynamic",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = optimize,
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
});
|
||||
dynamic_export.entry = .disabled;
|
||||
dynamic_export.rdynamic = true;
|
||||
dynamic_export.use_llvm = false;
|
||||
dynamic_export.use_lld = false;
|
||||
|
||||
const force_export = b.addSharedLibrary(.{
|
||||
const force_export = b.addExecutable(.{
|
||||
.name = "force",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = optimize,
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
});
|
||||
force_export.entry = .disabled;
|
||||
force_export.export_symbol_names = &.{"foo"};
|
||||
force_export.use_llvm = false;
|
||||
force_export.use_lld = false;
|
||||
|
||||
@ -11,12 +11,13 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.import_symbols = true; // import `a` and `b`
|
||||
lib.rdynamic = true; // export `foo`
|
||||
|
||||
|
||||
@ -13,32 +13,35 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const import_table = b.addSharedLibrary(.{
|
||||
const import_table = b.addExecutable(.{
|
||||
.name = "import_table",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
import_table.entry = .disabled;
|
||||
import_table.use_llvm = false;
|
||||
import_table.use_lld = false;
|
||||
import_table.import_table = true;
|
||||
|
||||
const export_table = b.addSharedLibrary(.{
|
||||
const export_table = b.addExecutable(.{
|
||||
.name = "export_table",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
export_table.entry = .disabled;
|
||||
export_table.use_llvm = false;
|
||||
export_table.use_lld = false;
|
||||
export_table.export_table = true;
|
||||
|
||||
const regular_table = b.addSharedLibrary(.{
|
||||
const regular_table = b.addExecutable(.{
|
||||
.name = "regular_table",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
regular_table.entry = .disabled;
|
||||
regular_table.use_llvm = false;
|
||||
regular_table.use_lld = false;
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void {
|
||||
|
||||
// Wasm library that doesn't have any features specified. This will
|
||||
// infer its featureset from other linked object files.
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "main.zig" },
|
||||
.optimize = .Debug,
|
||||
@ -27,6 +27,7 @@ pub fn build(b: *std.Build) void {
|
||||
.os_tag = .freestanding,
|
||||
},
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.addObject(c_obj);
|
||||
|
||||
@ -14,12 +14,13 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
@ -11,88 +11,87 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void {
|
||||
{
|
||||
const lib = b.addSharedLibrary(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{
|
||||
.cpu_arch = .wasm32,
|
||||
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
|
||||
.cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }),
|
||||
.os_tag = .freestanding,
|
||||
},
|
||||
.optimize = optimize_mode,
|
||||
});
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
lib.import_memory = true;
|
||||
lib.export_memory = true;
|
||||
lib.shared_memory = true;
|
||||
lib.max_memory = 67108864;
|
||||
lib.single_threaded = false;
|
||||
lib.export_symbol_names = &.{"foo"};
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{
|
||||
.cpu_arch = .wasm32,
|
||||
.cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
|
||||
.cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }),
|
||||
.os_tag = .freestanding,
|
||||
},
|
||||
.optimize = optimize_mode,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
lib.import_memory = true;
|
||||
lib.export_memory = true;
|
||||
lib.shared_memory = true;
|
||||
lib.max_memory = 67108864;
|
||||
lib.single_threaded = false;
|
||||
lib.export_symbol_names = &.{"foo"};
|
||||
|
||||
const check_lib = lib.checkObject();
|
||||
const check_lib = lib.checkObject();
|
||||
|
||||
check_lib.checkStart("Section import");
|
||||
check_lib.checkNext("entries 1");
|
||||
check_lib.checkNext("module env");
|
||||
check_lib.checkNext("name memory"); // ensure we are importing memory
|
||||
check_lib.checkStart("Section import");
|
||||
check_lib.checkNext("entries 1");
|
||||
check_lib.checkNext("module env");
|
||||
check_lib.checkNext("name memory"); // ensure we are importing memory
|
||||
|
||||
check_lib.checkStart("Section export");
|
||||
check_lib.checkNext("entries 2");
|
||||
check_lib.checkNext("name memory"); // ensure we also export memory again
|
||||
check_lib.checkStart("Section export");
|
||||
check_lib.checkNext("entries 2");
|
||||
check_lib.checkNext("name memory"); // ensure we also export memory again
|
||||
|
||||
// This section *must* be emit as the start function is set to the index
|
||||
// of __wasm_init_memory
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
// This means we won't have __wasm_init_memory in such case, and therefore
|
||||
// should also not have a section "start"
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section start");
|
||||
}
|
||||
|
||||
// This section is only and *must* be emit when shared-memory is enabled
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section data_count");
|
||||
check_lib.checkNext("count 3");
|
||||
}
|
||||
|
||||
check_lib.checkStart("Section custom");
|
||||
check_lib.checkNext("name name");
|
||||
check_lib.checkNext("type function");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __wasm_init_memory");
|
||||
}
|
||||
check_lib.checkNext("name __wasm_init_tls");
|
||||
check_lib.checkNext("type global");
|
||||
|
||||
// In debug mode the symbol __tls_base is resolved to an undefined symbol
|
||||
// from the object file, hence its placement differs than in release modes
|
||||
// where the entire tls segment is optimized away, and tls_base will have
|
||||
// its original position.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
check_lib.checkNext("name __tls_base");
|
||||
} else {
|
||||
check_lib.checkNext("name __tls_base");
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
}
|
||||
|
||||
check_lib.checkNext("type data_segment");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("names 3");
|
||||
check_lib.checkNext("index 0");
|
||||
check_lib.checkNext("name .rodata");
|
||||
check_lib.checkNext("index 1");
|
||||
check_lib.checkNext("name .bss");
|
||||
check_lib.checkNext("index 2");
|
||||
check_lib.checkNext("name .tdata");
|
||||
}
|
||||
|
||||
test_step.dependOn(&check_lib.step);
|
||||
// This section *must* be emit as the start function is set to the index
|
||||
// of __wasm_init_memory
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
// This means we won't have __wasm_init_memory in such case, and therefore
|
||||
// should also not have a section "start"
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section start");
|
||||
}
|
||||
|
||||
// This section is only and *must* be emit when shared-memory is enabled
|
||||
// release modes will have the TLS segment optimized out in our test-case.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkStart("Section data_count");
|
||||
check_lib.checkNext("count 3");
|
||||
}
|
||||
|
||||
check_lib.checkStart("Section custom");
|
||||
check_lib.checkNext("name name");
|
||||
check_lib.checkNext("type function");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __wasm_init_memory");
|
||||
}
|
||||
check_lib.checkNext("name __wasm_init_tls");
|
||||
check_lib.checkNext("type global");
|
||||
|
||||
// In debug mode the symbol __tls_base is resolved to an undefined symbol
|
||||
// from the object file, hence its placement differs than in release modes
|
||||
// where the entire tls segment is optimized away, and tls_base will have
|
||||
// its original position.
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
check_lib.checkNext("name __tls_base");
|
||||
} else {
|
||||
check_lib.checkNext("name __tls_base");
|
||||
check_lib.checkNext("name __tls_size");
|
||||
check_lib.checkNext("name __tls_align");
|
||||
}
|
||||
|
||||
check_lib.checkNext("type data_segment");
|
||||
if (optimize_mode == .Debug) {
|
||||
check_lib.checkNext("names 3");
|
||||
check_lib.checkNext("index 0");
|
||||
check_lib.checkNext("name .rodata");
|
||||
check_lib.checkNext("index 1");
|
||||
check_lib.checkNext("name .bss");
|
||||
check_lib.checkNext("index 2");
|
||||
check_lib.checkNext("name .tdata");
|
||||
}
|
||||
|
||||
test_step.dependOn(&check_lib.step);
|
||||
}
|
||||
|
||||
@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
@ -13,12 +13,13 @@ pub fn build(b: *std.Build) void {
|
||||
}
|
||||
|
||||
fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
|
||||
const lib = b.addSharedLibrary(.{
|
||||
const lib = b.addExecutable(.{
|
||||
.name = "lib",
|
||||
.root_source_file = .{ .path = "lib.zig" },
|
||||
.target = .{ .cpu_arch = .wasm32, .os_tag = .freestanding },
|
||||
.optimize = optimize,
|
||||
});
|
||||
lib.entry = .disabled;
|
||||
lib.use_llvm = false;
|
||||
lib.use_lld = false;
|
||||
lib.strip = false;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user