Skip to content

Commit

Permalink
Merge branch 'alexnask-bundle_compiler_rt' into master
Browse files Browse the repository at this point in the history
Closes #7013
Closes #6817
  • Loading branch information
andrewrk committed Nov 30, 2020
2 parents 51d7c14 + ff9798e commit 205af5b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 31 deletions.
11 changes: 7 additions & 4 deletions lib/std/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ pub const LibExeObjStep = struct {
emit_bin: bool = true,
emit_docs: bool = false,
emit_h: bool = false,
bundle_compiler_rt: bool,
bundle_compiler_rt: ?bool = null,
disable_stack_probing: bool,
disable_sanitize_c: bool,
rdynamic: bool,
Expand Down Expand Up @@ -1395,7 +1395,6 @@ pub const LibExeObjStep = struct {
.exec_cmd_args = null,
.name_prefix = "",
.filter = null,
.bundle_compiler_rt = false,
.disable_stack_probing = false,
.disable_sanitize_c = false,
.rdynamic = false,
Expand Down Expand Up @@ -2120,8 +2119,12 @@ pub const LibExeObjStep = struct {
if (self.is_dynamic) {
try zig_args.append("-dynamic");
}
if (self.bundle_compiler_rt) {
try zig_args.append("--bundle-compiler-rt");
if (self.bundle_compiler_rt) |x| {
if (x) {
try zig_args.append("-fcompiler-rt");
} else {
try zig_args.append("-fno-compiler-rt");
}
}
if (self.disable_stack_probing) {
try zig_args.append("-fno-stack-check");
Expand Down
77 changes: 57 additions & 20 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ libc_static_lib: ?CRTFile = null,
/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
compiler_rt_static_lib: ?CRTFile = null,
/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue
/// and resolved before calling linker.flush().
compiler_rt_obj: ?CRTFile = null,

glibc_so_files: ?glibc.BuiltSharedObjects = null,

Expand Down Expand Up @@ -164,8 +167,8 @@ const Job = union(enum) {
libcxx: void,
libcxxabi: void,
libssp: void,
/// needed when producing a dynamic library or executable
libcompiler_rt: void,
compiler_rt_lib: void,
compiler_rt_obj: void,
/// needed when not linking libc and using LLVM for code generation because it generates
/// calls to, for example, memcpy and memset.
zig_libc: void,
Expand Down Expand Up @@ -350,6 +353,7 @@ pub const InitOptions = struct {
want_sanitize_c: ?bool = null,
want_stack_check: ?bool = null,
want_valgrind: ?bool = null,
want_compiler_rt: ?bool = null,
use_llvm: ?bool = null,
use_lld: ?bool = null,
use_clang: ?bool = null,
Expand Down Expand Up @@ -409,6 +413,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.Lib => is_dyn_lib,
.Exe => true,
};
const needs_c_symbols = !options.is_compiler_rt_or_libc and
(is_exe_or_dyn_lib or (options.target.isWasm() and options.output_mode != .Obj));

const comp: *Compilation = comp: {
// For allocations that have the same lifetime as Compilation. This arena is used only during this
// initialization and then is freed in deinit().
Expand Down Expand Up @@ -585,6 +592,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
};

const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;

const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);

const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
Expand Down Expand Up @@ -821,6 +830,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
.z_defs = options.linker_z_defs,
.stack_size_override = options.stack_size_override,
.image_base_override = options.image_base_override,
.include_compiler_rt = include_compiler_rt,
.linker_script = options.linker_script,
.version_script = options.version_script,
.gc_sections = options.linker_gc_sections,
Expand Down Expand Up @@ -967,16 +977,31 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
try comp.work_queue.writeItem(.libcxxabi);
}

const needs_compiler_rt_and_c = is_exe_or_dyn_lib or
(comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
if (needs_compiler_rt_and_c and build_options.is_stage1) {
try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
// MinGW provides no libssp, use our own implementation.
if (comp.getTarget().isMinGW()) {
try comp.work_queue.writeItem(.{ .libssp = {} });
// The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt.
// Once it is capable this condition should be removed.
if (build_options.is_stage1) {
if (comp.bin_file.options.include_compiler_rt) {
if (is_exe_or_dyn_lib) {
try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
} else {
try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
if (comp.bin_file.options.object_format != .elf) {
// For ELF we can rely on using -r to link multiple objects together into one,
// but to truly support `build-obj -fcompiler-rt` will require virtually
// injecting `_ = @import("compiler_rt.zig")` into the root source file of
// the compilation.
fatal("Embedding compiler-rt into non-ELF objects is not yet implemented.", .{});
}
}
}
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()) {
try comp.work_queue.writeItem(.{ .libssp = {} });
}
if (!comp.bin_file.options.link_libc) {
try comp.work_queue.writeItem(.{ .zig_libc = {} });
}
}
}
}
Expand Down Expand Up @@ -1374,20 +1399,26 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
fatal("unable to build libcxxabi: {}", .{@errorName(err)});
};
},
.libcompiler_rt => {
self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
.compiler_rt_lib => {
self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build compiler_rt: {}", .{@errorName(err)});
fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
};
},
.compiler_rt_obj => {
self.buildOutputFromZig("compiler_rt.zig", .Obj, &self.compiler_rt_obj) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
};
},
.libssp => {
self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| {
self.buildOutputFromZig("ssp.zig", .Lib, &self.libssp_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build libssp: {}", .{@errorName(err)});
};
},
.zig_libc => {
self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
self.buildOutputFromZig("c.zig", .Lib, &self.libc_static_lib) catch |err| {
// TODO Expose this as a normal compile error rather than crashing here.
fatal("unable to build zig's multitarget libc: {}", .{@errorName(err)});
};
Expand Down Expand Up @@ -2551,10 +2582,16 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
}
}

fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void {
fn buildOutputFromZig(
comp: *Compilation,
src_basename: []const u8,
output_mode: std.builtin.OutputMode,
out: *?CRTFile,
) !void {
const tracy = trace(@src());
defer tracy.end();

std.debug.assert(output_mode != .Exe);
const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
defer comp.gpa.free(special_path);
Expand All @@ -2571,11 +2608,11 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
};
const root_name = mem.split(src_basename, ".").next().?;
const target = comp.getTarget();
const output_mode: std.builtin.OutputMode = if (target.cpu.arch.isWasm()) .Obj else .Lib;
const fixed_output_mode = if (target.cpu.arch.isWasm()) .Obj else output_mode;
const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
.root_name = root_name,
.target = target,
.output_mode = output_mode,
.output_mode = fixed_output_mode,
});
defer comp.gpa.free(bin_basename);

Expand All @@ -2598,7 +2635,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
.target = target,
.root_name = root_name,
.root_pkg = &root_pkg,
.output_mode = output_mode,
.output_mode = fixed_output_mode,
.rand = comp.rand,
.libc_installation = comp.bin_file.options.libc_installation,
.emit_bin = emit_bin,
Expand Down
12 changes: 11 additions & 1 deletion src/link.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub const Options = struct {
entry_addr: ?u64 = null,
stack_size_override: ?u64,
image_base_override: ?u64,
include_compiler_rt: bool,
/// Set to `true` to omit debug info.
strip: bool,
/// If this is true then this link code is responsible for outputting an object
Expand Down Expand Up @@ -473,6 +474,11 @@ pub const File = struct {
break :blk full_obj_path;
} else null;

const compiler_rt_path: ?[]const u8 = if (base.options.include_compiler_rt)
comp.compiler_rt_obj.?.full_object_path
else
null;

// This function follows the same pattern as link.Elf.linkWithLLD so if you want some
// insight as to what's going on here you can read that function body which is more
// well-commented.
Expand All @@ -489,6 +495,7 @@ pub const File = struct {
_ = try ch.addFile(entry.key.status.success.object_path, null);
}
try ch.addOptionalFile(module_obj_path);
try ch.addOptionalFile(compiler_rt_path);

// We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
_ = try ch.hit();
Expand Down Expand Up @@ -518,7 +525,7 @@ pub const File = struct {
var object_files = std.ArrayList([*:0]const u8).init(base.allocator);
defer object_files.deinit();

try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 1);
try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 2);
for (base.options.objects) |obj_path| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj_path));
}
Expand All @@ -528,6 +535,9 @@ pub const File = struct {
if (module_obj_path) |p| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
}
if (compiler_rt_path) |p| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
}

const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path});
const full_out_path_z = try arena.dupeZ(u8, full_out_path);
Expand Down
23 changes: 17 additions & 6 deletions src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
const gc_sections = self.base.options.gc_sections orelse !is_obj;
const stack_size = self.base.options.stack_size_override orelse 16777216;
const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt) blk: {
if (is_exe_or_dyn_lib) {
break :blk comp.compiler_rt_static_lib.?.full_object_path;
} else {
break :blk comp.compiler_rt_obj.?.full_object_path;
}
} else null;

// Here we want to determine whether we can save time by not invoking LLD when the
// output is unchanged. None of the linker options or the object files that are being
Expand Down Expand Up @@ -1289,6 +1296,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
_ = try man.addFile(entry.key.status.success.object_path, null);
}
try man.addOptionalFile(module_obj_path);
try man.addOptionalFile(compiler_rt_path);

// We can skip hashing libc and libc++ components that we are in charge of building from Zig
// installation sources because they are always a product of the compiler version + target information.
man.hash.add(stack_size);
Expand Down Expand Up @@ -1531,12 +1540,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
try argv.append(p);
}

// compiler-rt and libc
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
if (!self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}
try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
// libc
if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc and !self.base.options.link_libc) {
try argv.append(comp.libc_static_lib.?.full_object_path);
}

// compiler-rt
if (compiler_rt_path) |p| {
try argv.append(p);
}

// Shared libraries.
Expand Down
8 changes: 8 additions & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ const usage_build_generic =
\\ -fno-soname (Linux) Disable emitting a SONAME
\\ -fLLD Force using LLD as the linker
\\ -fno-LLD Prevent using LLD as the linker
\\ -fcompiler-rt Always include compiler-rt symbols in output
\\ -fno-compiler-rt Prevent including compiler-rt symbols in output
\\ -rdynamic Add all symbols to the dynamic symbol table
\\ -rpath [path] Add directory to the runtime library search path
\\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
Expand Down Expand Up @@ -478,6 +480,7 @@ fn buildOutputType(
var want_sanitize_c: ?bool = null;
var want_stack_check: ?bool = null;
var want_valgrind: ?bool = null;
var want_compiler_rt: ?bool = null;
var rdynamic: bool = false;
var linker_script: ?[]const u8 = null;
var version_script: ?[]const u8 = null;
Expand Down Expand Up @@ -794,6 +797,10 @@ fn buildOutputType(
if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
i += 1;
override_lib_dir = args[i];
} else if (mem.eql(u8, arg, "-fcompiler-rt")) {
want_compiler_rt = true;
} else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
want_compiler_rt = false;
} else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
each_lib_rpath = true;
} else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
Expand Down Expand Up @@ -1688,6 +1695,7 @@ fn buildOutputType(
.want_sanitize_c = want_sanitize_c,
.want_stack_check = want_stack_check,
.want_valgrind = want_valgrind,
.want_compiler_rt = want_compiler_rt,
.use_llvm = use_llvm,
.use_lld = use_lld,
.use_clang = use_clang,
Expand Down

0 comments on commit 205af5b

Please sign in to comment.