Commit 50201e1c30
Changed files (5)
lib
std
lib/std/build.zig
@@ -1491,6 +1491,8 @@ pub const LibExeObjStep = struct {
test_evented_io: bool = false,
code_model: std.builtin.CodeModel = .default,
wasi_exec_model: ?std.builtin.WasiExecModel = null,
+ /// Symbols to be exported when compiling to wasm
+ export_symbol_names: []const []const u8 = &.{},
root_src: ?FileSource,
out_h_filename: []const u8,
@@ -2511,6 +2513,9 @@ pub const LibExeObjStep = struct {
if (self.wasi_exec_model) |model| {
try zig_args.append(builder.fmt("-mexec-model={s}", .{@tagName(model)}));
}
+ for (self.export_symbol_names) |symbol_name| {
+ try zig_args.append(builder.fmt("--export={s}", .{symbol_name}));
+ }
if (!self.target.isNative()) {
try zig_args.append("-target");
src/link/Wasm.zig
@@ -1011,6 +1011,10 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
man.hash.addOptional(self.base.options.initial_memory);
man.hash.addOptional(self.base.options.max_memory);
man.hash.addOptional(self.base.options.global_base);
+ man.hash.add(self.base.options.export_symbol_names.len);
+ for (self.base.options.export_symbol_names) |symbol_name| {
+ man.hash.addBytes(symbol_name);
+ }
// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try man.hit();
@@ -1103,6 +1107,16 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
try argv.append(arg);
}
+ // Users are allowed to specify which symbols they want to export to the wasm host.
+ for (self.base.options.export_symbol_names) |symbol_name| {
+ const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
+ try argv.append(arg);
+ }
+
+ if (self.base.options.rdynamic) {
+ try argv.append("--export-dynamic");
+ }
+
if (self.base.options.output_mode == .Exe) {
// Increase the default stack size to a more reasonable value of 1MB instead of
// the default of 1 Wasm page being 64KB, unless overridden by the user.
@@ -1119,7 +1133,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
// 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.
- try argv.append("--export-dynamic");
+ // 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 (!self.base.options.rdynamic) {
+ try argv.append("--export-dynamic");
+ }
}
} else {
if (self.base.options.stack_size_override) |stack_size| {
@@ -1127,8 +1145,13 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size});
try argv.append(arg);
}
+
+ // Only when the user has not specified how they want to export the symbols, do we want
+ // to export all symbols.
+ if (self.base.options.export_symbol_names.len == 0 and !self.base.options.rdynamic) {
+ try argv.append("--export-all");
+ }
try argv.append("--no-entry"); // So lld doesn't look for _start.
- try argv.append("--export-all");
}
try argv.appendSlice(&[_][]const u8{
"--allow-undefined",
src/Compilation.zig
@@ -727,6 +727,7 @@ pub const InitOptions = struct {
linker_initial_memory: ?u64 = null,
linker_max_memory: ?u64 = null,
linker_global_base: ?u64 = null,
+ linker_export_symbol_names: []const []const u8 = &.{},
each_lib_rpath: ?bool = null,
disable_c_depfile: bool = false,
linker_z_nodelete: bool = false,
@@ -1457,6 +1458,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
.initial_memory = options.linker_initial_memory,
.max_memory = options.linker_max_memory,
.global_base = options.linker_global_base,
+ .export_symbol_names = options.linker_export_symbol_names,
.z_nodelete = options.linker_z_nodelete,
.z_notext = options.linker_z_notext,
.z_defs = options.linker_z_defs,
src/link.zig
@@ -104,6 +104,7 @@ pub const Options = struct {
import_memory: bool,
initial_memory: ?u64,
max_memory: ?u64,
+ export_symbol_names: []const []const u8,
global_base: ?u64,
is_native_os: bool,
is_native_abi: bool,
src/main.zig
@@ -434,6 +434,7 @@ const usage_build_generic =
\\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
\\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
\\ --global-base=[addr] (WebAssembly) where to start to place global data
+ \\ --export=[value] (WebAssembly) Force a symbol to be exported
\\
\\Test Options:
\\ --test-filter [text] Skip tests that do not match filter
@@ -711,6 +712,9 @@ fn buildOutputType(
var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
defer test_exec_args.deinit();
+ var linker_export_symbol_names = std.ArrayList([]const u8).init(gpa);
+ defer linker_export_symbol_names.deinit();
+
// This package only exists to clean up the code parsing --pkg-begin and
// --pkg-end flags. Use dummy values that are safe for the destroy call.
var pkg_tree_root: Package = .{
@@ -1175,6 +1179,8 @@ fn buildOutputType(
linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
} else if (mem.startsWith(u8, arg, "--global-base=")) {
linker_global_base = parseIntSuffix(arg, "--global-base=".len);
+ } else if (mem.startsWith(u8, arg, "--export=")) {
+ try linker_export_symbol_names.append(arg["--export=".len..]);
} else if (mem.eql(u8, arg, "-Bsymbolic")) {
linker_bind_global_refs_locally = true;
} else if (mem.eql(u8, arg, "--debug-compile-errors")) {
@@ -1554,6 +1560,8 @@ fn buildOutputType(
linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
} else if (mem.startsWith(u8, arg, "--global-base=")) {
linker_global_base = parseIntSuffix(arg, "--global-base=".len);
+ } else if (mem.startsWith(u8, arg, "--export=")) {
+ try linker_export_symbol_names.append(arg["--export=".len..]);
} else if (mem.eql(u8, arg, "-z")) {
i += 1;
if (i >= linker_args.items.len) {
@@ -2438,6 +2446,7 @@ fn buildOutputType(
.linker_initial_memory = linker_initial_memory,
.linker_max_memory = linker_max_memory,
.linker_global_base = linker_global_base,
+ .linker_export_symbol_names = linker_export_symbol_names.items,
.linker_z_nodelete = linker_z_nodelete,
.linker_z_notext = linker_z_notext,
.linker_z_defs = linker_z_defs,