authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-20 16:58:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-20 16:58:31-07:00
log7ea3937c5a6f63557db99c8a8f7b3f6d3de8c38b
treec972e12f5eeb56d9865089af79fa8edff8dff93e
parent74b72a766de96c7c70fc8a02d3e2ee3cd353f225

std.build.LibExeObjStep: better handle transitive deps

* no longer repeat -lc on the linker line redundantly * when using linkLibrary() with a static library, it will now also put the static library's static library dependencies on the linker line, recursively. * refactor out a common pattern to an addFlag function

1 files changed, 122 insertions(+), 179 deletions(-)

lib/std/build/LibExeObjStep.zig+122-179
......@@ -595,31 +595,11 @@ pub fn producesPdbFile(self: *LibExeObjStep) bool {
595595}
596596
597597pub fn linkLibC(self: *LibExeObjStep) void {
598 if (!self.is_linking_libc) {
599 self.is_linking_libc = true;
600 self.link_objects.append(.{
601 .system_lib = .{
602 .name = "c",
603 .needed = false,
604 .weak = false,
605 .use_pkg_config = .no,
606 },
607 }) catch unreachable;
608 }
598 self.is_linking_libc = true;
609599}
610600
611601pub fn linkLibCpp(self: *LibExeObjStep) void {
612 if (!self.is_linking_libcpp) {
613 self.is_linking_libcpp = true;
614 self.link_objects.append(.{
615 .system_lib = .{
616 .name = "c++",
617 .needed = false,
618 .weak = false,
619 .use_pkg_config = .no,
620 },
621 }) catch unreachable;
622 }
602 self.is_linking_libcpp = true;
623603}
624604
625605/// If the value is omitted, it is set to 1.
......@@ -762,7 +742,7 @@ pub fn runPkgConfig(self: *LibExeObjStep, lib_name: []const u8) ![]const []const
762742 else => return err,
763743 };
764744
765 var zig_args = std.ArrayList([]const u8).init(self.builder.allocator);
745 var zig_args = ArrayList([]const u8).init(self.builder.allocator);
766746 defer zig_args.deinit();
767747
768748 var it = mem.tokenize(u8, stdout, " \r\n\t");
......@@ -1105,21 +1085,8 @@ fn make(step: *Step) !void {
11051085 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-freference-trace={d}", .{some}));
11061086 }
11071087
1108 if (self.use_llvm) |use_llvm| {
1109 if (use_llvm) {
1110 try zig_args.append("-fLLVM");
1111 } else {
1112 try zig_args.append("-fno-LLVM");
1113 }
1114 }
1115
1116 if (self.use_lld) |use_lld| {
1117 if (use_lld) {
1118 try zig_args.append("-fLLD");
1119 } else {
1120 try zig_args.append("-fno-LLD");
1121 }
1122 }
1088 try addFlag(&zig_args, "LLVM", self.use_llvm);
1089 try addFlag(&zig_args, "LLD", self.use_lld);
11231090
11241091 if (self.target.ofmt) |ofmt| {
11251092 try zig_args.append(try std.fmt.allocPrint(builder.allocator, "-ofmt={s}", .{@tagName(ofmt)}));
......@@ -1137,40 +1104,24 @@ fn make(step: *Step) !void {
11371104
11381105 if (self.root_src) |root_src| try zig_args.append(root_src.getPath(builder));
11391106
1140 var prev_has_extra_flags = false;
1141
1142 // Resolve transitive dependencies
1143 {
1144 var transitive_dependencies = std.ArrayList(LinkObject).init(builder.allocator);
1145 defer transitive_dependencies.deinit();
1146
1147 for (self.link_objects.items) |link_object| {
1148 switch (link_object) {
1149 .other_step => |other| {
1150 // Inherit dependency on system libraries
1151 for (other.link_objects.items) |other_link_object| {
1152 switch (other_link_object) {
1153 .system_lib => try transitive_dependencies.append(other_link_object),
1154 else => continue,
1155 }
1156 }
1107 // We will add link objects from transitive dependencies, but we want to keep
1108 // all link objects in the same order provided.
1109 // This array is used to keep self.link_objects immutable.
1110 var transitive_deps: TransitiveDeps = .{
1111 .link_objects = ArrayList(LinkObject).init(builder.allocator),
1112 .seen_system_libs = StringHashMap(void).init(builder.allocator),
1113 .seen_steps = std.AutoHashMap(*const Step, void).init(builder.allocator),
1114 .is_linking_libcpp = self.is_linking_libcpp,
1115 .is_linking_libc = self.is_linking_libc,
1116 .frameworks = &self.frameworks,
1117 };
11571118
1158 // Inherit dependencies on darwin frameworks
1159 if (!other.isDynamicLibrary()) {
1160 var it = other.frameworks.iterator();
1161 while (it.next()) |framework| {
1162 self.frameworks.put(framework.key_ptr.*, framework.value_ptr.*) catch unreachable;
1163 }
1164 }
1165 },
1166 else => continue,
1167 }
1168 }
1119 try transitive_deps.seen_steps.put(&self.step, {});
1120 try transitive_deps.add(self.link_objects.items);
11691121
1170 try self.link_objects.appendSlice(transitive_dependencies.items);
1171 }
1122 var prev_has_extra_flags = false;
11721123
1173 for (self.link_objects.items) |link_object| {
1124 for (transitive_deps.link_objects.items) |link_object| {
11741125 switch (link_object) {
11751126 .static_path => |static_path| try zig_args.append(static_path.getPath(builder)),
11761127
......@@ -1185,10 +1136,12 @@ fn make(step: *Step) !void {
11851136 const full_path_lib = other.getOutputLibSource().getPath(builder);
11861137 try zig_args.append(full_path_lib);
11871138
1188 if (other.linkage != null and other.linkage.? == .dynamic and !self.target.isWindows()) {
1189 if (fs.path.dirname(full_path_lib)) |dirname| {
1190 try zig_args.append("-rpath");
1191 try zig_args.append(dirname);
1139 if (other.linkage) |linkage| {
1140 if (linkage == .dynamic and !self.target.isWindows()) {
1141 if (fs.path.dirname(full_path_lib)) |dirname| {
1142 try zig_args.append("-rpath");
1143 try zig_args.append(dirname);
1144 }
11921145 }
11931146 }
11941147 },
......@@ -1282,6 +1235,14 @@ fn make(step: *Step) !void {
12821235 }
12831236 }
12841237
1238 if (transitive_deps.is_linking_libcpp) {
1239 try zig_args.append("-lc++");
1240 }
1241
1242 if (transitive_deps.is_linking_libc) {
1243 try zig_args.append("-lc");
1244 }
1245
12851246 if (self.image_base) |image_base| {
12861247 try zig_args.append("--image-base");
12871248 try zig_args.append(builder.fmt("0x{x}", .{image_base}));
......@@ -1332,21 +1293,8 @@ fn make(step: *Step) !void {
13321293
13331294 if (self.emit_h) try zig_args.append("-femit-h");
13341295
1335 if (self.strip) |strip| {
1336 if (strip) {
1337 try zig_args.append("-fstrip");
1338 } else {
1339 try zig_args.append("-fno-strip");
1340 }
1341 }
1342
1343 if (self.unwind_tables) |unwind_tables| {
1344 if (unwind_tables) {
1345 try zig_args.append("-funwind-tables");
1346 } else {
1347 try zig_args.append("-fno-unwind-tables");
1348 }
1349 }
1296 try addFlag(&zig_args, "strip", self.strip);
1297 try addFlag(&zig_args, "unwind-tables", self.unwind_tables);
13501298
13511299 switch (self.compress_debug_sections) {
13521300 .none => {},
......@@ -1454,51 +1402,16 @@ fn make(step: *Step) !void {
14541402 try zig_args.append("-dead_strip_dylibs");
14551403 }
14561404
1457 if (self.bundle_compiler_rt) |x| {
1458 if (x) {
1459 try zig_args.append("-fcompiler-rt");
1460 } else {
1461 try zig_args.append("-fno-compiler-rt");
1462 }
1463 }
1464 if (self.single_threaded) |single_threaded| {
1465 if (single_threaded) {
1466 try zig_args.append("-fsingle-threaded");
1467 } else {
1468 try zig_args.append("-fno-single-threaded");
1469 }
1470 }
1405 try addFlag(&zig_args, "compiler-rt", self.bundle_compiler_rt);
1406 try addFlag(&zig_args, "single-threaded", self.single_threaded);
14711407 if (self.disable_stack_probing) {
14721408 try zig_args.append("-fno-stack-check");
14731409 }
1474 if (self.stack_protector) |stack_protector| {
1475 if (stack_protector) {
1476 try zig_args.append("-fstack-protector");
1477 } else {
1478 try zig_args.append("-fno-stack-protector");
1479 }
1480 }
1481 if (self.red_zone) |red_zone| {
1482 if (red_zone) {
1483 try zig_args.append("-mred-zone");
1484 } else {
1485 try zig_args.append("-mno-red-zone");
1486 }
1487 }
1488 if (self.omit_frame_pointer) |omit_frame_pointer| {
1489 if (omit_frame_pointer) {
1490 try zig_args.append("-fomit-frame-pointer");
1491 } else {
1492 try zig_args.append("-fno-omit-frame-pointer");
1493 }
1494 }
1495 if (self.dll_export_fns) |dll_export_fns| {
1496 if (dll_export_fns) {
1497 try zig_args.append("-fdll-export-fns");
1498 } else {
1499 try zig_args.append("-fno-dll-export-fns");
1500 }
1501 }
1410 try addFlag(&zig_args, "stack-protector", self.stack_protector);
1411 try addFlag(&zig_args, "red-zone", self.red_zone);
1412 try addFlag(&zig_args, "omit-frame-pointer", self.omit_frame_pointer);
1413 try addFlag(&zig_args, "dll-export-fns", self.dll_export_fns);
1414
15021415 if (self.disable_sanitize_c) {
15031416 try zig_args.append("-fno-sanitize-c");
15041417 }
......@@ -1559,7 +1472,7 @@ fn make(step: *Step) !void {
15591472 try zig_args.append("-mcpu");
15601473 try zig_args.append(cross.cpu.model.name);
15611474 } else {
1562 var mcpu_buffer = std.ArrayList(u8).init(builder.allocator);
1475 var mcpu_buffer = ArrayList(u8).init(builder.allocator);
15631476
15641477 try mcpu_buffer.writer().print("-mcpu={s}", .{cross.cpu.model.name});
15651478
......@@ -1604,11 +1517,11 @@ fn make(step: *Step) !void {
16041517 }
16051518 }
16061519 } else {
1607 const need_cross_glibc = self.target.isGnuLibC() and self.is_linking_libc;
1520 const need_cross_glibc = self.target.isGnuLibC() and transitive_deps.is_linking_libc;
16081521
16091522 switch (builder.host.getExternalExecutor(self.target_info, .{
16101523 .qemu_fixes_dl = need_cross_glibc and builder.glibc_runtimes_dir != null,
1611 .link_libc = self.is_linking_libc,
1524 .link_libc = transitive_deps.is_linking_libc,
16121525 })) {
16131526 .native => {},
16141527 .bad_dl, .bad_os_or_cpu => {
......@@ -1803,29 +1716,9 @@ fn make(step: *Step) !void {
18031716 }));
18041717 }
18051718
1806 if (self.valgrind_support) |valgrind_support| {
1807 if (valgrind_support) {
1808 try zig_args.append("-fvalgrind");
1809 } else {
1810 try zig_args.append("-fno-valgrind");
1811 }
1812 }
1813
1814 if (self.each_lib_rpath) |each_lib_rpath| {
1815 if (each_lib_rpath) {
1816 try zig_args.append("-feach-lib-rpath");
1817 } else {
1818 try zig_args.append("-fno-each-lib-rpath");
1819 }
1820 }
1821
1822 if (self.build_id) |build_id| {
1823 if (build_id) {
1824 try zig_args.append("-fbuild-id");
1825 } else {
1826 try zig_args.append("-fno-build-id");
1827 }
1828 }
1719 try addFlag(&zig_args, "valgrind", self.valgrind_support);
1720 try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
1721 try addFlag(&zig_args, "build-id", self.build_id);
18291722
18301723 if (self.override_lib_dir) |dir| {
18311724 try zig_args.append("--zig-lib-dir");
......@@ -1840,29 +1733,9 @@ fn make(step: *Step) !void {
18401733 try zig_args.append(builder.pathFromRoot(dir));
18411734 }
18421735
1843 if (self.force_pic) |pic| {
1844 if (pic) {
1845 try zig_args.append("-fPIC");
1846 } else {
1847 try zig_args.append("-fno-PIC");
1848 }
1849 }
1850
1851 if (self.pie) |pie| {
1852 if (pie) {
1853 try zig_args.append("-fPIE");
1854 } else {
1855 try zig_args.append("-fno-PIE");
1856 }
1857 }
1858
1859 if (self.want_lto) |lto| {
1860 if (lto) {
1861 try zig_args.append("-flto");
1862 } else {
1863 try zig_args.append("-fno-lto");
1864 }
1865 }
1736 try addFlag(&zig_args, "PIC", self.force_pic);
1737 try addFlag(&zig_args, "PIE", self.pie);
1738 try addFlag(&zig_args, "lto", self.want_lto);
18661739
18671740 if (self.subsystem) |subsystem| {
18681741 try zig_args.append("--subsystem");
......@@ -2129,3 +2002,73 @@ test "addPackage" {
21292002 const dupe = exe.packages.items[0];
21302003 try std.testing.expectEqualStrings(pkg_top.name, dupe.name);
21312004}
2005
2006fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void {
2007 const cond = opt orelse return;
2008 try args.ensureUnusedCapacity(1);
2009 if (cond) {
2010 args.appendAssumeCapacity("-f" ++ name);
2011 } else {
2012 args.appendAssumeCapacity("-fno-" ++ name);
2013 }
2014}
2015
2016const TransitiveDeps = struct {
2017 link_objects: ArrayList(LinkObject),
2018 seen_system_libs: StringHashMap(void),
2019 seen_steps: std.AutoHashMap(*const Step, void),
2020 is_linking_libcpp: bool,
2021 is_linking_libc: bool,
2022 frameworks: *StringHashMap(FrameworkLinkInfo),
2023
2024 fn add(td: *TransitiveDeps, link_objects: []const LinkObject) !void {
2025 try td.link_objects.ensureUnusedCapacity(link_objects.len);
2026
2027 for (link_objects) |link_object| {
2028 try td.link_objects.append(link_object);
2029 switch (link_object) {
2030 .other_step => |other| try addInner(td, other, other.isDynamicLibrary()),
2031 else => {},
2032 }
2033 }
2034 }
2035
2036 fn addInner(td: *TransitiveDeps, other: *LibExeObjStep, dyn: bool) !void {
2037 // Inherit dependency on libc and libc++
2038 td.is_linking_libcpp = td.is_linking_libcpp or other.is_linking_libcpp;
2039 td.is_linking_libc = td.is_linking_libc or other.is_linking_libc;
2040
2041 // Inherit dependencies on darwin frameworks
2042 if (!dyn) {
2043 var it = other.frameworks.iterator();
2044 while (it.next()) |framework| {
2045 try td.frameworks.put(framework.key_ptr.*, framework.value_ptr.*);
2046 }
2047 }
2048
2049 // Inherit dependencies on system libraries and static libraries.
2050 for (other.link_objects.items) |other_link_object| {
2051 switch (other_link_object) {
2052 .system_lib => |system_lib| {
2053 if ((try td.seen_system_libs.fetchPut(system_lib.name, {})) != null)
2054 continue;
2055
2056 if (dyn)
2057 continue;
2058
2059 try td.link_objects.append(other_link_object);
2060 },
2061 .other_step => |inner_other| {
2062 if ((try td.seen_steps.fetchPut(&inner_other.step, {})) != null)
2063 continue;
2064
2065 if (!dyn)
2066 try td.link_objects.append(other_link_object);
2067
2068 try addInner(td, inner_other, dyn or inner_other.isDynamicLibrary());
2069 },
2070 else => continue,
2071 }
2072 }
2073 }
2074};