Commit 6d951aff7e
Changed files (6)
src
src/link/Wasm.zig
@@ -1163,7 +1163,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
};
}
- if (self.base.options.output_mode == .Obj) {
+ if (is_obj) {
// LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy
// here. TODO: think carefully about how we can avoid this redundant operation when doing
// build-obj. See also the corresponding TODO in linkAsArchive.
@@ -1233,14 +1233,38 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
try argv.append(arg);
}
+ var auto_export_symbols = true;
// 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);
+ auto_export_symbols = false;
}
if (self.base.options.rdynamic) {
try argv.append("--export-dynamic");
+ auto_export_symbols = false;
+ }
+
+ if (auto_export_symbols) {
+ if (self.base.options.module) |module| {
+ // when we use stage1, we use the exports that stage1 provided us.
+ // For stage2, we can directly retrieve them from the module.
+ const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
+ if (use_stage1) {
+ for (comp.export_symbol_names.items) |symbol_name| {
+ try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}));
+ }
+ } else {
+ for (module.decl_exports.values()) |exports| {
+ for (exports) |exprt| {
+ const symbol_name = exprt.exported_decl.name;
+ const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name});
+ try argv.append(arg);
+ }
+ }
+ }
+ }
}
if (self.base.options.output_mode == .Exe) {
@@ -1258,12 +1282,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
if (self.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 (!self.base.options.rdynamic) {
- try argv.append("--export-dynamic");
- }
}
} else {
if (self.base.options.stack_size_override) |stack_size| {
@@ -1271,12 +1289,6 @@ 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.appendSlice(&[_][]const u8{
src/stage1/codegen.cpp
@@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) {
codegen_add_time_event(g, "Done");
codegen_switch_sub_prog_node(g, nullptr);
+
+ // append all export symbols to stage2 so we can provide them to the linker
+ if (target_is_wasm(g->zig_target)){
+ Error err;
+ auto export_it = g->exported_symbol_names.entry_iterator();
+ decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr;
+ while ((curr_entry = export_it.next()) != nullptr) {
+ if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key)))) {
+ fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err));
+ }
+ }
+ }
}
ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path,
src/stage1/stage2.h
@@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1,
const char *lib_name_ptr, size_t lib_name_len,
const char *symbol_name_ptr, size_t symbol_name_len);
+// ABI warning
+ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr);
+
#endif
src/stage1/zig0.cpp
@@ -554,3 +554,8 @@ const char *stage2_version_string(void) {
struct Stage2SemVer stage2_version(void) {
return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
}
+
+Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr)
+{
+ return ErrorNone;
+}
src/Compilation.zig
@@ -165,6 +165,10 @@ emit_docs: ?EmitLoc,
work_queue_wait_group: WaitGroup,
astgen_wait_group: WaitGroup,
+/// Exported symbol names. This is only for when the target is wasm.
+/// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information.
+export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{},
+
pub const SemaError = Module.SemaError;
pub const CRTFile = struct {
@@ -1877,6 +1881,11 @@ pub fn destroy(self: *Compilation) void {
self.work_queue_wait_group.deinit();
self.astgen_wait_group.deinit();
+ for (self.export_symbol_names.items) |symbol_name| {
+ self.gpa.free(symbol_name);
+ }
+ self.export_symbol_names.deinit(self.gpa);
+
// This destroys `self`.
self.arena_state.promote(gpa).deinit();
}
src/stage1.zig
@@ -467,3 +467,14 @@ export fn stage2_fetch_file(
if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1);
return contents.ptr;
}
+
+export fn stage2_append_symbol(stage1: *Module, name_ptr: ?[*:0]const u8) Error {
+ const comp = @intToPtr(*Compilation, stage1.userdata);
+
+ if (name_ptr) |unwrapped_name| {
+ const symbol_name = std.mem.sliceTo(unwrapped_name, 0);
+ if (symbol_name.len == 0) return Error.None;
+ comp.export_symbol_names.append(comp.gpa, symbol_name) catch return Error.OutOfMemory;
+ }
+ return Error.None;
+}