| author | |
| committer | |
| log | dafbc6eb2524d1e8276ceec2cf26cb1d4982e2ad |
| tree | 00e562e85f176fca441581ea1e7f7b98b46b6363 |
| parent | 6f49233ac6a6569b909b689f22fc260dc8c19234 |
7 files changed, 71 insertions(+), 14 deletions(-)
lib/std/build.zig+2| ... | @@ -2651,6 +2651,8 @@ pub const LibExeObjStep = struct { | ... | @@ -2651,6 +2651,8 @@ pub const LibExeObjStep = struct { |
| 2651 | try zig_args.append(bin_name); | 2651 | try zig_args.append(bin_name); |
| 2652 | try zig_args.append("--test-cmd"); | 2652 | try zig_args.append("--test-cmd"); |
| 2653 | try zig_args.append("--dir=."); | 2653 | try zig_args.append("--dir=."); |
| 2654 | try zig_args.append("--test-cmd"); | ||
| 2655 | try zig_args.append("--allow-unknown-exports"); // TODO: Remove when stage2 is default compiler | ||
| 2654 | try zig_args.append("--test-cmd-bin"); | 2656 | try zig_args.append("--test-cmd-bin"); |
| 2655 | } else { | 2657 | } else { |
| 2656 | try zig_args.append("--test-no-exec"); | 2658 | try zig_args.append("--test-no-exec"); |
src/Compilation.zig+9| ... | @@ -158,6 +158,10 @@ emit_docs: ?EmitLoc, | ... | @@ -158,6 +158,10 @@ emit_docs: ?EmitLoc, |
| 158 | work_queue_wait_group: WaitGroup, | 158 | work_queue_wait_group: WaitGroup, |
| 159 | astgen_wait_group: WaitGroup, | 159 | astgen_wait_group: WaitGroup, |
| 160 | 160 | ||
| 161 | /// Exported symbol names. This is only for when the target is wasm. | ||
| 162 | /// TODO: Remove this when Stage2 becomes the default compiler as it will already have this information. | ||
| 163 | export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{}, | ||
| 164 | |||
| 161 | pub const SemaError = Module.SemaError; | 165 | pub const SemaError = Module.SemaError; |
| 162 | 166 | ||
| 163 | pub const CRTFile = struct { | 167 | pub const CRTFile = struct { |
| ... | @@ -1791,6 +1795,11 @@ pub fn destroy(self: *Compilation) void { | ... | @@ -1791,6 +1795,11 @@ pub fn destroy(self: *Compilation) void { |
| 1791 | self.work_queue_wait_group.deinit(); | 1795 | self.work_queue_wait_group.deinit(); |
| 1792 | self.astgen_wait_group.deinit(); | 1796 | self.astgen_wait_group.deinit(); |
| 1793 | 1797 | ||
| 1798 | for (self.export_symbol_names.items) |symbol_name| { | ||
| 1799 | gpa.free(symbol_name); | ||
| 1800 | } | ||
| 1801 | self.export_symbol_names.deinit(gpa); | ||
| 1802 | |||
| 1794 | // This destroys `self`. | 1803 | // This destroys `self`. |
| 1795 | self.arena_state.promote(gpa).deinit(); | 1804 | self.arena_state.promote(gpa).deinit(); |
| 1796 | } | 1805 | } |
src/link/Wasm.zig+32-14| ... | @@ -1058,8 +1058,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1058,8 +1058,7 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1058 | } | 1058 | } |
| 1059 | 1059 | ||
| 1060 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | 1060 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); |
| 1061 | 1061 | if (is_obj) { | |
| 1062 | if (self.base.options.output_mode == .Obj) { | ||
| 1063 | // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy | 1062 | // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy |
| 1064 | // here. TODO: think carefully about how we can avoid this redundant operation when doing | 1063 | // here. TODO: think carefully about how we can avoid this redundant operation when doing |
| 1065 | // build-obj. See also the corresponding TODO in linkAsArchive. | 1064 | // build-obj. See also the corresponding TODO in linkAsArchive. |
| ... | @@ -1125,14 +1124,45 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1125,14 +1124,45 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1125 | try argv.append("--stack-first"); | 1124 | try argv.append("--stack-first"); |
| 1126 | } | 1125 | } |
| 1127 | 1126 | ||
| 1127 | var auto_export_symbols = true; | ||
| 1128 | // Users are allowed to specify which symbols they want to export to the wasm host. | 1128 | // Users are allowed to specify which symbols they want to export to the wasm host. |
| 1129 | for (self.base.options.export_symbol_names) |symbol_name| { | 1129 | for (self.base.options.export_symbol_names) |symbol_name| { |
| 1130 | const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); | 1130 | const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); |
| 1131 | try argv.append(arg); | 1131 | try argv.append(arg); |
| 1132 | auto_export_symbols = false; | ||
| 1132 | } | 1133 | } |
| 1133 | 1134 | ||
| 1134 | if (self.base.options.rdynamic) { | 1135 | if (self.base.options.rdynamic) { |
| 1135 | try argv.append("--export-dynamic"); | 1136 | try argv.append("--export-dynamic"); |
| 1137 | auto_export_symbols = false; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | if (auto_export_symbols) { | ||
| 1141 | if (self.base.options.module) |module| { | ||
| 1142 | // when we use stage1, we use the exports that stage1 provided us. | ||
| 1143 | // For stage2, we can directly retrieve them from the module. | ||
| 1144 | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; | ||
| 1145 | if (use_stage1) { | ||
| 1146 | for (comp.export_symbol_names.items) |symbol_name| { | ||
| 1147 | try argv.append(try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name})); | ||
| 1148 | } | ||
| 1149 | } else { | ||
| 1150 | const skip_export_non_fn = target.os.tag == .wasi and | ||
| 1151 | self.base.options.wasi_exec_model == .command; | ||
| 1152 | for (module.decl_exports.values()) |exports| { | ||
| 1153 | for (exports) |exprt| { | ||
| 1154 | if (skip_export_non_fn and exprt.exported_decl.ty.zigTypeTag() != .Fn) { | ||
| 1155 | // skip exporting symbols when we're building a WASI command | ||
| 1156 | // and the symbol is not a function | ||
| 1157 | continue; | ||
| 1158 | } | ||
| 1159 | const symbol_name = exprt.exported_decl.name; | ||
| 1160 | const arg = try std.fmt.allocPrint(arena, "--export={s}", .{symbol_name}); | ||
| 1161 | try argv.append(arg); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1136 | } | 1166 | } |
| 1137 | 1167 | ||
| 1138 | if (self.base.options.output_mode == .Exe) { | 1168 | if (self.base.options.output_mode == .Exe) { |
| ... | @@ -1146,12 +1176,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1146,12 +1176,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1146 | if (self.base.options.wasi_exec_model == .reactor) { | 1176 | if (self.base.options.wasi_exec_model == .reactor) { |
| 1147 | // Reactor execution model does not have _start so lld doesn't look for it. | 1177 | // Reactor execution model does not have _start so lld doesn't look for it. |
| 1148 | try argv.append("--no-entry"); | 1178 | try argv.append("--no-entry"); |
| 1149 | // Make sure "_initialize" and other used-defined functions are exported if this is WASI reactor. | ||
| 1150 | // If rdynamic is true, it will already be appended, so only verify if the user did not specify | ||
| 1151 | // the flag in which case, we ensure `--export-dynamic` is called. | ||
| 1152 | if (!self.base.options.rdynamic) { | ||
| 1153 | try argv.append("--export-dynamic"); | ||
| 1154 | } | ||
| 1155 | } | 1179 | } |
| 1156 | } else { | 1180 | } else { |
| 1157 | if (self.base.options.stack_size_override) |stack_size| { | 1181 | if (self.base.options.stack_size_override) |stack_size| { |
| ... | @@ -1159,12 +1183,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1159,12 +1183,6 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1159 | const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); | 1183 | const arg = try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}); |
| 1160 | try argv.append(arg); | 1184 | try argv.append(arg); |
| 1161 | } | 1185 | } |
| 1162 | |||
| 1163 | // Only when the user has not specified how they want to export the symbols, do we want | ||
| 1164 | // to export all symbols. | ||
| 1165 | if (self.base.options.export_symbol_names.len == 0 and !self.base.options.rdynamic) { | ||
| 1166 | try argv.append("--export-all"); | ||
| 1167 | } | ||
| 1168 | try argv.append("--no-entry"); // So lld doesn't look for _start. | 1186 | try argv.append("--no-entry"); // So lld doesn't look for _start. |
| 1169 | } | 1187 | } |
| 1170 | try argv.appendSlice(&[_][]const u8{ | 1188 | try argv.appendSlice(&[_][]const u8{ |
src/stage1.zig+8| ... | @@ -464,3 +464,11 @@ export fn stage2_fetch_file( | ... | @@ -464,3 +464,11 @@ export fn stage2_fetch_file( |
| 464 | if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1); | 464 | if (contents.len == 0) return @intToPtr(?[*]const u8, 0x1); |
| 465 | return contents.ptr; | 465 | return contents.ptr; |
| 466 | } | 466 | } |
| 467 | |||
| 468 | export fn stage2_append_symbol(stage1: *Module, name_ptr: [*c]const u8, name_len: usize) Error { | ||
| 469 | if (name_len == 0) return Error.None; | ||
| 470 | const comp = @intToPtr(*Compilation, stage1.userdata); | ||
| 471 | const sym_name = comp.gpa.dupe(u8, name_ptr[0..name_len]) catch return Error.OutOfMemory; | ||
| 472 | comp.export_symbol_names.append(comp.gpa, sym_name) catch return Error.OutOfMemory; | ||
| 473 | return Error.None; | ||
| 474 | } |
src/stage1/codegen.cpp+12| ... | @@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) { | ... | @@ -9905,6 +9905,18 @@ void codegen_build_object(CodeGen *g) { |
| 9905 | 9905 | ||
| 9906 | codegen_add_time_event(g, "Done"); | 9906 | codegen_add_time_event(g, "Done"); |
| 9907 | codegen_switch_sub_prog_node(g, nullptr); | 9907 | codegen_switch_sub_prog_node(g, nullptr); |
| 9908 | |||
| 9909 | // append all export symbols to stage2 so we can provide them to the linker | ||
| 9910 | if (target_is_wasm(g->zig_target)){ | ||
| 9911 | Error err; | ||
| 9912 | auto export_it = g->exported_symbol_names.entry_iterator(); | ||
| 9913 | decltype(g->exported_symbol_names)::Entry *curr_entry = nullptr; | ||
| 9914 | while ((curr_entry = export_it.next()) != nullptr) { | ||
| 9915 | if ((err = stage2_append_symbol(&g->stage1, buf_ptr(curr_entry->key), buf_len(curr_entry->key)))) { | ||
| 9916 | fprintf(stderr, "Unable to export symbol '%s': %s\n", buf_ptr(curr_entry->key), err_str(err)); | ||
| 9917 | } | ||
| 9918 | } | ||
| 9919 | } | ||
| 9908 | } | 9920 | } |
| 9909 | 9921 | ||
| 9910 | ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, | 9922 | ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, |
src/stage1/stage2.h+3| ... | @@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1, | ... | @@ -182,4 +182,7 @@ ZIG_EXTERN_C const char *stage2_add_link_lib(struct ZigStage1 *stage1, |
| 182 | const char *lib_name_ptr, size_t lib_name_len, | 182 | const char *lib_name_ptr, size_t lib_name_len, |
| 183 | const char *symbol_name_ptr, size_t symbol_name_len); | 183 | const char *symbol_name_ptr, size_t symbol_name_len); |
| 184 | 184 | ||
| 185 | // ABI warning | ||
| 186 | ZIG_EXTERN_C enum Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len); | ||
| 187 | |||
| 185 | #endif | 188 | #endif |
src/stage1/zig0.cpp+5| ... | @@ -554,3 +554,8 @@ const char *stage2_version_string(void) { | ... | @@ -554,3 +554,8 @@ const char *stage2_version_string(void) { |
| 554 | struct Stage2SemVer stage2_version(void) { | 554 | struct Stage2SemVer stage2_version(void) { |
| 555 | return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH}; | 555 | return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH}; |
| 556 | } | 556 | } |
| 557 | |||
| 558 | Error stage2_append_symbol(struct ZigStage1 *stage1, const char *name_ptr, size_t name_len) | ||
| 559 | { | ||
| 560 | return ErrorNone; | ||
| 561 | } |