authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-12-03 16:15:27-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:18-07:00
log04480f72d8993196052375c0f0aca9d33f475fe7
treeb742c23c5c60b57676d3d56bc09db49497324a9d
parent0ee8fbb15dd32a2bb91696e4765926e9170d2a23

fix linker test regressions

Caused by problems with transitive dependencies

4 files changed, 81 insertions(+), 33 deletions(-)

lib/std/Build/Module.zig+7-2
......@@ -229,7 +229,7 @@ pub fn init(m: *Module, owner: *std.Build, options: CreateOptions, compile: ?*St
229229 }
230230
231231 // This logic accesses `depending_steps` which was just modified above.
232 var it = m.iterateDependencies(null);
232 var it = m.iterateDependencies(null, false);
233233 while (it.next()) |item| addShallowDependencies(m, item.module);
234234}
235235
......@@ -244,7 +244,7 @@ pub fn addImport(m: *Module, name: []const u8, module: *Module) void {
244244 const b = m.owner;
245245 m.import_table.put(b.allocator, b.dupe(name), module) catch @panic("OOM");
246246
247 var it = module.iterateDependencies(null);
247 var it = module.iterateDependencies(null, false);
248248 while (it.next()) |item| addShallowDependencies(m, item.module);
249249}
250250
......@@ -319,6 +319,7 @@ pub const DependencyIterator = struct {
319319 allocator: std.mem.Allocator,
320320 index: usize,
321321 set: std.AutoArrayHashMapUnmanaged(Key, []const u8),
322 chase_dyn_libs: bool,
322323
323324 pub const Key = struct {
324325 /// The compilation that contains the `Module`. Note that a `Module` might be
......@@ -361,6 +362,8 @@ pub const DependencyIterator = struct {
361362 if (key.compile != null) {
362363 for (module.link_objects.items) |link_object| switch (link_object) {
363364 .other_step => |compile| {
365 if (!it.chase_dyn_libs and compile.isDynamicLibrary()) continue;
366
364367 it.set.put(it.allocator, .{
365368 .module = &compile.root_module,
366369 .compile = compile,
......@@ -381,11 +384,13 @@ pub const DependencyIterator = struct {
381384pub fn iterateDependencies(
382385 m: *Module,
383386 chase_steps: ?*Step.Compile,
387 chase_dyn_libs: bool,
384388) DependencyIterator {
385389 var it: DependencyIterator = .{
386390 .allocator = m.owner.allocator,
387391 .index = 0,
388392 .set = .{},
393 .chase_dyn_libs = chase_dyn_libs,
389394 };
390395 it.set.ensureUnusedCapacity(m.owner.allocator, m.import_table.count() + 1) catch @panic("OOM");
391396 it.set.putAssumeCapacity(.{
lib/std/Build/Step/Compile.zig+63-24
......@@ -488,11 +488,12 @@ pub fn forceUndefinedSymbol(self: *Compile, symbol_name: []const u8) void {
488488}
489489
490490/// Returns whether the library, executable, or object depends on a particular system library.
491/// Includes transitive dependencies.
491492pub fn dependsOnSystemLibrary(self: *const Compile, name: []const u8) bool {
492493 var is_linking_libc = false;
493494 var is_linking_libcpp = false;
494495
495 var it = self.root_module.iterateDependencies(self);
496 var it = self.root_module.iterateDependencies(self, true);
496497 while (it.next()) |module| {
497498 for (module.link_objects.items) |link_object| {
498499 switch (link_object) {
......@@ -841,7 +842,7 @@ fn appendModuleArgs(cs: *Compile, zig_args: *ArrayList([]const u8)) !void {
841842 var names = std.StringHashMap(void).init(b.allocator);
842843
843844 {
844 var it = cs.root_module.iterateDependencies(null);
845 var it = cs.root_module.iterateDependencies(null, false);
845846 _ = it.next(); // Skip over the root module.
846847 while (it.next()) |item| {
847848 // While we're traversing the root dependencies, let's make sure that no module names
......@@ -1000,33 +1001,51 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10001001
10011002 try self.root_module.appendZigProcessFlags(&zig_args, step);
10021003
1003 var it = self.root_module.iterateDependencies(self);
1004 {
1005 // Fully recursive iteration including dynamic libraries to detect
1006 // libc and libc++ linkage.
1007 var it = self.root_module.iterateDependencies(self, true);
1008 while (it.next()) |key| {
1009 if (key.module.link_libc == true) self.is_linking_libc = true;
1010 if (key.module.link_libcpp == true) self.is_linking_libcpp = true;
1011 }
1012 }
1013
1014 // For this loop, don't chase dynamic libraries because their link
1015 // objects are already linked.
1016 var it = self.root_module.iterateDependencies(self, false);
1017
10041018 while (it.next()) |key| {
10051019 const module = key.module;
10061020 const compile = key.compile.?;
1007 const dyn = compile.isDynamicLibrary();
10081021
1009 // Inherit dependency on libc and libc++.
1010 if (module.link_libc == true) self.is_linking_libc = true;
1011 if (module.link_libcpp == true) self.is_linking_libcpp = true;
1022 // While walking transitive dependencies, if a given link object is
1023 // already included in a library, it should not redundantly be
1024 // placed on the linker line of the dependee.
1025 const my_responsibility = compile == self;
1026 const already_linked = !my_responsibility and compile.isDynamicLibrary();
10121027
10131028 // Inherit dependencies on darwin frameworks.
1014 if (!dyn) {
1029 if (!already_linked) {
10151030 for (module.frameworks.keys(), module.frameworks.values()) |name, info| {
10161031 try frameworks.put(b.allocator, name, info);
10171032 }
10181033 }
10191034
10201035 // Inherit dependencies on system libraries and static libraries.
1021 total_linker_objects += module.link_objects.items.len;
10221036 for (module.link_objects.items) |link_object| {
10231037 switch (link_object) {
1024 .static_path => |static_path| try zig_args.append(static_path.getPath(b)),
1038 .static_path => |static_path| {
1039 if (my_responsibility) {
1040 try zig_args.append(static_path.getPath(b));
1041 total_linker_objects += 1;
1042 }
1043 },
10251044 .system_lib => |system_lib| {
10261045 if ((try seen_system_libs.fetchPut(b.allocator, system_lib.name, {})) != null)
10271046 continue;
10281047
1029 if (dyn)
1048 if (already_linked)
10301049 continue;
10311050
10321051 if ((system_lib.search_strategy != prev_search_strategy or
......@@ -1088,29 +1107,36 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10881107 }
10891108 },
10901109 .other_step => |other| {
1091 const included_in_lib = (compile.kind == .lib and other.kind == .obj);
1092 if (dyn or included_in_lib)
1093 continue;
1094
10951110 switch (other.kind) {
10961111 .exe => return step.fail("cannot link with an executable build artifact", .{}),
10971112 .@"test" => return step.fail("cannot link with a test", .{}),
10981113 .obj => {
1099 try zig_args.append(other.getEmittedBin().getPath(b));
1114 const included_in_lib = !my_responsibility and
1115 compile.kind == .lib and other.kind == .obj;
1116 if (!already_linked and !included_in_lib) {
1117 try zig_args.append(other.getEmittedBin().getPath(b));
1118 total_linker_objects += 1;
1119 }
11001120 },
11011121 .lib => l: {
1102 if (self.isStaticLibrary() and other.isStaticLibrary()) {
1122 const other_produces_implib = other.producesImplib();
1123 const other_is_static = other_produces_implib or other.isStaticLibrary();
1124
1125 if (self.isStaticLibrary() and other_is_static) {
11031126 // Avoid putting a static library inside a static library.
11041127 break :l;
11051128 }
11061129
1107 // For DLLs, we gotta link against the implib. For
1108 // everything else, we directly link against the library file.
1109 const full_path_lib = if (other.producesImplib())
1130 // For DLLs, we must link against the implib.
1131 // For everything else, we directly link
1132 // against the library file.
1133 const full_path_lib = if (other_produces_implib)
11101134 other.getGeneratedFilePath("generated_implib", &self.step)
11111135 else
11121136 other.getGeneratedFilePath("generated_bin", &self.step);
1137
11131138 try zig_args.append(full_path_lib);
1139 total_linker_objects += 1;
11141140
11151141 if (other.linkage == Linkage.dynamic and
11161142 self.rootModuleTarget().os.tag != .windows)
......@@ -1123,16 +1149,21 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11231149 },
11241150 }
11251151 },
1126 .assembly_file => |asm_file| {
1152 .assembly_file => |asm_file| l: {
1153 if (!my_responsibility) break :l;
1154
11271155 if (prev_has_cflags) {
11281156 try zig_args.append("-cflags");
11291157 try zig_args.append("--");
11301158 prev_has_cflags = false;
11311159 }
11321160 try zig_args.append(asm_file.getPath(b));
1161 total_linker_objects += 1;
11331162 },
11341163
1135 .c_source_file => |c_source_file| {
1164 .c_source_file => |c_source_file| l: {
1165 if (!my_responsibility) break :l;
1166
11361167 if (c_source_file.flags.len == 0) {
11371168 if (prev_has_cflags) {
11381169 try zig_args.append("-cflags");
......@@ -1148,9 +1179,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11481179 prev_has_cflags = true;
11491180 }
11501181 try zig_args.append(c_source_file.file.getPath(b));
1182 total_linker_objects += 1;
11511183 },
11521184
1153 .c_source_files => |c_source_files| {
1185 .c_source_files => |c_source_files| l: {
1186 if (!my_responsibility) break :l;
1187
11541188 if (c_source_files.flags.len == 0) {
11551189 if (prev_has_cflags) {
11561190 try zig_args.append("-cflags");
......@@ -1165,6 +1199,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11651199 try zig_args.append("--");
11661200 prev_has_cflags = true;
11671201 }
1202
11681203 if (c_source_files.dependency) |dep| {
11691204 for (c_source_files.files) |file| {
11701205 try zig_args.append(dep.builder.pathFromRoot(file));
......@@ -1174,9 +1209,12 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11741209 try zig_args.append(b.pathFromRoot(file));
11751210 }
11761211 }
1212 total_linker_objects += c_source_files.files.len;
11771213 },
11781214
1179 .win32_resource_file => |rc_source_file| {
1215 .win32_resource_file => |rc_source_file| l: {
1216 if (!my_responsibility) break :l;
1217
11801218 if (rc_source_file.flags.len == 0) {
11811219 if (prev_has_rcflags) {
11821220 try zig_args.append("-rcflags");
......@@ -1192,6 +1230,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
11921230 prev_has_rcflags = true;
11931231 }
11941232 try zig_args.append(rc_source_file.file.getPath(b));
1233 total_linker_objects += 1;
11951234 },
11961235 }
11971236 }
lib/std/Build/Step/Run.zig+1-1
......@@ -1291,7 +1291,7 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult {
12911291
12921292fn addPathForDynLibs(self: *Run, artifact: *Step.Compile) void {
12931293 const b = self.step.owner;
1294 var it = artifact.root_module.iterateDependencies(artifact);
1294 var it = artifact.root_module.iterateDependencies(artifact, true);
12951295 while (it.next()) |item| {
12961296 const other = item.compile.?;
12971297 if (item.module == &other.root_module) {
test/link/elf.zig+10-6
......@@ -1317,8 +1317,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
13171317fn testIFuncDso(b: *Build, opts: Options) *Step {
13181318 const test_step = addTestStep(b, "ifunc-dso", opts);
13191319
1320 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
1321 addCSourceBytes(dso,
1320 const dso = addSharedLibrary(b, opts, .{
1321 .name = "a",
1322 .c_source_bytes =
13221323 \\#include<stdio.h>
13231324 \\__attribute__((ifunc("resolve_foobar")))
13241325 \\void foobar(void);
......@@ -1329,16 +1330,19 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
13291330 \\static Func *resolve_foobar(void) {
13301331 \\ return real_foobar;
13311332 \\}
1332 , &.{});
1333 ,
1334 });
13331335 dso.linkLibC();
13341336
1335 const exe = addExecutable(b, opts, .{ .name = "main" });
1336 addCSourceBytes(exe,
1337 const exe = addExecutable(b, opts, .{
1338 .name = "main",
1339 .c_source_bytes =
13371340 \\void foobar(void);
13381341 \\int main() {
13391342 \\ foobar();
13401343 \\}
1341 , &.{});
1344 ,
1345 });
13421346 exe.linkLibrary(dso);
13431347
13441348 const run = addRunArtifact(exe);