Commit ef7fa76001
src/codegen/llvm.zig
@@ -164,15 +164,17 @@ pub const Object = struct {
/// * it works for functions not all globals.
/// Therefore, this table keeps track of the mapping.
decl_map: std.AutoHashMapUnmanaged(*const Module.Decl, *const llvm.Value),
+ /// Where to put the output object file, relative to bin_file.options.emit directory.
+ sub_path: []const u8,
- pub fn create(gpa: *Allocator, options: link.Options) !*Object {
+ pub fn create(gpa: *Allocator, sub_path: []const u8, options: link.Options) !*Object {
const obj = try gpa.create(Object);
errdefer gpa.destroy(obj);
- obj.* = try Object.init(gpa, options);
+ obj.* = try Object.init(gpa, sub_path, options);
return obj;
}
- pub fn init(gpa: *Allocator, options: link.Options) !Object {
+ pub fn init(gpa: *Allocator, sub_path: []const u8, options: link.Options) !Object {
const context = llvm.Context.create();
errdefer context.dispose();
@@ -251,6 +253,7 @@ pub const Object = struct {
.context = context,
.target_machine = target_machine,
.decl_map = .{},
+ .sub_path = sub_path,
};
}
@@ -301,23 +304,18 @@ pub const Object = struct {
const mod = comp.bin_file.options.module.?;
const cache_dir = mod.zig_cache_artifact_directory;
- const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit != null) blk: {
- const obj_basename = try std.zig.binNameAlloc(arena, .{
- .root_name = comp.bin_file.options.root_name,
- .target = comp.bin_file.options.target,
- .output_mode = .Obj,
- });
- if (cache_dir.joinZ(arena, &[_][]const u8{obj_basename})) |p| {
- break :blk p.ptr;
- } else |err| {
- return err;
- }
- } else null;
+ const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|
+ try emit.directory.joinZ(arena, &[_][]const u8{self.sub_path})
+ else
+ null;
const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir);
const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir);
const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir);
+ const debug_emit_path = emit_bin_path orelse "(none)";
+ log.debug("emit LLVM object to {s}", .{debug_emit_path});
+
var error_message: [*:0]const u8 = undefined;
if (self.target_machine.emitToFile(
self.llvm_module,
src/link/Coff.zig
@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
- self.llvm_object = try LlvmObject.create(allocator, options);
+ self.llvm_object = try LlvmObject.create(allocator, sub_path, options);
return self;
}
@@ -884,11 +884,8 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
- // Both stage1 and stage2 LLVM backend put the object file in the cache directory.
- if (self.base.options.use_llvm) {
- // Stage2 has to call flushModule since that outputs the LLVM object file.
- if (!build_options.is_stage1 or !self.base.options.use_stage1) try self.flushModule(comp);
-
+ const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
+ if (use_stage1) {
const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
.target = self.base.options.target,
@@ -1269,22 +1266,23 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
try argv.append(comp.libunwind_static_lib.?.full_object_path);
}
- // TODO: remove when stage2 can build compiler_rt.zig, c.zig and ssp.zig
- // compiler-rt, libc and libssp
- if (is_exe_or_dyn_lib and
- !self.base.options.skip_linker_dependencies and
- build_options.is_stage1 and self.base.options.use_stage1)
- {
+ if (is_exe_or_dyn_lib and !self.base.options.skip_linker_dependencies) {
if (!self.base.options.link_libc) {
- try argv.append(comp.libc_static_lib.?.full_object_path);
+ if (comp.libc_static_lib) |lib| {
+ try argv.append(lib.full_object_path);
+ }
}
// MinGW doesn't provide libssp symbols
if (target.abi.isGnu()) {
- try argv.append(comp.libssp_static_lib.?.full_object_path);
+ if (comp.libssp_static_lib) |lib| {
+ try argv.append(lib.full_object_path);
+ }
}
// MSVC compiler_rt is missing some stuff, so we build it unconditionally but
// and rely on weak linkage to allow MSVC compiler_rt functions to override ours.
- try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
+ if (comp.compiler_rt_static_lib) |lib| {
+ try argv.append(lib.full_object_path);
+ }
}
try argv.ensureUnusedCapacity(self.base.options.system_libs.count());
src/link/Elf.zig
@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
- self.llvm_object = try LlvmObject.create(allocator, options);
+ self.llvm_object = try LlvmObject.create(allocator, sub_path, options);
return self;
}
@@ -1254,11 +1254,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
// If there is no Zig code to compile, then we should skip flushing the output file because it
// will not be part of the linker line anyway.
const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
- // Both stage1 and stage2 LLVM backend put the object file in the cache directory.
- if (self.base.options.use_llvm) {
- // Stage2 has to call flushModule since that outputs the LLVM object file.
- if (!build_options.is_stage1 or !self.base.options.use_stage1) try self.flushModule(comp);
-
+ // stage1 puts the object file in the cache directory.
+ if (self.base.options.use_stage1) {
const obj_basename = try std.zig.binNameAlloc(arena, .{
.root_name = self.base.options.root_name,
.target = self.base.options.target,
@@ -1621,14 +1618,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
}
// libc
- // TODO: enable when stage2 can build c.zig
if (is_exe_or_dyn_lib and
!self.base.options.skip_linker_dependencies and
- !self.base.options.link_libc and
- build_options.is_stage1 and
- self.base.options.use_stage1)
+ !self.base.options.link_libc)
{
- try argv.append(comp.libc_static_lib.?.full_object_path);
+ if (comp.libc_static_lib) |lib| {
+ try argv.append(lib.full_object_path);
+ }
}
// compiler-rt
src/link/MachO.zig
@@ -290,7 +290,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
- self.llvm_object = try LlvmObject.create(allocator, options);
+ self.llvm_object = try LlvmObject.create(allocator, sub_path, options);
return self;
}
src/link/Wasm.zig
@@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
const self = try createEmpty(allocator, options);
errdefer self.base.destroy();
- self.llvm_object = try LlvmObject.create(allocator, options);
+ self.llvm_object = try LlvmObject.create(allocator, sub_path, options);
return self;
}
src/Compilation.zig
@@ -1574,25 +1574,29 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
// also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler
// and make sure the compiler-rt symbols are emitted. Currently this is hooked up for
// stage1 but not stage2.
- if (comp.bin_file.options.use_stage1) {
- if (comp.bin_file.options.include_compiler_rt) {
- if (is_exe_or_dyn_lib) {
- try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
- } else if (options.output_mode != .Obj) {
- // If build-obj with -fcompiler-rt is requested, that is handled specially
- // elsewhere. In this case we are making a static library, so we ask
- // for a compiler-rt object to put in it.
- try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
- }
+ const capable_of_building_compiler_rt = comp.bin_file.options.use_stage1;
+ const capable_of_building_ssp = comp.bin_file.options.use_stage1;
+ const capable_of_building_zig_libc = comp.bin_file.options.use_stage1 or
+ comp.bin_file.options.use_llvm;
+
+ if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
+ if (is_exe_or_dyn_lib) {
+ try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
+ } else if (options.output_mode != .Obj) {
+ // If build-obj with -fcompiler-rt is requested, that is handled specially
+ // elsewhere. In this case we are making a static library, so we ask
+ // for a compiler-rt object to put in it.
+ try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
}
- if (needs_c_symbols) {
- // MinGW provides no libssp, use our own implementation.
- if (comp.getTarget().isMinGW()) {
- try comp.work_queue.writeItem(.{ .libssp = {} });
- }
- if (!comp.bin_file.options.link_libc) {
- try comp.work_queue.writeItem(.{ .zig_libc = {} });
- }
+ }
+ if (needs_c_symbols) {
+ // MinGW provides no libssp, use our own implementation.
+ if (comp.getTarget().isMinGW() and capable_of_building_ssp) {
+ try comp.work_queue.writeItem(.{ .libssp = {} });
+ }
+
+ if (!comp.bin_file.options.link_libc and capable_of_building_zig_libc) {
+ try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
}
src/link.zig
@@ -245,6 +245,9 @@ pub const File = struct {
};
if (use_lld) {
+ // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
+ // we also want to put the intermediary object file in the cache while the
+ // main emit directory is the cwd.
file.intermediary_basename = sub_path;
}