authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-30 16:40:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-30 16:40:25-07:00
log205af5b14828d64c10f5c67e05cebf32b882c646
treea76c48fca7b7458f41c4dca14f9ec9eb30325818
parent51d7c14ce1bdadc4405474cfb3945581c198c741
parentff9798eb265b02d572ecbced675efcd7c763aea9

Merge branch 'alexnask-bundle_compiler_rt' into master

Closes #7013 Closes #6817

5 files changed, 100 insertions(+), 31 deletions(-)

lib/std/build.zig+7-4
......@@ -1216,7 +1216,7 @@ pub const LibExeObjStep = struct {
12161216 emit_bin: bool = true,
12171217 emit_docs: bool = false,
12181218 emit_h: bool = false,
1219 bundle_compiler_rt: bool,
1219 bundle_compiler_rt: ?bool = null,
12201220 disable_stack_probing: bool,
12211221 disable_sanitize_c: bool,
12221222 rdynamic: bool,
......@@ -1395,7 +1395,6 @@ pub const LibExeObjStep = struct {
13951395 .exec_cmd_args = null,
13961396 .name_prefix = "",
13971397 .filter = null,
1398 .bundle_compiler_rt = false,
13991398 .disable_stack_probing = false,
14001399 .disable_sanitize_c = false,
14011400 .rdynamic = false,
......@@ -2120,8 +2119,12 @@ pub const LibExeObjStep = struct {
21202119 if (self.is_dynamic) {
21212120 try zig_args.append("-dynamic");
21222121 }
2123 if (self.bundle_compiler_rt) {
2124 try zig_args.append("--bundle-compiler-rt");
2122 if (self.bundle_compiler_rt) |x| {
2123 if (x) {
2124 try zig_args.append("-fcompiler-rt");
2125 } else {
2126 try zig_args.append("-fno-compiler-rt");
2127 }
21252128 }
21262129 if (self.disable_stack_probing) {
21272130 try zig_args.append("-fno-stack-check");
src/Compilation.zig+57-20
......@@ -93,6 +93,9 @@ libc_static_lib: ?CRTFile = null,
9393/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
9494/// and resolved before calling linker.flush().
9595compiler_rt_static_lib: ?CRTFile = null,
96/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue
97/// and resolved before calling linker.flush().
98compiler_rt_obj: ?CRTFile = null,
9699
97100glibc_so_files: ?glibc.BuiltSharedObjects = null,
98101
......@@ -164,8 +167,8 @@ const Job = union(enum) {
164167 libcxx: void,
165168 libcxxabi: void,
166169 libssp: void,
167 /// needed when producing a dynamic library or executable
168 libcompiler_rt: void,
170 compiler_rt_lib: void,
171 compiler_rt_obj: void,
169172 /// needed when not linking libc and using LLVM for code generation because it generates
170173 /// calls to, for example, memcpy and memset.
171174 zig_libc: void,
......@@ -350,6 +353,7 @@ pub const InitOptions = struct {
350353 want_sanitize_c: ?bool = null,
351354 want_stack_check: ?bool = null,
352355 want_valgrind: ?bool = null,
356 want_compiler_rt: ?bool = null,
353357 use_llvm: ?bool = null,
354358 use_lld: ?bool = null,
355359 use_clang: ?bool = null,
......@@ -409,6 +413,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
409413 .Lib => is_dyn_lib,
410414 .Exe => true,
411415 };
416 const needs_c_symbols = !options.is_compiler_rt_or_libc and
417 (is_exe_or_dyn_lib or (options.target.isWasm() and options.output_mode != .Obj));
418
412419 const comp: *Compilation = comp: {
413420 // For allocations that have the same lifetime as Compilation. This arena is used only during this
414421 // initialization and then is freed in deinit().
......@@ -585,6 +592,8 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
585592 break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
586593 };
587594
595 const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;
596
588597 const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
589598
590599 const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
......@@ -821,6 +830,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
821830 .z_defs = options.linker_z_defs,
822831 .stack_size_override = options.stack_size_override,
823832 .image_base_override = options.image_base_override,
833 .include_compiler_rt = include_compiler_rt,
824834 .linker_script = options.linker_script,
825835 .version_script = options.version_script,
826836 .gc_sections = options.linker_gc_sections,
......@@ -967,16 +977,31 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
967977 try comp.work_queue.writeItem(.libcxxabi);
968978 }
969979
970 const needs_compiler_rt_and_c = is_exe_or_dyn_lib or
971 (comp.getTarget().isWasm() and comp.bin_file.options.output_mode != .Obj);
972 if (needs_compiler_rt_and_c and build_options.is_stage1) {
973 try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
974 // MinGW provides no libssp, use our own implementation.
975 if (comp.getTarget().isMinGW()) {
976 try comp.work_queue.writeItem(.{ .libssp = {} });
980 // The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt.
981 // Once it is capable this condition should be removed.
982 if (build_options.is_stage1) {
983 if (comp.bin_file.options.include_compiler_rt) {
984 if (is_exe_or_dyn_lib) {
985 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
986 } else {
987 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
988 if (comp.bin_file.options.object_format != .elf) {
989 // For ELF we can rely on using -r to link multiple objects together into one,
990 // but to truly support `build-obj -fcompiler-rt` will require virtually
991 // injecting `_ = @import("compiler_rt.zig")` into the root source file of
992 // the compilation.
993 fatal("Embedding compiler-rt into non-ELF objects is not yet implemented.", .{});
994 }
995 }
977996 }
978 if (!comp.bin_file.options.link_libc) {
979 try comp.work_queue.writeItem(.{ .zig_libc = {} });
997 if (needs_c_symbols) {
998 // MinGW provides no libssp, use our own implementation.
999 if (comp.getTarget().isMinGW()) {
1000 try comp.work_queue.writeItem(.{ .libssp = {} });
1001 }
1002 if (!comp.bin_file.options.link_libc) {
1003 try comp.work_queue.writeItem(.{ .zig_libc = {} });
1004 }
9801005 }
9811006 }
9821007 }
......@@ -1374,20 +1399,26 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
13741399 fatal("unable to build libcxxabi: {}", .{@errorName(err)});
13751400 };
13761401 },
1377 .libcompiler_rt => {
1378 self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
1402 .compiler_rt_lib => {
1403 self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| {
13791404 // TODO Expose this as a normal compile error rather than crashing here.
1380 fatal("unable to build compiler_rt: {}", .{@errorName(err)});
1405 fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
1406 };
1407 },
1408 .compiler_rt_obj => {
1409 self.buildOutputFromZig("compiler_rt.zig", .Obj, &self.compiler_rt_obj) catch |err| {
1410 // TODO Expose this as a normal compile error rather than crashing here.
1411 fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
13811412 };
13821413 },
13831414 .libssp => {
1384 self.buildStaticLibFromZig("ssp.zig", &self.libssp_static_lib) catch |err| {
1415 self.buildOutputFromZig("ssp.zig", .Lib, &self.libssp_static_lib) catch |err| {
13851416 // TODO Expose this as a normal compile error rather than crashing here.
13861417 fatal("unable to build libssp: {}", .{@errorName(err)});
13871418 };
13881419 },
13891420 .zig_libc => {
1390 self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
1421 self.buildOutputFromZig("c.zig", .Lib, &self.libc_static_lib) catch |err| {
13911422 // TODO Expose this as a normal compile error rather than crashing here.
13921423 fatal("unable to build zig's multitarget libc: {}", .{@errorName(err)});
13931424 };
......@@ -2551,10 +2582,16 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
25512582 }
25522583}
25532584
2554fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CRTFile) !void {
2585fn buildOutputFromZig(
2586 comp: *Compilation,
2587 src_basename: []const u8,
2588 output_mode: std.builtin.OutputMode,
2589 out: *?CRTFile,
2590) !void {
25552591 const tracy = trace(@src());
25562592 defer tracy.end();
25572593
2594 std.debug.assert(output_mode != .Exe);
25582595 const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
25592596 const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
25602597 defer comp.gpa.free(special_path);
......@@ -2571,11 +2608,11 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
25712608 };
25722609 const root_name = mem.split(src_basename, ".").next().?;
25732610 const target = comp.getTarget();
2574 const output_mode: std.builtin.OutputMode = if (target.cpu.arch.isWasm()) .Obj else .Lib;
2611 const fixed_output_mode = if (target.cpu.arch.isWasm()) .Obj else output_mode;
25752612 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
25762613 .root_name = root_name,
25772614 .target = target,
2578 .output_mode = output_mode,
2615 .output_mode = fixed_output_mode,
25792616 });
25802617 defer comp.gpa.free(bin_basename);
25812618
......@@ -2598,7 +2635,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
25982635 .target = target,
25992636 .root_name = root_name,
26002637 .root_pkg = &root_pkg,
2601 .output_mode = output_mode,
2638 .output_mode = fixed_output_mode,
26022639 .rand = comp.rand,
26032640 .libc_installation = comp.bin_file.options.libc_installation,
26042641 .emit_bin = emit_bin,
src/link.zig+11-1
......@@ -46,6 +46,7 @@ pub const Options = struct {
4646 entry_addr: ?u64 = null,
4747 stack_size_override: ?u64,
4848 image_base_override: ?u64,
49 include_compiler_rt: bool,
4950 /// Set to `true` to omit debug info.
5051 strip: bool,
5152 /// If this is true then this link code is responsible for outputting an object
......@@ -473,6 +474,11 @@ pub const File = struct {
473474 break :blk full_obj_path;
474475 } else null;
475476
477 const compiler_rt_path: ?[]const u8 = if (base.options.include_compiler_rt)
478 comp.compiler_rt_obj.?.full_object_path
479 else
480 null;
481
476482 // This function follows the same pattern as link.Elf.linkWithLLD so if you want some
477483 // insight as to what's going on here you can read that function body which is more
478484 // well-commented.
......@@ -489,6 +495,7 @@ pub const File = struct {
489495 _ = try ch.addFile(entry.key.status.success.object_path, null);
490496 }
491497 try ch.addOptionalFile(module_obj_path);
498 try ch.addOptionalFile(compiler_rt_path);
492499
493500 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
494501 _ = try ch.hit();
......@@ -518,7 +525,7 @@ pub const File = struct {
518525 var object_files = std.ArrayList([*:0]const u8).init(base.allocator);
519526 defer object_files.deinit();
520527
521 try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 1);
528 try object_files.ensureCapacity(base.options.objects.len + comp.c_object_table.items().len + 2);
522529 for (base.options.objects) |obj_path| {
523530 object_files.appendAssumeCapacity(try arena.dupeZ(u8, obj_path));
524531 }
......@@ -528,6 +535,9 @@ pub const File = struct {
528535 if (module_obj_path) |p| {
529536 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
530537 }
538 if (compiler_rt_path) |p| {
539 object_files.appendAssumeCapacity(try arena.dupeZ(u8, p));
540 }
531541
532542 const full_out_path = try directory.join(arena, &[_][]const u8{base.options.emit.?.sub_path});
533543 const full_out_path_z = try arena.dupeZ(u8, full_out_path);
src/link/Elf.zig+17-6
......@@ -1260,6 +1260,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12601260 const gc_sections = self.base.options.gc_sections orelse !is_obj;
12611261 const stack_size = self.base.options.stack_size_override orelse 16777216;
12621262 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
1263 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt) blk: {
1264 if (is_exe_or_dyn_lib) {
1265 break :blk comp.compiler_rt_static_lib.?.full_object_path;
1266 } else {
1267 break :blk comp.compiler_rt_obj.?.full_object_path;
1268 }
1269 } else null;
12631270
12641271 // Here we want to determine whether we can save time by not invoking LLD when the
12651272 // output is unchanged. None of the linker options or the object files that are being
......@@ -1289,6 +1296,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12891296 _ = try man.addFile(entry.key.status.success.object_path, null);
12901297 }
12911298 try man.addOptionalFile(module_obj_path);
1299 try man.addOptionalFile(compiler_rt_path);
1300
12921301 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
12931302 // installation sources because they are always a product of the compiler version + target information.
12941303 man.hash.add(stack_size);
......@@ -1531,12 +1540,14 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
15311540 try argv.append(p);
15321541 }
15331542
1534 // compiler-rt and libc
1535 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc) {
1536 if (!self.base.options.link_libc) {
1537 try argv.append(comp.libc_static_lib.?.full_object_path);
1538 }
1539 try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
1543 // libc
1544 if (is_exe_or_dyn_lib and !self.base.options.is_compiler_rt_or_libc and !self.base.options.link_libc) {
1545 try argv.append(comp.libc_static_lib.?.full_object_path);
1546 }
1547
1548 // compiler-rt
1549 if (compiler_rt_path) |p| {
1550 try argv.append(p);
15401551 }
15411552
15421553 // Shared libraries.
src/main.zig+8
......@@ -314,6 +314,8 @@ const usage_build_generic =
314314 \\ -fno-soname (Linux) Disable emitting a SONAME
315315 \\ -fLLD Force using LLD as the linker
316316 \\ -fno-LLD Prevent using LLD as the linker
317 \\ -fcompiler-rt Always include compiler-rt symbols in output
318 \\ -fno-compiler-rt Prevent including compiler-rt symbols in output
317319 \\ -rdynamic Add all symbols to the dynamic symbol table
318320 \\ -rpath [path] Add directory to the runtime library search path
319321 \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
......@@ -478,6 +480,7 @@ fn buildOutputType(
478480 var want_sanitize_c: ?bool = null;
479481 var want_stack_check: ?bool = null;
480482 var want_valgrind: ?bool = null;
483 var want_compiler_rt: ?bool = null;
481484 var rdynamic: bool = false;
482485 var linker_script: ?[]const u8 = null;
483486 var version_script: ?[]const u8 = null;
......@@ -794,6 +797,10 @@ fn buildOutputType(
794797 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
795798 i += 1;
796799 override_lib_dir = args[i];
800 } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
801 want_compiler_rt = true;
802 } else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
803 want_compiler_rt = false;
797804 } else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
798805 each_lib_rpath = true;
799806 } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
......@@ -1688,6 +1695,7 @@ fn buildOutputType(
16881695 .want_sanitize_c = want_sanitize_c,
16891696 .want_stack_check = want_stack_check,
16901697 .want_valgrind = want_valgrind,
1698 .want_compiler_rt = want_compiler_rt,
16911699 .use_llvm = use_llvm,
16921700 .use_lld = use_lld,
16931701 .use_clang = use_clang,