| author | |
| committer | |
| log | ef7fa76001f873824b0f64dfc2172ed2f304c348 |
| tree | ea739ef9170f446568c6a328ff9428f78c0ad165 |
| parent | f215d98043ef948a996ac036609f4b71fa9c3c13 |
* LLVM backend: respect `sub_path` just like the other stage2 backends
do.
* Compilation has some new logic to only emit work queue jobs for
building stuff when it believes itself to be capable. The linker
backends no longer have duplicate logic; instead they respect the
optional bit on the respective asset.7 files changed, 60 insertions(+), 61 deletions(-)
src/Compilation.zig+22-18| ... | @@ -1574,25 +1574,29 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -1574,25 +1574,29 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 1574 | // also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler | 1574 | // also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler |
| 1575 | // and make sure the compiler-rt symbols are emitted. Currently this is hooked up for | 1575 | // and make sure the compiler-rt symbols are emitted. Currently this is hooked up for |
| 1576 | // stage1 but not stage2. | 1576 | // stage1 but not stage2. |
| 1577 | if (comp.bin_file.options.use_stage1) { | 1577 | const capable_of_building_compiler_rt = comp.bin_file.options.use_stage1; |
| 1578 | if (comp.bin_file.options.include_compiler_rt) { | 1578 | const capable_of_building_ssp = comp.bin_file.options.use_stage1; |
| 1579 | if (is_exe_or_dyn_lib) { | 1579 | const capable_of_building_zig_libc = comp.bin_file.options.use_stage1 or |
| 1580 | try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} }); | 1580 | comp.bin_file.options.use_llvm; |
| 1581 | } else if (options.output_mode != .Obj) { | 1581 | |
| 1582 | // If build-obj with -fcompiler-rt is requested, that is handled specially | 1582 | if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { |
| 1583 | // elsewhere. In this case we are making a static library, so we ask | 1583 | if (is_exe_or_dyn_lib) { |
| 1584 | // for a compiler-rt object to put in it. | 1584 | try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} }); |
| 1585 | try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} }); | 1585 | } else if (options.output_mode != .Obj) { |
| 1586 | } | 1586 | // If build-obj with -fcompiler-rt is requested, that is handled specially |
| 1587 | // elsewhere. In this case we are making a static library, so we ask | ||
| 1588 | // for a compiler-rt object to put in it. | ||
| 1589 | try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} }); | ||
| 1587 | } | 1590 | } |
| 1588 | if (needs_c_symbols) { | 1591 | } |
| 1589 | // MinGW provides no libssp, use our own implementation. | 1592 | if (needs_c_symbols) { |
| 1590 | if (comp.getTarget().isMinGW()) { | 1593 | // MinGW provides no libssp, use our own implementation. |
| 1591 | try comp.work_queue.writeItem(.{ .libssp = {} }); | 1594 | if (comp.getTarget().isMinGW() and capable_of_building_ssp) { |
| 1592 | } | 1595 | try comp.work_queue.writeItem(.{ .libssp = {} }); |
| 1593 | if (!comp.bin_file.options.link_libc) { | 1596 | } |
| 1594 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); | 1597 | |
| 1595 | } | 1598 | if (!comp.bin_file.options.link_libc and capable_of_building_zig_libc) { |
| 1599 | try comp.work_queue.writeItem(.{ .zig_libc = {} }); | ||
| 1596 | } | 1600 | } |
| 1597 | } | 1601 | } |
| 1598 | } | 1602 | } |
src/codegen/llvm.zig+13-15| ... | @@ -164,15 +164,17 @@ pub const Object = struct { | ... | @@ -164,15 +164,17 @@ pub const Object = struct { |
| 164 | /// * it works for functions not all globals. | 164 | /// * it works for functions not all globals. |
| 165 | /// Therefore, this table keeps track of the mapping. | 165 | /// Therefore, this table keeps track of the mapping. |
| 166 | decl_map: std.AutoHashMapUnmanaged(*const Module.Decl, *const llvm.Value), | 166 | decl_map: std.AutoHashMapUnmanaged(*const Module.Decl, *const llvm.Value), |
| 167 | /// Where to put the output object file, relative to bin_file.options.emit directory. | ||
| 168 | sub_path: []const u8, | ||
| 167 | 169 | ||
| 168 | pub fn create(gpa: *Allocator, options: link.Options) !*Object { | 170 | pub fn create(gpa: *Allocator, sub_path: []const u8, options: link.Options) !*Object { |
| 169 | const obj = try gpa.create(Object); | 171 | const obj = try gpa.create(Object); |
| 170 | errdefer gpa.destroy(obj); | 172 | errdefer gpa.destroy(obj); |
| 171 | obj.* = try Object.init(gpa, options); | 173 | obj.* = try Object.init(gpa, sub_path, options); |
| 172 | return obj; | 174 | return obj; |
| 173 | } | 175 | } |
| 174 | 176 | ||
| 175 | pub fn init(gpa: *Allocator, options: link.Options) !Object { | 177 | pub fn init(gpa: *Allocator, sub_path: []const u8, options: link.Options) !Object { |
| 176 | const context = llvm.Context.create(); | 178 | const context = llvm.Context.create(); |
| 177 | errdefer context.dispose(); | 179 | errdefer context.dispose(); |
| 178 | 180 | ||
| ... | @@ -251,6 +253,7 @@ pub const Object = struct { | ... | @@ -251,6 +253,7 @@ pub const Object = struct { |
| 251 | .context = context, | 253 | .context = context, |
| 252 | .target_machine = target_machine, | 254 | .target_machine = target_machine, |
| 253 | .decl_map = .{}, | 255 | .decl_map = .{}, |
| 256 | .sub_path = sub_path, | ||
| 254 | }; | 257 | }; |
| 255 | } | 258 | } |
| 256 | 259 | ||
| ... | @@ -301,23 +304,18 @@ pub const Object = struct { | ... | @@ -301,23 +304,18 @@ pub const Object = struct { |
| 301 | const mod = comp.bin_file.options.module.?; | 304 | const mod = comp.bin_file.options.module.?; |
| 302 | const cache_dir = mod.zig_cache_artifact_directory; | 305 | const cache_dir = mod.zig_cache_artifact_directory; |
| 303 | 306 | ||
| 304 | const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit != null) blk: { | 307 | const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| |
| 305 | const obj_basename = try std.zig.binNameAlloc(arena, .{ | 308 | try emit.directory.joinZ(arena, &[_][]const u8{self.sub_path}) |
| 306 | .root_name = comp.bin_file.options.root_name, | 309 | else |
| 307 | .target = comp.bin_file.options.target, | 310 | null; |
| 308 | .output_mode = .Obj, | ||
| 309 | }); | ||
| 310 | if (cache_dir.joinZ(arena, &[_][]const u8{obj_basename})) |p| { | ||
| 311 | break :blk p.ptr; | ||
| 312 | } else |err| { | ||
| 313 | return err; | ||
| 314 | } | ||
| 315 | } else null; | ||
| 316 | 311 | ||
| 317 | const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir); | 312 | const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir); |
| 318 | const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir); | 313 | const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir); |
| 319 | const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir); | 314 | const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir); |
| 320 | 315 | ||
| 316 | const debug_emit_path = emit_bin_path orelse "(none)"; | ||
| 317 | log.debug("emit LLVM object to {s}", .{debug_emit_path}); | ||
| 318 | |||
| 321 | var error_message: [*:0]const u8 = undefined; | 319 | var error_message: [*:0]const u8 = undefined; |
| 322 | if (self.target_machine.emitToFile( | 320 | if (self.target_machine.emitToFile( |
| 323 | self.llvm_module, | 321 | self.llvm_module, |
src/link.zig+3| ... | @@ -245,6 +245,9 @@ pub const File = struct { | ... | @@ -245,6 +245,9 @@ pub const File = struct { |
| 245 | }; | 245 | }; |
| 246 | 246 | ||
| 247 | if (use_lld) { | 247 | if (use_lld) { |
| 248 | // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`, | ||
| 249 | // we also want to put the intermediary object file in the cache while the | ||
| 250 | // main emit directory is the cwd. | ||
| 248 | file.intermediary_basename = sub_path; | 251 | file.intermediary_basename = sub_path; |
| 249 | } | 252 | } |
| 250 | 253 |
src/link/Coff.zig+13-15| ... | @@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 132 | const self = try createEmpty(allocator, options); | 132 | const self = try createEmpty(allocator, options); |
| 133 | errdefer self.base.destroy(); | 133 | errdefer self.base.destroy(); |
| 134 | 134 | ||
| 135 | self.llvm_object = try LlvmObject.create(allocator, options); | 135 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); |
| 136 | return self; | 136 | return self; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| ... | @@ -884,11 +884,8 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { | ... | @@ -884,11 +884,8 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 884 | // If there is no Zig code to compile, then we should skip flushing the output file because it | 884 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 885 | // will not be part of the linker line anyway. | 885 | // will not be part of the linker line anyway. |
| 886 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { | 886 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { |
| 887 | // Both stage1 and stage2 LLVM backend put the object file in the cache directory. | 887 | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; |
| 888 | if (self.base.options.use_llvm) { | 888 | if (use_stage1) { |
| 889 | // Stage2 has to call flushModule since that outputs the LLVM object file. | ||
| 890 | if (!build_options.is_stage1 or !self.base.options.use_stage1) try self.flushModule(comp); | ||
| 891 | |||
| 892 | const obj_basename = try std.zig.binNameAlloc(arena, .{ | 889 | const obj_basename = try std.zig.binNameAlloc(arena, .{ |
| 893 | .root_name = self.base.options.root_name, | 890 | .root_name = self.base.options.root_name, |
| 894 | .target = self.base.options.target, | 891 | .target = self.base.options.target, |
| ... | @@ -1269,22 +1266,23 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { | ... | @@ -1269,22 +1266,23 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void { |
| 1269 | try argv.append(comp.libunwind_static_lib.?.full_object_path); | 1266 | try argv.append(comp.libunwind_static_lib.?.full_object_path); |
| 1270 | } | 1267 | } |
| 1271 | 1268 | ||
| 1272 | // TODO: remove when stage2 can build compiler_rt.zig, c.zig and ssp.zig | 1269 | if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) { |
| 1273 | // compiler-rt, libc and libssp | ||
| 1274 | if (is_exe_or_dyn_lib and | ||
| 1275 | !self.base.options.skip_linker_dependencies and | ||
| 1276 | build_options.is_stage1 and self.base.options.use_stage1) | ||
| 1277 | { | ||
| 1278 | if (!self.base.options.link_libc) { | 1270 | if (!self.base.options.link_libc) { |
| 1279 | try argv.append(comp.libc_static_lib.?.full_object_path); | 1271 | if (comp.libc_static_lib) |lib| { |
| 1272 | try argv.append(lib.full_object_path); | ||
| 1273 | } | ||
| 1280 | } | 1274 | } |
| 1281 | // MinGW doesn't provide libssp symbols | 1275 | // MinGW doesn't provide libssp symbols |
| 1282 | if (target.abi.isGnu()) { | 1276 | if (target.abi.isGnu()) { |
| 1283 | try argv.append(comp.libssp_static_lib.?.full_object_path); | 1277 | if (comp.libssp_static_lib) |lib| { |
| 1278 | try argv.append(lib.full_object_path); | ||
| 1279 | } | ||
| 1284 | } | 1280 | } |
| 1285 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but | 1281 | // MSVC compiler_rt is missing some stuff, so we build it unconditionally but |
| 1286 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. | 1282 | // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. |
| 1287 | try argv.append(comp.compiler_rt_static_lib.?.full_object_path); | 1283 | if (comp.compiler_rt_static_lib) |lib| { |
| 1284 | try argv.append(lib.full_object_path); | ||
| 1285 | } | ||
| 1288 | } | 1286 | } |
| 1289 | 1287 | ||
| 1290 | try argv.ensureUnusedCapacity(self.base.options.system_libs.count()); | 1288 | try argv.ensureUnusedCapacity(self.base.options.system_libs.count()); |
src/link/Elf.zig+7-11| ... | @@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 235 | const self = try createEmpty(allocator, options); | 235 | const self = try createEmpty(allocator, options); |
| 236 | errdefer self.base.destroy(); | 236 | errdefer self.base.destroy(); |
| 237 | 237 | ||
| 238 | self.llvm_object = try LlvmObject.create(allocator, options); | 238 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); |
| 239 | return self; | 239 | return self; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| ... | @@ -1254,11 +1254,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1254,11 +1254,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1254 | // If there is no Zig code to compile, then we should skip flushing the output file because it | 1254 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 1255 | // will not be part of the linker line anyway. | 1255 | // will not be part of the linker line anyway. |
| 1256 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { | 1256 | const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: { |
| 1257 | // Both stage1 and stage2 LLVM backend put the object file in the cache directory. | 1257 | // stage1 puts the object file in the cache directory. |
| 1258 | if (self.base.options.use_llvm) { | 1258 | if (self.base.options.use_stage1) { |
| 1259 | // Stage2 has to call flushModule since that outputs the LLVM object file. | ||
| 1260 | if (!build_options.is_stage1 or !self.base.options.use_stage1) try self.flushModule(comp); | ||
| 1261 | |||
| 1262 | const obj_basename = try std.zig.binNameAlloc(arena, .{ | 1259 | const obj_basename = try std.zig.binNameAlloc(arena, .{ |
| 1263 | .root_name = self.base.options.root_name, | 1260 | .root_name = self.base.options.root_name, |
| 1264 | .target = self.base.options.target, | 1261 | .target = self.base.options.target, |
| ... | @@ -1621,14 +1618,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1621,14 +1618,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1621 | } | 1618 | } |
| 1622 | 1619 | ||
| 1623 | // libc | 1620 | // libc |
| 1624 | // TODO: enable when stage2 can build c.zig | ||
| 1625 | if (is_exe_or_dyn_lib and | 1621 | if (is_exe_or_dyn_lib and |
| 1626 | !self.base.options.skip_linker_dependencies and | 1622 | !self.base.options.skip_linker_dependencies and |
| 1627 | !self.base.options.link_libc and | 1623 | !self.base.options.link_libc) |
| 1628 | build_options.is_stage1 and | ||
| 1629 | self.base.options.use_stage1) | ||
| 1630 | { | 1624 | { |
| 1631 | try argv.append(comp.libc_static_lib.?.full_object_path); | 1625 | if (comp.libc_static_lib) |lib| { |
| 1626 | try argv.append(lib.full_object_path); | ||
| 1627 | } | ||
| 1632 | } | 1628 | } |
| 1633 | 1629 | ||
| 1634 | // compiler-rt | 1630 | // compiler-rt |
src/link/MachO.zig+1-1| ... | @@ -290,7 +290,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -290,7 +290,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 290 | const self = try createEmpty(allocator, options); | 290 | const self = try createEmpty(allocator, options); |
| 291 | errdefer self.base.destroy(); | 291 | errdefer self.base.destroy(); |
| 292 | 292 | ||
| 293 | self.llvm_object = try LlvmObject.create(allocator, options); | 293 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); |
| 294 | return self; | 294 | return self; |
| 295 | } | 295 | } |
| 296 | 296 |
src/link/Wasm.zig+1-1| ... | @@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 121 | const self = try createEmpty(allocator, options); | 121 | const self = try createEmpty(allocator, options); |
| 122 | errdefer self.base.destroy(); | 122 | errdefer self.base.destroy(); |
| 123 | 123 | ||
| 124 | self.llvm_object = try LlvmObject.create(allocator, options); | 124 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); |
| 125 | return self; | 125 | return self; |
| 126 | } | 126 | } |
| 127 | 127 |