authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-02 11:05:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-03 09:52:15-07:00
logaef8bcf7763cd098201d6b4b4c3e9e447188ae43
tree9277bd3a722ca352cfad04704793e85bdb120247
parenta0e94ec576428e3b9f003c95e6538cb57f029263

std.Build.Step.Compile: fine-grained system lib search control

For each library you can specify the preferred mode and search strategy. The old way of setting global state is eliminated.

2 files changed, 70 insertions(+), 81 deletions(-)

lib/std/Build/Step/Compile.zig+63-76
...@@ -149,13 +149,6 @@ entitlements: ?[]const u8 = null,...@@ -149,13 +149,6 @@ entitlements: ?[]const u8 = null,
149/// (Darwin) Size of the pagezero segment.149/// (Darwin) Size of the pagezero segment.
150pagezero_size: ?u64 = null,150pagezero_size: ?u64 = null,
151151
152/// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`.
153/// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first`
154/// option.
155/// By default, if no option is specified, the linker assumes `paths_first` as the default
156/// search strategy.
157search_strategy: ?enum { paths_first, dylibs_first } = null,
158
159/// (Darwin) Set size of the padding between the end of load commands152/// (Darwin) Set size of the padding between the end of load commands
160/// and start of `__TEXT,__text` section.153/// and start of `__TEXT,__text` section.
161headerpad_size: ?u32 = null,154headerpad_size: ?u32 = null,
...@@ -242,7 +235,11 @@ pub const SystemLib = struct {...@@ -242,7 +235,11 @@ pub const SystemLib = struct {
242 name: []const u8,235 name: []const u8,
243 needed: bool,236 needed: bool,
244 weak: bool,237 weak: bool,
245 use_pkg_config: enum {238 use_pkg_config: UsePkgConfig,
239 preferred_link_mode: std.builtin.LinkMode,
240 search_strategy: SystemLib.SearchStrategy,
241
242 pub const UsePkgConfig = enum {
246 /// Don't use pkg-config, just pass -lfoo where foo is name.243 /// Don't use pkg-config, just pass -lfoo where foo is name.
247 no,244 no,
248 /// Try to get information on how to link the library from pkg-config.245 /// Try to get information on how to link the library from pkg-config.
...@@ -251,7 +248,9 @@ pub const SystemLib = struct {...@@ -251,7 +248,9 @@ pub const SystemLib = struct {
251 /// Try to get information on how to link the library from pkg-config.248 /// Try to get information on how to link the library from pkg-config.
252 /// If that fails, error out.249 /// If that fails, error out.
253 force,250 force,
254 },251 };
252
253 pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
255};254};
256255
257const FrameworkLinkInfo = struct {256const FrameworkLinkInfo = struct {
...@@ -718,74 +717,29 @@ pub fn defineCMacroRaw(self: *Compile, name_and_value: []const u8) void {...@@ -718,74 +717,29 @@ pub fn defineCMacroRaw(self: *Compile, name_and_value: []const u8) void {
718 self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");717 self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");
719}718}
720719
721/// This one has no integration with anything, it just puts -lname on the command line.720/// deprecated: use linkSystemLibrary2
722/// Prefer to use `linkSystemLibrary` instead.
723pub fn linkSystemLibraryName(self: *Compile, name: []const u8) void {721pub fn linkSystemLibraryName(self: *Compile, name: []const u8) void {
724 const b = self.step.owner;722 return linkSystemLibrary2(self, name, .{ .use_pkg_config = .no });
725 self.link_objects.append(.{
726 .system_lib = .{
727 .name = b.dupe(name),
728 .needed = false,
729 .weak = false,
730 .use_pkg_config = .no,
731 },
732 }) catch @panic("OOM");
733}723}
734724
735/// This one has no integration with anything, it just puts -needed-lname on the command line.725/// deprecated: use linkSystemLibrary2
736/// Prefer to use `linkSystemLibraryNeeded` instead.
737pub fn linkSystemLibraryNeededName(self: *Compile, name: []const u8) void {726pub fn linkSystemLibraryNeededName(self: *Compile, name: []const u8) void {
738 const b = self.step.owner;727 return linkSystemLibrary2(self, name, .{ .needed = true, .use_pkg_config = .no });
739 self.link_objects.append(.{
740 .system_lib = .{
741 .name = b.dupe(name),
742 .needed = true,
743 .weak = false,
744 .use_pkg_config = .no,
745 },
746 }) catch @panic("OOM");
747}728}
748729
749/// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the730/// deprecated: use linkSystemLibrary2
750/// command line. Prefer to use `linkSystemLibraryWeak` instead.
751pub fn linkSystemLibraryWeakName(self: *Compile, name: []const u8) void {731pub fn linkSystemLibraryWeakName(self: *Compile, name: []const u8) void {
752 const b = self.step.owner;732 return linkSystemLibrary2(self, name, .{ .weak = true, .use_pkg_config = .no });
753 self.link_objects.append(.{
754 .system_lib = .{
755 .name = b.dupe(name),
756 .needed = false,
757 .weak = true,
758 .use_pkg_config = .no,
759 },
760 }) catch @panic("OOM");
761}733}
762734
763/// This links against a system library, exclusively using pkg-config to find the library.735/// deprecated: use linkSystemLibrary2
764/// Prefer to use `linkSystemLibrary` instead.
765pub fn linkSystemLibraryPkgConfigOnly(self: *Compile, lib_name: []const u8) void {736pub fn linkSystemLibraryPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
766 const b = self.step.owner;737 return linkSystemLibrary2(self, lib_name, .{ .use_pkg_config = .force });
767 self.link_objects.append(.{
768 .system_lib = .{
769 .name = b.dupe(lib_name),
770 .needed = false,
771 .weak = false,
772 .use_pkg_config = .force,
773 },
774 }) catch @panic("OOM");
775}738}
776739
777/// This links against a system library, exclusively using pkg-config to find the library.740/// deprecated: use linkSystemLibrary2
778/// Prefer to use `linkSystemLibraryNeeded` instead.
779pub fn linkSystemLibraryNeededPkgConfigOnly(self: *Compile, lib_name: []const u8) void {741pub fn linkSystemLibraryNeededPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
780 const b = self.step.owner;742 return linkSystemLibrary2(self, lib_name, .{ .needed = true, .use_pkg_config = .force });
781 self.link_objects.append(.{
782 .system_lib = .{
783 .name = b.dupe(lib_name),
784 .needed = true,
785 .weak = false,
786 .use_pkg_config = .force,
787 },
788 }) catch @panic("OOM");
789}743}
790744
791/// Run pkg-config for the given library name and parse the output, returning the arguments745/// Run pkg-config for the given library name and parse the output, returning the arguments
...@@ -885,21 +839,32 @@ fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 {...@@ -885,21 +839,32 @@ fn runPkgConfig(self: *Compile, lib_name: []const u8) ![]const []const u8 {
885}839}
886840
887pub fn linkSystemLibrary(self: *Compile, name: []const u8) void {841pub fn linkSystemLibrary(self: *Compile, name: []const u8) void {
888 self.linkSystemLibraryInner(name, .{});842 self.linkSystemLibrary2(name, .{});
889}843}
890844
845/// deprecated: use linkSystemLibrary2
891pub fn linkSystemLibraryNeeded(self: *Compile, name: []const u8) void {846pub fn linkSystemLibraryNeeded(self: *Compile, name: []const u8) void {
892 self.linkSystemLibraryInner(name, .{ .needed = true });847 return linkSystemLibrary2(self, name, .{ .needed = true });
893}848}
894849
850/// deprecated: use linkSystemLibrary2
895pub fn linkSystemLibraryWeak(self: *Compile, name: []const u8) void {851pub fn linkSystemLibraryWeak(self: *Compile, name: []const u8) void {
896 self.linkSystemLibraryInner(name, .{ .weak = true });852 return linkSystemLibrary2(self, name, .{ .weak = true });
897}853}
898854
899fn linkSystemLibraryInner(self: *Compile, name: []const u8, opts: struct {855pub const LinkSystemLibraryOptions = struct {
900 needed: bool = false,856 needed: bool = false,
901 weak: bool = false,857 weak: bool = false,
902}) void {858 use_pkg_config: SystemLib.UsePkgConfig = .yes,
859 preferred_link_mode: std.builtin.LinkMode = .Dynamic,
860 search_strategy: SystemLib.SearchStrategy = .paths_first,
861};
862
863pub fn linkSystemLibrary2(
864 self: *Compile,
865 name: []const u8,
866 options: LinkSystemLibraryOptions,
867) void {
903 const b = self.step.owner;868 const b = self.step.owner;
904 if (isLibCLibrary(name)) {869 if (isLibCLibrary(name)) {
905 self.linkLibC();870 self.linkLibC();
...@@ -913,9 +878,11 @@ fn linkSystemLibraryInner(self: *Compile, name: []const u8, opts: struct {...@@ -913,9 +878,11 @@ fn linkSystemLibraryInner(self: *Compile, name: []const u8, opts: struct {
913 self.link_objects.append(.{878 self.link_objects.append(.{
914 .system_lib = .{879 .system_lib = .{
915 .name = b.dupe(name),880 .name = b.dupe(name),
916 .needed = opts.needed,881 .needed = options.needed,
917 .weak = opts.weak,882 .weak = options.weak,
918 .use_pkg_config = .yes,883 .use_pkg_config = options.use_pkg_config,
884 .preferred_link_mode = options.preferred_link_mode,
885 .search_strategy = options.search_strategy,
919 },886 },
920 }) catch @panic("OOM");887 }) catch @panic("OOM");
921}888}
...@@ -1385,6 +1352,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1385,6 +1352,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1385 try transitive_deps.add(self.link_objects.items);1352 try transitive_deps.add(self.link_objects.items);
13861353
1387 var prev_has_cflags = false;1354 var prev_has_cflags = false;
1355 var prev_search_strategy: SystemLib.SearchStrategy = .paths_first;
1356 var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
13881357
1389 for (transitive_deps.link_objects.items) |link_object| {1358 for (transitive_deps.link_objects.items) |link_object| {
1390 switch (link_object) {1359 switch (link_object) {
...@@ -1420,6 +1389,28 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1420,6 +1389,28 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1420 },1389 },
14211390
1422 .system_lib => |system_lib| {1391 .system_lib => |system_lib| {
1392 if ((system_lib.search_strategy != prev_search_strategy or
1393 system_lib.preferred_link_mode != prev_preferred_link_mode) and
1394 self.linkage != .static)
1395 {
1396 switch (system_lib.search_strategy) {
1397 .no_fallback => switch (system_lib.preferred_link_mode) {
1398 .Dynamic => try zig_args.append("-search_dylibs_only"),
1399 .Static => try zig_args.append("-search_static_only"),
1400 },
1401 .paths_first => switch (system_lib.preferred_link_mode) {
1402 .Dynamic => try zig_args.append("-search_paths_first"),
1403 .Static => try zig_args.append("-search_paths_first_static"),
1404 },
1405 .mode_first => switch (system_lib.preferred_link_mode) {
1406 .Dynamic => try zig_args.append("-search_dylibs_first"),
1407 .Static => try zig_args.append("-search_static_first"),
1408 },
1409 }
1410 prev_search_strategy = system_lib.search_strategy;
1411 prev_preferred_link_mode = system_lib.preferred_link_mode;
1412 }
1413
1423 const prefix: []const u8 = prefix: {1414 const prefix: []const u8 = prefix: {
1424 if (system_lib.needed) break :prefix "-needed-l";1415 if (system_lib.needed) break :prefix "-needed-l";
1425 if (system_lib.weak) break :prefix "-weak-l";1416 if (system_lib.weak) break :prefix "-weak-l";
...@@ -1662,10 +1653,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {...@@ -1662,10 +1653,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
1662 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{pagezero_size});1653 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{pagezero_size});
1663 try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });1654 try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
1664 }1655 }
1665 if (self.search_strategy) |strat| switch (strat) {
1666 .paths_first => try zig_args.append("-search_paths_first"),
1667 .dylibs_first => try zig_args.append("-search_dylibs_first"),
1668 };
1669 if (self.headerpad_size) |headerpad_size| {1656 if (self.headerpad_size) |headerpad_size| {
1670 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{headerpad_size});1657 const size = try std.fmt.allocPrint(b.allocator, "{x}", .{headerpad_size});
1671 try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });1658 try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
test/link/macho/search_strategy/build.zig+7-5
...@@ -17,8 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -17,8 +17,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
1717
18 {18 {
19 // -search_dylibs_first19 // -search_dylibs_first
20 const exe = createScenario(b, optimize, target, "search_dylibs_first");20 const exe = createScenario(b, optimize, target, "search_dylibs_first", .mode_first);
21 exe.search_strategy = .dylibs_first;
2221
23 const check = exe.checkObject();22 const check = exe.checkObject();
24 check.checkStart();23 check.checkStart();
...@@ -34,8 +33,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -34,8 +33,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
3433
35 {34 {
36 // -search_paths_first35 // -search_paths_first
37 const exe = createScenario(b, optimize, target, "search_paths_first");36 const exe = createScenario(b, optimize, target, "search_paths_first", .paths_first);
38 exe.search_strategy = .paths_first;
3937
40 const run = b.addRunArtifact(exe);38 const run = b.addRunArtifact(exe);
41 run.skip_foreign_checks = true;39 run.skip_foreign_checks = true;
...@@ -49,6 +47,7 @@ fn createScenario(...@@ -49,6 +47,7 @@ fn createScenario(
49 optimize: std.builtin.OptimizeMode,47 optimize: std.builtin.OptimizeMode,
50 target: std.zig.CrossTarget,48 target: std.zig.CrossTarget,
51 name: []const u8,49 name: []const u8,
50 search_strategy: std.Build.Step.Compile.SystemLib.SearchStrategy,
52) *std.Build.Step.Compile {51) *std.Build.Step.Compile {
53 const static = b.addStaticLibrary(.{52 const static = b.addStaticLibrary(.{
54 .name = name,53 .name = name,
...@@ -73,7 +72,10 @@ fn createScenario(...@@ -73,7 +72,10 @@ fn createScenario(
73 .target = target,72 .target = target,
74 });73 });
75 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });74 exe.addCSourceFile(.{ .file = .{ .path = "main.c" }, .flags = &.{} });
76 exe.linkSystemLibraryName(name);75 exe.linkSystemLibrary2(name, .{
76 .use_pkg_config = .no,
77 .search_strategy = search_strategy,
78 });
77 exe.linkLibC();79 exe.linkLibC();
78 exe.addLibraryPath(static.getEmittedBinDirectory());80 exe.addLibraryPath(static.getEmittedBinDirectory());
79 exe.addLibraryPath(dylib.getEmittedBinDirectory());81 exe.addLibraryPath(dylib.getEmittedBinDirectory());