| author | |
| committer | |
| log | 5c228765f1094d30e64d13c0077c67b2867ecd6a |
| tree | 3987430030804d36895f680f5a5573db6b7e66cb |
| parent | 3c87d4e14ec6b0c2442372cbcc60174d654edddc |
| parent | b6d6152e6514dcb4e67750cbb22b90b38ebedf49 |
| signature |
linker: fix build-obj and -fno-emit-bin7 files changed, 138 insertions(+), 73 deletions(-)
src/codegen/llvm.zig+14-18| ... | @@ -181,8 +181,6 @@ pub const Object = struct { | ... | @@ -181,8 +181,6 @@ pub const Object = struct { |
| 181 | /// The backing memory for `type_map`. Periodically garbage collected after flush(). | 181 | /// The backing memory for `type_map`. Periodically garbage collected after flush(). |
| 182 | /// The code for doing the periodical GC is not yet implemented. | 182 | /// The code for doing the periodical GC is not yet implemented. |
| 183 | type_map_arena: std.heap.ArenaAllocator, | 183 | type_map_arena: std.heap.ArenaAllocator, |
| 184 | /// Where to put the output object file, relative to bin_file.options.emit directory. | ||
| 185 | sub_path: []const u8, | ||
| 186 | 184 | ||
| 187 | pub const TypeMap = std.HashMapUnmanaged( | 185 | pub const TypeMap = std.HashMapUnmanaged( |
| 188 | Type, | 186 | Type, |
| ... | @@ -191,14 +189,14 @@ pub const Object = struct { | ... | @@ -191,14 +189,14 @@ pub const Object = struct { |
| 191 | std.hash_map.default_max_load_percentage, | 189 | std.hash_map.default_max_load_percentage, |
| 192 | ); | 190 | ); |
| 193 | 191 | ||
| 194 | pub fn create(gpa: Allocator, sub_path: []const u8, options: link.Options) !*Object { | 192 | pub fn create(gpa: Allocator, options: link.Options) !*Object { |
| 195 | const obj = try gpa.create(Object); | 193 | const obj = try gpa.create(Object); |
| 196 | errdefer gpa.destroy(obj); | 194 | errdefer gpa.destroy(obj); |
| 197 | obj.* = try Object.init(gpa, sub_path, options); | 195 | obj.* = try Object.init(gpa, options); |
| 198 | return obj; | 196 | return obj; |
| 199 | } | 197 | } |
| 200 | 198 | ||
| 201 | pub fn init(gpa: Allocator, sub_path: []const u8, options: link.Options) !Object { | 199 | pub fn init(gpa: Allocator, options: link.Options) !Object { |
| 202 | const context = llvm.Context.create(); | 200 | const context = llvm.Context.create(); |
| 203 | errdefer context.dispose(); | 201 | errdefer context.dispose(); |
| 204 | 202 | ||
| ... | @@ -271,7 +269,6 @@ pub const Object = struct { | ... | @@ -271,7 +269,6 @@ pub const Object = struct { |
| 271 | .decl_map = .{}, | 269 | .decl_map = .{}, |
| 272 | .type_map = .{}, | 270 | .type_map = .{}, |
| 273 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | 271 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), |
| 274 | .sub_path = sub_path, | ||
| 275 | }; | 272 | }; |
| 276 | } | 273 | } |
| 277 | 274 | ||
| ... | @@ -324,19 +321,22 @@ pub const Object = struct { | ... | @@ -324,19 +321,22 @@ pub const Object = struct { |
| 324 | const mod = comp.bin_file.options.module.?; | 321 | const mod = comp.bin_file.options.module.?; |
| 325 | const cache_dir = mod.zig_cache_artifact_directory; | 322 | const cache_dir = mod.zig_cache_artifact_directory; |
| 326 | 323 | ||
| 327 | const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| blk: { | 324 | const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| |
| 328 | const full_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path}); | 325 | try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?)) |
| 329 | break :blk try std.fs.path.joinZ(arena, &.{ | 326 | else |
| 330 | std.fs.path.dirname(full_out_path).?, self.sub_path, | 327 | null; |
| 331 | }); | ||
| 332 | } else null; | ||
| 333 | 328 | ||
| 334 | const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir); | 329 | const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir); |
| 335 | const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir); | 330 | const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir); |
| 336 | const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir); | 331 | const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir); |
| 337 | 332 | ||
| 338 | const debug_emit_path = emit_bin_path orelse "(none)"; | 333 | const emit_asm_msg = emit_asm_path orelse "(none)"; |
| 339 | log.debug("emit LLVM object to {s}", .{debug_emit_path}); | 334 | const emit_bin_msg = emit_bin_path orelse "(none)"; |
| 335 | const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)"; | ||
| 336 | const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)"; | ||
| 337 | log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{ | ||
| 338 | emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg, | ||
| 339 | }); | ||
| 340 | 340 | ||
| 341 | var error_message: [*:0]const u8 = undefined; | 341 | var error_message: [*:0]const u8 = undefined; |
| 342 | if (self.target_machine.emitToFile( | 342 | if (self.target_machine.emitToFile( |
| ... | @@ -354,10 +354,6 @@ pub const Object = struct { | ... | @@ -354,10 +354,6 @@ pub const Object = struct { |
| 354 | )) { | 354 | )) { |
| 355 | defer llvm.disposeMessage(error_message); | 355 | defer llvm.disposeMessage(error_message); |
| 356 | 356 | ||
| 357 | const emit_asm_msg = emit_asm_path orelse "(none)"; | ||
| 358 | const emit_bin_msg = emit_bin_path orelse "(none)"; | ||
| 359 | const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)"; | ||
| 360 | const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)"; | ||
| 361 | log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{ | 357 | log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{ |
| 362 | emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg, | 358 | emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg, |
| 363 | error_message, | 359 | error_message, |
src/glibc.zig+2-2| ... | @@ -225,7 +225,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { | ... | @@ -225,7 +225,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { |
| 225 | }); | 225 | }); |
| 226 | }, | 226 | }, |
| 227 | .scrt1_o => { | 227 | .scrt1_o => { |
| 228 | const start_os: Compilation.CSourceFile = blk: { | 228 | const start_o: Compilation.CSourceFile = blk: { |
| 229 | var args = std.ArrayList([]const u8).init(arena); | 229 | var args = std.ArrayList([]const u8).init(arena); |
| 230 | try add_include_dirs(comp, arena, &args); | 230 | try add_include_dirs(comp, arena, &args); |
| 231 | try args.appendSlice(&[_][]const u8{ | 231 | try args.appendSlice(&[_][]const u8{ |
| ... | @@ -266,7 +266,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { | ... | @@ -266,7 +266,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { |
| 266 | .extra_flags = args.items, | 266 | .extra_flags = args.items, |
| 267 | }; | 267 | }; |
| 268 | }; | 268 | }; |
| 269 | return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_os, abi_note_o }); | 269 | return comp.build_crt_file("Scrt1", .Obj, &[_]Compilation.CSourceFile{ start_o, abi_note_o }); |
| 270 | }, | 270 | }, |
| 271 | .libc_nonshared_a => { | 271 | .libc_nonshared_a => { |
| 272 | const target = comp.getTarget(); | 272 | const target = comp.getTarget(); |
src/link.zig+16-2| ... | @@ -43,6 +43,21 @@ pub const Emit = struct { | ... | @@ -43,6 +43,21 @@ pub const Emit = struct { |
| 43 | directory: Compilation.Directory, | 43 | directory: Compilation.Directory, |
| 44 | /// Path to the output file, relative to `directory`. | 44 | /// Path to the output file, relative to `directory`. |
| 45 | sub_path: []const u8, | 45 | sub_path: []const u8, |
| 46 | |||
| 47 | /// Returns the full path to `basename` if it were in the same directory as the | ||
| 48 | /// `Emit` sub_path. | ||
| 49 | pub fn basenamePath(emit: Emit, arena: Allocator, basename: [:0]const u8) ![:0]const u8 { | ||
| 50 | const full_path = if (emit.directory.path) |p| | ||
| 51 | try fs.path.join(arena, &[_][]const u8{ p, emit.sub_path }) | ||
| 52 | else | ||
| 53 | emit.sub_path; | ||
| 54 | |||
| 55 | if (fs.path.dirname(full_path)) |dirname| { | ||
| 56 | return try fs.path.joinZ(arena, &.{ dirname, basename }); | ||
| 57 | } else { | ||
| 58 | return basename; | ||
| 59 | } | ||
| 60 | } | ||
| 46 | }; | 61 | }; |
| 47 | 62 | ||
| 48 | pub const Options = struct { | 63 | pub const Options = struct { |
| ... | @@ -533,9 +548,8 @@ pub const File = struct { | ... | @@ -533,9 +548,8 @@ pub const File = struct { |
| 533 | /// Commit pending changes and write headers. Takes into account final output mode | 548 | /// Commit pending changes and write headers. Takes into account final output mode |
| 534 | /// and `use_lld`, not only `effectiveOutputMode`. | 549 | /// and `use_lld`, not only `effectiveOutputMode`. |
| 535 | pub fn flush(base: *File, comp: *Compilation) !void { | 550 | pub fn flush(base: *File, comp: *Compilation) !void { |
| 536 | const emit = base.options.emit orelse return; // -fno-emit-bin | ||
| 537 | |||
| 538 | if (comp.clang_preprocessor_mode == .yes) { | 551 | if (comp.clang_preprocessor_mode == .yes) { |
| 552 | const emit = base.options.emit orelse return; // -fno-emit-bin | ||
| 539 | // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) | 553 | // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) |
| 540 | // Until then, we do `lld -r -o output.o input.o` even though the output is the same | 554 | // Until then, we do `lld -r -o output.o input.o` even though the output is the same |
| 541 | // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file | 555 | // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file |
src/link/Coff.zig+21-8| ... | @@ -129,11 +129,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -129,11 +129,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 129 | assert(options.object_format == .coff); | 129 | assert(options.object_format == .coff); |
| 130 | 130 | ||
| 131 | if (build_options.have_llvm and options.use_llvm) { | 131 | if (build_options.have_llvm and options.use_llvm) { |
| 132 | const self = try createEmpty(allocator, options); | 132 | return createEmpty(allocator, options); |
| 133 | errdefer self.base.destroy(); | ||
| 134 | |||
| 135 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); | ||
| 136 | return self; | ||
| 137 | } | 133 | } |
| 138 | 134 | ||
| 139 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | 135 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ |
| ... | @@ -403,6 +399,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { | ... | @@ -403,6 +399,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { |
| 403 | else => return error.UnsupportedCOFFArchitecture, | 399 | else => return error.UnsupportedCOFFArchitecture, |
| 404 | }; | 400 | }; |
| 405 | const self = try gpa.create(Coff); | 401 | const self = try gpa.create(Coff); |
| 402 | errdefer gpa.destroy(self); | ||
| 406 | self.* = .{ | 403 | self.* = .{ |
| 407 | .base = .{ | 404 | .base = .{ |
| 408 | .tag = .coff, | 405 | .tag = .coff, |
| ... | @@ -412,6 +409,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { | ... | @@ -412,6 +409,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff { |
| 412 | }, | 409 | }, |
| 413 | .ptr_width = ptr_width, | 410 | .ptr_width = ptr_width, |
| 414 | }; | 411 | }; |
| 412 | |||
| 413 | const use_llvm = build_options.have_llvm and options.use_llvm; | ||
| 414 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | ||
| 415 | if (use_llvm and !use_stage1) { | ||
| 416 | self.llvm_object = try LlvmObject.create(gpa, options); | ||
| 417 | } | ||
| 415 | return self; | 418 | return self; |
| 416 | } | 419 | } |
| 417 | 420 | ||
| ... | @@ -817,6 +820,14 @@ pub fn updateDeclExports( | ... | @@ -817,6 +820,14 @@ pub fn updateDeclExports( |
| 817 | } | 820 | } |
| 818 | 821 | ||
| 819 | pub fn flush(self: *Coff, comp: *Compilation) !void { | 822 | pub fn flush(self: *Coff, comp: *Compilation) !void { |
| 823 | if (self.base.options.emit == null) { | ||
| 824 | if (build_options.have_llvm) { | ||
| 825 | if (self.llvm_object) |llvm_object| { | ||
| 826 | return try llvm_object.flushModule(comp); | ||
| 827 | } | ||
| 828 | } | ||
| 829 | return; | ||
| 830 | } | ||
| 820 | if (build_options.have_llvm and self.base.options.use_lld) { | 831 | if (build_options.have_llvm and self.base.options.use_lld) { |
| 821 | return self.linkWithLLD(comp); | 832 | return self.linkWithLLD(comp); |
| 822 | } else { | 833 | } else { |
| ... | @@ -905,9 +916,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { | ... | @@ -905,9 +916,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 905 | 916 | ||
| 906 | try self.flushModule(comp); | 917 | try self.flushModule(comp); |
| 907 | 918 | ||
| 908 | break :blk try fs.path.join(arena, &.{ | 919 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 909 | fs.path.dirname(full_out_path).?, self.base.intermediary_basename.?, | 920 | break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); |
| 910 | }); | 921 | } else { |
| 922 | break :blk self.base.intermediary_basename.?; | ||
| 923 | } | ||
| 911 | } else null; | 924 | } else null; |
| 912 | 925 | ||
| 913 | const is_lib = self.base.options.output_mode == .Lib; | 926 | const is_lib = self.base.options.output_mode == .Lib; |
src/link/Elf.zig+38-25| ... | @@ -241,11 +241,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -241,11 +241,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 241 | assert(options.object_format == .elf); | 241 | assert(options.object_format == .elf); |
| 242 | 242 | ||
| 243 | if (build_options.have_llvm and options.use_llvm) { | 243 | if (build_options.have_llvm and options.use_llvm) { |
| 244 | const self = try createEmpty(allocator, options); | 244 | return createEmpty(allocator, options); |
| 245 | errdefer self.base.destroy(); | ||
| 246 | |||
| 247 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); | ||
| 248 | return self; | ||
| 249 | } | 245 | } |
| 250 | 246 | ||
| 251 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | 247 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ |
| ... | @@ -298,6 +294,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { | ... | @@ -298,6 +294,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { |
| 298 | }; | 294 | }; |
| 299 | const self = try gpa.create(Elf); | 295 | const self = try gpa.create(Elf); |
| 300 | errdefer gpa.destroy(self); | 296 | errdefer gpa.destroy(self); |
| 297 | |||
| 301 | self.* = .{ | 298 | self.* = .{ |
| 302 | .base = .{ | 299 | .base = .{ |
| 303 | .tag = .elf, | 300 | .tag = .elf, |
| ... | @@ -307,9 +304,11 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { | ... | @@ -307,9 +304,11 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { |
| 307 | }, | 304 | }, |
| 308 | .ptr_width = ptr_width, | 305 | .ptr_width = ptr_width, |
| 309 | }; | 306 | }; |
| 310 | // TODO get rid of the sub_path parameter to LlvmObject.create | 307 | const use_llvm = build_options.have_llvm and options.use_llvm; |
| 311 | // and create the llvm_object here. Also openPath needs to | 308 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| 312 | // not override this field or there will be a memory leak. | 309 | if (use_llvm and !use_stage1) { |
| 310 | self.llvm_object = try LlvmObject.create(gpa, options); | ||
| 311 | } | ||
| 313 | return self; | 312 | return self; |
| 314 | } | 313 | } |
| 315 | 314 | ||
| ... | @@ -788,14 +787,21 @@ pub const abbrev_pad1 = 5; | ... | @@ -788,14 +787,21 @@ pub const abbrev_pad1 = 5; |
| 788 | pub const abbrev_parameter = 6; | 787 | pub const abbrev_parameter = 6; |
| 789 | 788 | ||
| 790 | pub fn flush(self: *Elf, comp: *Compilation) !void { | 789 | pub fn flush(self: *Elf, comp: *Compilation) !void { |
| 791 | if (build_options.have_llvm and self.base.options.use_lld) { | 790 | if (self.base.options.emit == null) { |
| 792 | return self.linkWithLLD(comp); | 791 | if (build_options.have_llvm) { |
| 793 | } else { | 792 | if (self.llvm_object) |llvm_object| { |
| 794 | switch (self.base.options.effectiveOutputMode()) { | 793 | return try llvm_object.flushModule(comp); |
| 795 | .Exe, .Obj => {}, | 794 | } |
| 796 | .Lib => return error.TODOImplementWritingLibFiles, | ||
| 797 | } | 795 | } |
| 798 | return self.flushModule(comp); | 796 | return; |
| 797 | } | ||
| 798 | const use_lld = build_options.have_llvm and self.base.options.use_lld; | ||
| 799 | if (use_lld) { | ||
| 800 | return self.linkWithLLD(comp); | ||
| 801 | } | ||
| 802 | switch (self.base.options.output_mode) { | ||
| 803 | .Exe, .Obj => return self.flushModule(comp), | ||
| 804 | .Lib => return error.TODOImplementWritingLibFiles, | ||
| 799 | } | 805 | } |
| 800 | } | 806 | } |
| 801 | 807 | ||
| ... | @@ -803,8 +809,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { | ... | @@ -803,8 +809,11 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { |
| 803 | const tracy = trace(@src()); | 809 | const tracy = trace(@src()); |
| 804 | defer tracy.end(); | 810 | defer tracy.end(); |
| 805 | 811 | ||
| 806 | if (build_options.have_llvm) | 812 | if (build_options.have_llvm) { |
| 807 | if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp); | 813 | if (self.llvm_object) |llvm_object| { |
| 814 | return try llvm_object.flushModule(comp); | ||
| 815 | } | ||
| 816 | } | ||
| 808 | 817 | ||
| 809 | // TODO This linker code currently assumes there is only 1 compilation unit and it | 818 | // TODO This linker code currently assumes there is only 1 compilation unit and it |
| 810 | // corresponds to the Zig source code. | 819 | // corresponds to the Zig source code. |
| ... | @@ -1327,9 +1336,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1327,9 +1336,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1327 | 1336 | ||
| 1328 | try self.flushModule(comp); | 1337 | try self.flushModule(comp); |
| 1329 | 1338 | ||
| 1330 | break :blk try fs.path.join(arena, &.{ | 1339 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 1331 | fs.path.dirname(full_out_path).?, self.base.intermediary_basename.?, | 1340 | break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); |
| 1332 | }); | 1341 | } else { |
| 1342 | break :blk self.base.intermediary_basename.?; | ||
| 1343 | } | ||
| 1333 | } else null; | 1344 | } else null; |
| 1334 | 1345 | ||
| 1335 | const is_obj = self.base.options.output_mode == .Obj; | 1346 | const is_obj = self.base.options.output_mode == .Obj; |
| ... | @@ -1446,10 +1457,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1446,10 +1457,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1446 | }; | 1457 | }; |
| 1447 | } | 1458 | } |
| 1448 | 1459 | ||
| 1449 | // Due to a deficiency in LLD, we need to special-case BPF to a simple file copy when generating | 1460 | // Due to a deficiency in LLD, we need to special-case BPF to a simple file |
| 1450 | // relocatables. Normally, we would expect `lld -r` to work. However, because LLD wants to resolve | 1461 | // copy when generating relocatables. Normally, we would expect `lld -r` to work. |
| 1451 | // BPF relocations which it shouldn't, it fails before even generating the relocatable. | 1462 | // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails |
| 1452 | if (self.base.options.output_mode == .Obj and (self.base.options.lto or target.isBpfFreestanding())) { | 1463 | // before even generating the relocatable. |
| 1464 | if (self.base.options.output_mode == .Obj and | ||
| 1465 | (self.base.options.lto or target.isBpfFreestanding())) | ||
| 1466 | { | ||
| 1453 | // In this case we must do a simple file copy | 1467 | // In this case we must do a simple file copy |
| 1454 | // here. TODO: think carefully about how we can avoid this redundant operation when doing | 1468 | // here. TODO: think carefully about how we can avoid this redundant operation when doing |
| 1455 | // build-obj. See also the corresponding TODO in linkAsArchive. | 1469 | // build-obj. See also the corresponding TODO in linkAsArchive. |
| ... | @@ -1473,7 +1487,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1473,7 +1487,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1473 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); | 1487 | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); |
| 1474 | } | 1488 | } |
| 1475 | } else { | 1489 | } else { |
| 1476 | |||
| 1477 | // Create an LLD command line and invoke it. | 1490 | // Create an LLD command line and invoke it. |
| 1478 | var argv = std.ArrayList([]const u8).init(self.base.allocator); | 1491 | var argv = std.ArrayList([]const u8).init(self.base.allocator); |
| 1479 | defer argv.deinit(); | 1492 | defer argv.deinit(); |
src/link/MachO.zig+24-7| ... | @@ -313,11 +313,10 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { | ... | @@ -313,11 +313,10 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 313 | // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`, | 313 | // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`, |
| 314 | // we also want to put the intermediary object file in the cache while the | 314 | // we also want to put the intermediary object file in the cache while the |
| 315 | // main emit directory is the cwd. | 315 | // main emit directory is the cwd. |
| 316 | const sub_path = try std.fmt.allocPrint(allocator, "{s}{s}", .{ | 316 | self.llvm_object = try LlvmObject.create(allocator, options); |
| 317 | self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{ | ||
| 317 | emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), | 318 | emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), |
| 318 | }); | 319 | }); |
| 319 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); | ||
| 320 | self.base.intermediary_basename = sub_path; | ||
| 321 | } | 320 | } |
| 322 | 321 | ||
| 323 | if (options.output_mode == .Lib and | 322 | if (options.output_mode == .Lib and |
| ... | @@ -373,7 +372,6 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { | ... | @@ -373,7 +372,6 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO { |
| 373 | } | 372 | } |
| 374 | 373 | ||
| 375 | pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { | 374 | pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 376 | const self = try gpa.create(MachO); | ||
| 377 | const cpu_arch = options.target.cpu.arch; | 375 | const cpu_arch = options.target.cpu.arch; |
| 378 | const os_tag = options.target.os.tag; | 376 | const os_tag = options.target.os.tag; |
| 379 | const abi = options.target.abi; | 377 | const abi = options.target.abi; |
| ... | @@ -383,6 +381,9 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { | ... | @@ -383,6 +381,9 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 383 | const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); | 381 | const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator); |
| 384 | const needs_prealloc = !(build_options.is_stage1 and options.use_stage1); | 382 | const needs_prealloc = !(build_options.is_stage1 and options.use_stage1); |
| 385 | 383 | ||
| 384 | const self = try gpa.create(MachO); | ||
| 385 | errdefer gpa.destroy(self); | ||
| 386 | |||
| 386 | self.* = .{ | 387 | self.* = .{ |
| 387 | .base = .{ | 388 | .base = .{ |
| 388 | .tag = .macho, | 389 | .tag = .macho, |
| ... | @@ -395,10 +396,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { | ... | @@ -395,10 +396,24 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 395 | .needs_prealloc = needs_prealloc, | 396 | .needs_prealloc = needs_prealloc, |
| 396 | }; | 397 | }; |
| 397 | 398 | ||
| 399 | const use_llvm = build_options.have_llvm and options.use_llvm; | ||
| 400 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | ||
| 401 | if (use_llvm and !use_stage1) { | ||
| 402 | self.llvm_object = try LlvmObject.create(gpa, options); | ||
| 403 | } | ||
| 404 | |||
| 398 | return self; | 405 | return self; |
| 399 | } | 406 | } |
| 400 | 407 | ||
| 401 | pub fn flush(self: *MachO, comp: *Compilation) !void { | 408 | pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 409 | if (self.base.options.emit == null) { | ||
| 410 | if (build_options.have_llvm) { | ||
| 411 | if (self.llvm_object) |llvm_object| { | ||
| 412 | return try llvm_object.flushModule(comp); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | return; | ||
| 416 | } | ||
| 402 | if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { | 417 | if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) { |
| 403 | if (build_options.have_llvm) { | 418 | if (build_options.have_llvm) { |
| 404 | return self.base.linkAsArchive(comp); | 419 | return self.base.linkAsArchive(comp); |
| ... | @@ -449,9 +464,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -449,9 +464,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 449 | 464 | ||
| 450 | try self.flushObject(comp); | 465 | try self.flushObject(comp); |
| 451 | 466 | ||
| 452 | break :blk try fs.path.join(arena, &.{ | 467 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 453 | fs.path.dirname(full_out_path).?, obj_basename, | 468 | break :blk try fs.path.join(arena, &.{ dirname, obj_basename }); |
| 454 | }); | 469 | } else { |
| 470 | break :blk obj_basename; | ||
| 471 | } | ||
| 455 | } else null; | 472 | } else null; |
| 456 | 473 | ||
| 457 | const is_lib = self.base.options.output_mode == .Lib; | 474 | const is_lib = self.base.options.output_mode == .Lib; |
src/link/Wasm.zig+23-11| ... | @@ -101,11 +101,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -101,11 +101,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 101 | assert(options.object_format == .wasm); | 101 | assert(options.object_format == .wasm); |
| 102 | 102 | ||
| 103 | if (build_options.have_llvm and options.use_llvm) { | 103 | if (build_options.have_llvm and options.use_llvm) { |
| 104 | const self = try createEmpty(allocator, options); | 104 | return createEmpty(allocator, options); |
| 105 | errdefer self.base.destroy(); | ||
| 106 | |||
| 107 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); | ||
| 108 | return self; | ||
| 109 | } | 105 | } |
| 110 | 106 | ||
| 111 | // TODO: read the file and keep valid parts instead of truncating | 107 | // TODO: read the file and keep valid parts instead of truncating |
| ... | @@ -139,8 +135,9 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -139,8 +135,9 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 139 | } | 135 | } |
| 140 | 136 | ||
| 141 | pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { | 137 | pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 142 | const wasm_bin = try gpa.create(Wasm); | 138 | const self = try gpa.create(Wasm); |
| 143 | wasm_bin.* = .{ | 139 | errdefer gpa.destroy(self); |
| 140 | self.* = .{ | ||
| 144 | .base = .{ | 141 | .base = .{ |
| 145 | .tag = .wasm, | 142 | .tag = .wasm, |
| 146 | .options = options, | 143 | .options = options, |
| ... | @@ -148,7 +145,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { | ... | @@ -148,7 +145,12 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 148 | .allocator = gpa, | 145 | .allocator = gpa, |
| 149 | }, | 146 | }, |
| 150 | }; | 147 | }; |
| 151 | return wasm_bin; | 148 | const use_llvm = build_options.have_llvm and options.use_llvm; |
| 149 | const use_stage1 = build_options.is_stage1 and options.use_stage1; | ||
| 150 | if (use_llvm and !use_stage1) { | ||
| 151 | self.llvm_object = try LlvmObject.create(gpa, options); | ||
| 152 | } | ||
| 153 | return self; | ||
| 152 | } | 154 | } |
| 153 | 155 | ||
| 154 | pub fn deinit(self: *Wasm) void { | 156 | pub fn deinit(self: *Wasm) void { |
| ... | @@ -576,6 +578,14 @@ fn resetState(self: *Wasm) void { | ... | @@ -576,6 +578,14 @@ fn resetState(self: *Wasm) void { |
| 576 | } | 578 | } |
| 577 | 579 | ||
| 578 | pub fn flush(self: *Wasm, comp: *Compilation) !void { | 580 | pub fn flush(self: *Wasm, comp: *Compilation) !void { |
| 581 | if (self.base.options.emit == null) { | ||
| 582 | if (build_options.have_llvm) { | ||
| 583 | if (self.llvm_object) |llvm_object| { | ||
| 584 | return try llvm_object.flushModule(comp); | ||
| 585 | } | ||
| 586 | } | ||
| 587 | return; | ||
| 588 | } | ||
| 579 | if (build_options.have_llvm and self.base.options.use_lld) { | 589 | if (build_options.have_llvm and self.base.options.use_lld) { |
| 580 | return self.linkWithLLD(comp); | 590 | return self.linkWithLLD(comp); |
| 581 | } else { | 591 | } else { |
| ... | @@ -1075,9 +1085,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1075,9 +1085,11 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void { |
| 1075 | 1085 | ||
| 1076 | try self.flushModule(comp); | 1086 | try self.flushModule(comp); |
| 1077 | 1087 | ||
| 1078 | break :blk try fs.path.join(arena, &.{ | 1088 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 1079 | fs.path.dirname(full_out_path).?, self.base.intermediary_basename.?, | 1089 | break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? }); |
| 1080 | }); | 1090 | } else { |
| 1091 | break :blk self.base.intermediary_basename.?; | ||
| 1092 | } | ||
| 1081 | } else null; | 1093 | } else null; |
| 1082 | 1094 | ||
| 1083 | const is_obj = self.base.options.output_mode == .Obj; | 1095 | const is_obj = self.base.options.output_mode == .Obj; |