authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-08-03 09:53:18-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-08-03 09:53:18-07:00
logc4e62be62e8d8a006cc9d7861232f511c5a05385
tree2e28a575a3eef3bbf80ddd7d8f27ab607d720d85
parentf887b0251822f75dc4a3e24ca5337cb681c1eb1f
parentd0fd67cffe664ff70d9a70dd4d2d28aba5a378e8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16058 from ziglang/frontend-lib-paths

compiler: resolve library paths in the frontend

21 files changed, 914 insertions(+), 717 deletions(-)

build.zig+3-4
...@@ -204,10 +204,9 @@ pub fn build(b: *std.Build) !void {...@@ -204,10 +204,9 @@ pub fn build(b: *std.Build) !void {
204 );204 );
205205
206 if (!no_bin) {206 if (!no_bin) {
207 const install_exe = b.addInstallArtifact(exe, .{});207 const install_exe = b.addInstallArtifact(exe, .{
208 if (flat) {208 .dest_dir = if (flat) .{ .override = .prefix } else .default,
209 install_exe.dest_dir = .prefix;209 });
210 }
211 b.getInstallStep().dependOn(&install_exe.step);210 b.getInstallStep().dependOn(&install_exe.step);
212 }211 }
213212
ci/aarch64-linux-debug.sh+1-1
...@@ -72,7 +72,7 @@ stage3-debug/bin/zig build test docs \...@@ -72,7 +72,7 @@ stage3-debug/bin/zig build test docs \
7272
73# Look for HTML errors.73# Look for HTML errors.
74# TODO: move this to a build.zig flag (-Denable-tidy)74# TODO: move this to a build.zig flag (-Denable-tidy)
75tidy --drop-empty-elements no -qe "zig-out/doc/langref.html"75tidy --drop-empty-elements no -qe "../zig-out/doc/langref.html"
7676
77# Ensure that updating the wasm binary from this commit will result in a viable build.77# Ensure that updating the wasm binary from this commit will result in a viable build.
78stage3-debug/bin/zig build update-zig178stage3-debug/bin/zig build update-zig1
ci/aarch64-linux-release.sh+1-1
...@@ -72,7 +72,7 @@ stage3-release/bin/zig build test docs \...@@ -72,7 +72,7 @@ stage3-release/bin/zig build test docs \
7272
73# Look for HTML errors.73# Look for HTML errors.
74# TODO: move this to a build.zig flag (-Denable-tidy)74# TODO: move this to a build.zig flag (-Denable-tidy)
75tidy --drop-empty-elements no -qe "zig-out/doc/langref.html"75tidy --drop-empty-elements no -qe "../zig-out/doc/langref.html"
7676
77# Ensure that updating the wasm binary from this commit will result in a viable build.77# Ensure that updating the wasm binary from this commit will result in a viable build.
78stage3-release/bin/zig build update-zig178stage3-release/bin/zig build update-zig1
ci/x86_64-linux-debug.sh+1-1
...@@ -72,7 +72,7 @@ stage3-debug/bin/zig build test docs \...@@ -72,7 +72,7 @@ stage3-debug/bin/zig build test docs \
7272
73# Look for HTML errors.73# Look for HTML errors.
74# TODO: move this to a build.zig flag (-Denable-tidy)74# TODO: move this to a build.zig flag (-Denable-tidy)
75tidy --drop-empty-elements no -qe "zig-out/doc/langref.html"75tidy --drop-empty-elements no -qe "../zig-out/doc/langref.html"
7676
77# Ensure that updating the wasm binary from this commit will result in a viable build.77# Ensure that updating the wasm binary from this commit will result in a viable build.
78stage3-debug/bin/zig build update-zig178stage3-debug/bin/zig build update-zig1
ci/x86_64-linux-release.sh+1-1
...@@ -73,7 +73,7 @@ stage3-release/bin/zig build test docs \...@@ -73,7 +73,7 @@ stage3-release/bin/zig build test docs \
7373
74# Look for HTML errors.74# Look for HTML errors.
75# TODO: move this to a build.zig flag (-Denable-tidy)75# TODO: move this to a build.zig flag (-Denable-tidy)
76tidy --drop-empty-elements no -qe "zig-out/doc/langref.html"76tidy --drop-empty-elements no -qe "../zig-out/doc/langref.html"
7777
78# Ensure that stage3 and stage4 are byte-for-byte identical.78# Ensure that stage3 and stage4 are byte-for-byte identical.
79stage3-release/bin/zig build \79stage3-release/bin/zig build \
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 });
lib/std/zig/system/NativePaths.zig+32-74
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const ArrayList = std.ArrayList;
4const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
5const process = std.process;4const process = std.process;
6const mem = std.mem;5const mem = std.mem;
...@@ -8,28 +7,18 @@ const mem = std.mem;...@@ -8,28 +7,18 @@ const mem = std.mem;
8const NativePaths = @This();7const NativePaths = @This();
9const NativeTargetInfo = std.zig.system.NativeTargetInfo;8const NativeTargetInfo = std.zig.system.NativeTargetInfo;
109
11include_dirs: ArrayList([:0]u8),10arena: Allocator,
12lib_dirs: ArrayList([:0]u8),11include_dirs: std.ArrayListUnmanaged([]const u8) = .{},
13framework_dirs: ArrayList([:0]u8),12lib_dirs: std.ArrayListUnmanaged([]const u8) = .{},
14rpaths: ArrayList([:0]u8),13framework_dirs: std.ArrayListUnmanaged([]const u8) = .{},
15warnings: ArrayList([:0]u8),14rpaths: std.ArrayListUnmanaged([]const u8) = .{},
15warnings: std.ArrayListUnmanaged([]const u8) = .{},
1616
17pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths {17pub fn detect(arena: Allocator, native_info: NativeTargetInfo) !NativePaths {
18 const native_target = native_info.target;18 const native_target = native_info.target;
1919 var self: NativePaths = .{ .arena = arena };
20 var self: NativePaths = .{
21 .include_dirs = ArrayList([:0]u8).init(allocator),
22 .lib_dirs = ArrayList([:0]u8).init(allocator),
23 .framework_dirs = ArrayList([:0]u8).init(allocator),
24 .rpaths = ArrayList([:0]u8).init(allocator),
25 .warnings = ArrayList([:0]u8).init(allocator),
26 };
27 errdefer self.deinit();
28
29 var is_nix = false;20 var is_nix = false;
30 if (process.getEnvVarOwned(allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {21 if (process.getEnvVarOwned(arena, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
31 defer allocator.free(nix_cflags_compile);
32
33 is_nix = true;22 is_nix = true;
34 var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' ');23 var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' ');
35 while (true) {24 while (true) {
...@@ -58,9 +47,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths...@@ -58,9 +47,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
58 error.EnvironmentVariableNotFound => {},47 error.EnvironmentVariableNotFound => {},
59 error.OutOfMemory => |e| return e,48 error.OutOfMemory => |e| return e,
60 }49 }
61 if (process.getEnvVarOwned(allocator, "NIX_LDFLAGS")) |nix_ldflags| {50 if (process.getEnvVarOwned(arena, "NIX_LDFLAGS")) |nix_ldflags| {
62 defer allocator.free(nix_ldflags);
63
64 is_nix = true;51 is_nix = true;
65 var it = mem.tokenizeScalar(u8, nix_ldflags, ' ');52 var it = mem.tokenizeScalar(u8, nix_ldflags, ' ');
66 while (true) {53 while (true) {
...@@ -89,17 +76,16 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths...@@ -89,17 +76,16 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
89 return self;76 return self;
90 }77 }
9178
79 // TODO: consider also adding homebrew paths
80 // TODO: consider also adding macports paths
92 if (comptime builtin.target.isDarwin()) {81 if (comptime builtin.target.isDarwin()) {
93 try self.addIncludeDir("/usr/include");82 if (std.zig.system.darwin.isSdkInstalled(arena)) sdk: {
94 try self.addLibDir("/usr/lib");83 const sdk = std.zig.system.darwin.getSdk(arena, native_target) orelse break :sdk;
95 try self.addFrameworkDir("/System/Library/Frameworks");84 try self.addLibDir(try std.fs.path.join(arena, &.{ sdk.path, "usr/lib" }));
9685 try self.addFrameworkDir(try std.fs.path.join(arena, &.{ sdk.path, "System/Library/Frameworks" }));
97 if (builtin.target.os.version_range.semver.min.major < 11) {86 try self.addIncludeDir(try std.fs.path.join(arena, &.{ sdk.path, "usr/include" }));
98 try self.addIncludeDir("/usr/local/include");87 return self;
99 try self.addLibDir("/usr/local/lib");
100 try self.addFrameworkDir("/Library/Frameworks");
101 }88 }
102
103 return self;89 return self;
104 }90 }
10591
...@@ -115,8 +101,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths...@@ -115,8 +101,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
115 }101 }
116102
117 if (builtin.os.tag != .windows) {103 if (builtin.os.tag != .windows) {
118 const triple = try native_target.linuxTriple(allocator);104 const triple = try native_target.linuxTriple(arena);
119 defer allocator.free(triple);
120105
121 const qual = native_target.ptrBitWidth();106 const qual = native_target.ptrBitWidth();
122107
...@@ -172,69 +157,42 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths...@@ -172,69 +157,42 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
172 return self;157 return self;
173}158}
174159
175pub fn deinit(self: *NativePaths) void {
176 deinitArray(&self.include_dirs);
177 deinitArray(&self.lib_dirs);
178 deinitArray(&self.framework_dirs);
179 deinitArray(&self.rpaths);
180 deinitArray(&self.warnings);
181 self.* = undefined;
182}
183
184fn deinitArray(array: *ArrayList([:0]u8)) void {
185 for (array.items) |item| {
186 array.allocator.free(item);
187 }
188 array.deinit();
189}
190
191pub fn addIncludeDir(self: *NativePaths, s: []const u8) !void {160pub fn addIncludeDir(self: *NativePaths, s: []const u8) !void {
192 return self.appendArray(&self.include_dirs, s);161 return self.include_dirs.append(self.arena, s);
193}162}
194163
195pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {164pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
196 const item = try std.fmt.allocPrintZ(self.include_dirs.allocator, fmt, args);165 const item = try std.fmt.allocPrint(self.arena, fmt, args);
197 errdefer self.include_dirs.allocator.free(item);166 try self.include_dirs.append(self.arena, item);
198 try self.include_dirs.append(item);
199}167}
200168
201pub fn addLibDir(self: *NativePaths, s: []const u8) !void {169pub fn addLibDir(self: *NativePaths, s: []const u8) !void {
202 return self.appendArray(&self.lib_dirs, s);170 try self.lib_dirs.append(self.arena, s);
203}171}
204172
205pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {173pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
206 const item = try std.fmt.allocPrintZ(self.lib_dirs.allocator, fmt, args);174 const item = try std.fmt.allocPrint(self.arena, fmt, args);
207 errdefer self.lib_dirs.allocator.free(item);175 try self.lib_dirs.append(self.arena, item);
208 try self.lib_dirs.append(item);
209}176}
210177
211pub fn addWarning(self: *NativePaths, s: []const u8) !void {178pub fn addWarning(self: *NativePaths, s: []const u8) !void {
212 return self.appendArray(&self.warnings, s);179 return self.warnings.append(self.arena, s);
213}180}
214181
215pub fn addFrameworkDir(self: *NativePaths, s: []const u8) !void {182pub fn addFrameworkDir(self: *NativePaths, s: []const u8) !void {
216 return self.appendArray(&self.framework_dirs, s);183 return self.framework_dirs.append(self.arena, s);
217}184}
218185
219pub fn addFrameworkDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {186pub fn addFrameworkDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
220 const item = try std.fmt.allocPrintZ(self.framework_dirs.allocator, fmt, args);187 const item = try std.fmt.allocPrint(self.arena, fmt, args);
221 errdefer self.framework_dirs.allocator.free(item);188 try self.framework_dirs.append(self.arena, item);
222 try self.framework_dirs.append(item);
223}189}
224190
225pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {191pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
226 const item = try std.fmt.allocPrintZ(self.warnings.allocator, fmt, args);192 const item = try std.fmt.allocPrint(self.arena, fmt, args);
227 errdefer self.warnings.allocator.free(item);193 try self.warnings.append(self.arena, item);
228 try self.warnings.append(item);
229}194}
230195
231pub fn addRPath(self: *NativePaths, s: []const u8) !void {196pub fn addRPath(self: *NativePaths, s: []const u8) !void {
232 return self.appendArray(&self.rpaths, s);197 try self.rpaths.append(self.arena, s);
233}
234
235fn appendArray(self: *NativePaths, array: *ArrayList([:0]u8), s: []const u8) !void {
236 _ = self;
237 const item = try array.allocator.dupeZ(u8, s);
238 errdefer array.allocator.free(item);
239 try array.append(item);
240}198}
lib/std/zig/system/darwin.zig+29-25
...@@ -8,28 +8,34 @@ pub const macos = @import("darwin/macos.zig");...@@ -8,28 +8,34 @@ pub const macos = @import("darwin/macos.zig");
88
9/// Check if SDK is installed on Darwin without triggering CLT installation popup window.9/// Check if SDK is installed on Darwin without triggering CLT installation popup window.
10/// Note: simply invoking `xcrun` will inevitably trigger the CLT installation popup.10/// Note: simply invoking `xcrun` will inevitably trigger the CLT installation popup.
11/// Therefore, we resort to the same tool used by Homebrew, namely, invoking `xcode-select --print-path`11/// Therefore, we resort to invoking `xcode-select --print-path` and checking
12/// and checking if the status is nonzero or the returned string in nonempty.12/// if the status is nonzero.
13/// https://github.com/Homebrew/brew/blob/e119bdc571dcb000305411bc1e26678b132afb98/Library/Homebrew/brew.sh#L63013/// stderr from xcode-select is ignored.
14pub fn isDarwinSDKInstalled(allocator: Allocator) bool {14/// If error.OutOfMemory occurs in Allocator, this function returns null.
15 const argv = &[_][]const u8{ "/usr/bin/xcode-select", "--print-path" };15pub fn isSdkInstalled(allocator: Allocator) bool {
16 const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return false;16 const result = std.process.Child.exec(.{
17 .allocator = allocator,
18 .argv = &.{ "/usr/bin/xcode-select", "--print-path" },
19 }) catch return false;
20
17 defer {21 defer {
18 allocator.free(result.stderr);22 allocator.free(result.stderr);
19 allocator.free(result.stdout);23 allocator.free(result.stdout);
20 }24 }
21 if (result.stderr.len != 0 or result.term.Exited != 0) {25
22 // We don't actually care if there were errors as this is best-effort check anyhow.26 return switch (result.term) {
23 return false;27 .Exited => |code| if (code == 0) result.stdout.len > 0 else false,
24 }28 else => false,
25 return result.stdout.len > 0;29 };
26}30}
2731
28/// Detect SDK on Darwin.32/// Detect SDK on Darwin.
29/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which fetches the path to the SDK sysroot (if any).33/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which fetches the path to the SDK sysroot (if any).
30/// Subsequently calls `xcrun --sdk <target_sdk> --show-sdk-version` which fetches version of the SDK.34/// Subsequently calls `xcrun --sdk <target_sdk> --show-sdk-version` which fetches version of the SDK.
31/// The caller needs to deinit the resulting struct.35/// The caller needs to deinit the resulting struct.
32pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {36/// stderr from xcrun is ignored.
37/// If error.OutOfMemory occurs in Allocator, this function returns null.
38pub fn getSdk(allocator: Allocator, target: Target) ?Sdk {
33 const is_simulator_abi = target.abi == .simulator;39 const is_simulator_abi = target.abi == .simulator;
34 const sdk = switch (target.os.tag) {40 const sdk = switch (target.os.tag) {
35 .macos => "macosx",41 .macos => "macosx",
...@@ -40,30 +46,28 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {...@@ -40,30 +46,28 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {
40 };46 };
41 const path = path: {47 const path = path: {
42 const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-path" };48 const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-path" };
43 const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return null;49 const result = std.process.Child.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
44 defer {50 defer {
45 allocator.free(result.stderr);51 allocator.free(result.stderr);
46 allocator.free(result.stdout);52 allocator.free(result.stdout);
47 }53 }
48 if (result.stderr.len != 0 or result.term.Exited != 0) {54 switch (result.term) {
49 // We don't actually care if there were errors as this is best-effort check anyhow55 .Exited => |code| if (code != 0) return null,
50 // and in the worst case the user can specify the sysroot manually.56 else => return null,
51 return null;
52 }57 }
53 const path = allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n")) catch return null;58 const path = allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n")) catch return null;
54 break :path path;59 break :path path;
55 };60 };
56 const version = version: {61 const version = version: {
57 const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-version" };62 const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-version" };
58 const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return null;63 const result = std.process.Child.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
59 defer {64 defer {
60 allocator.free(result.stderr);65 allocator.free(result.stderr);
61 allocator.free(result.stdout);66 allocator.free(result.stdout);
62 }67 }
63 if (result.stderr.len != 0 or result.term.Exited != 0) {68 switch (result.term) {
64 // We don't actually care if there were errors as this is best-effort check anyhow69 .Exited => |code| if (code != 0) return null,
65 // and in the worst case the user can specify the sysroot manually.70 else => return null,
66 return null;
67 }71 }
68 const raw_version = mem.trimRight(u8, result.stdout, "\r\n");72 const raw_version = mem.trimRight(u8, result.stdout, "\r\n");
69 const version = parseSdkVersion(raw_version) orelse Version{73 const version = parseSdkVersion(raw_version) orelse Version{
...@@ -73,7 +77,7 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {...@@ -73,7 +77,7 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {
73 };77 };
74 break :version version;78 break :version version;
75 };79 };
76 return DarwinSDK{80 return Sdk{
77 .path = path,81 .path = path,
78 .version = version,82 .version = version,
79 };83 };
...@@ -96,11 +100,11 @@ fn parseSdkVersion(raw: []const u8) ?Version {...@@ -96,11 +100,11 @@ fn parseSdkVersion(raw: []const u8) ?Version {
96 return Version.parse(buffer[0..len]) catch null;100 return Version.parse(buffer[0..len]) catch null;
97}101}
98102
99pub const DarwinSDK = struct {103pub const Sdk = struct {
100 path: []const u8,104 path: []const u8,
101 version: Version,105 version: Version,
102106
103 pub fn deinit(self: DarwinSDK, allocator: Allocator) void {107 pub fn deinit(self: Sdk, allocator: Allocator) void {
104 allocator.free(self.path);108 allocator.free(self.path);
105 }109 }
106};110};
src/Compilation.zig+107-102
...@@ -124,6 +124,7 @@ zig_lib_directory: Directory,...@@ -124,6 +124,7 @@ zig_lib_directory: Directory,
124local_cache_directory: Directory,124local_cache_directory: Directory,
125global_cache_directory: Directory,125global_cache_directory: Directory,
126libc_include_dir_list: []const []const u8,126libc_include_dir_list: []const []const u8,
127libc_framework_dir_list: []const []const u8,
127thread_pool: *ThreadPool,128thread_pool: *ThreadPool,
128129
129/// Populated when we build the libc++ static library. A Job to build this is placed in the queue130/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
...@@ -448,6 +449,7 @@ pub const ClangPreprocessorMode = enum {...@@ -448,6 +449,7 @@ pub const ClangPreprocessorMode = enum {
448 stdout,449 stdout,
449};450};
450451
452pub const Framework = link.Framework;
451pub const SystemLib = link.SystemLib;453pub const SystemLib = link.SystemLib;
452pub const CacheMode = link.CacheMode;454pub const CacheMode = link.CacheMode;
453455
...@@ -505,7 +507,7 @@ pub const InitOptions = struct {...@@ -505,7 +507,7 @@ pub const InitOptions = struct {
505 c_source_files: []const CSourceFile = &[0]CSourceFile{},507 c_source_files: []const CSourceFile = &[0]CSourceFile{},
506 link_objects: []LinkObject = &[0]LinkObject{},508 link_objects: []LinkObject = &[0]LinkObject{},
507 framework_dirs: []const []const u8 = &[0][]const u8{},509 framework_dirs: []const []const u8 = &[0][]const u8{},
508 frameworks: std.StringArrayHashMapUnmanaged(SystemLib) = .{},510 frameworks: std.StringArrayHashMapUnmanaged(Framework) = .{},
509 system_lib_names: []const []const u8 = &.{},511 system_lib_names: []const []const u8 = &.{},
510 system_lib_infos: []const SystemLib = &.{},512 system_lib_infos: []const SystemLib = &.{},
511 /// These correspond to the WASI libc emulated subcomponents including:513 /// These correspond to the WASI libc emulated subcomponents including:
...@@ -636,16 +638,12 @@ pub const InitOptions = struct {...@@ -636,16 +638,12 @@ pub const InitOptions = struct {
636 wasi_exec_model: ?std.builtin.WasiExecModel = null,638 wasi_exec_model: ?std.builtin.WasiExecModel = null,
637 /// (Zig compiler development) Enable dumping linker's state as JSON.639 /// (Zig compiler development) Enable dumping linker's state as JSON.
638 enable_link_snapshots: bool = false,640 enable_link_snapshots: bool = false,
639 /// (Darwin) Path and version of the native SDK if detected.
640 native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
641 /// (Darwin) Install name of the dylib641 /// (Darwin) Install name of the dylib
642 install_name: ?[]const u8 = null,642 install_name: ?[]const u8 = null,
643 /// (Darwin) Path to entitlements file643 /// (Darwin) Path to entitlements file
644 entitlements: ?[]const u8 = null,644 entitlements: ?[]const u8 = null,
645 /// (Darwin) size of the __PAGEZERO segment645 /// (Darwin) size of the __PAGEZERO segment
646 pagezero_size: ?u64 = null,646 pagezero_size: ?u64 = null,
647 /// (Darwin) search strategy for system libraries
648 search_strategy: ?link.File.MachO.SearchStrategy = null,
649 /// (Darwin) set minimum space for future expansion of the load commands647 /// (Darwin) set minimum space for future expansion of the load commands
650 headerpad_size: ?u32 = null,648 headerpad_size: ?u32 = null,
651 /// (Darwin) set enough space as if all paths were MATPATHLEN649 /// (Darwin) set enough space as if all paths were MATPATHLEN
...@@ -855,16 +853,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -855,16 +853,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
855 break :blk false;853 break :blk false;
856 };854 };
857855
858 const sysroot = blk: {
859 if (options.sysroot) |sysroot| {
860 break :blk sysroot;
861 } else if (options.native_darwin_sdk) |sdk| {
862 break :blk sdk.path;
863 } else {
864 break :blk null;
865 }
866 };
867
868 const lto = blk: {856 const lto = blk: {
869 if (options.want_lto) |explicit| {857 if (options.want_lto) |explicit| {
870 if (!use_lld and !options.target.isDarwin())858 if (!use_lld and !options.target.isDarwin())
...@@ -948,9 +936,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -948,9 +936,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
948 options.is_native_abi,936 options.is_native_abi,
949 link_libc,937 link_libc,
950 options.libc_installation,938 options.libc_installation,
951 options.native_darwin_sdk != null,
952 );939 );
953940
941 const sysroot = options.sysroot orelse libc_dirs.sysroot;
942
954 const must_pie = target_util.requiresPIE(options.target);943 const must_pie = target_util.requiresPIE(options.target);
955 const pie: bool = if (options.want_pie) |explicit| pie: {944 const pie: bool = if (options.want_pie) |explicit| pie: {
956 if (!explicit and must_pie) {945 if (!explicit and must_pie) {
...@@ -1563,11 +1552,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1563,11 +1552,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1563 .wasi_exec_model = wasi_exec_model,1552 .wasi_exec_model = wasi_exec_model,
1564 .hash_style = options.hash_style,1553 .hash_style = options.hash_style,
1565 .enable_link_snapshots = options.enable_link_snapshots,1554 .enable_link_snapshots = options.enable_link_snapshots,
1566 .native_darwin_sdk = options.native_darwin_sdk,
1567 .install_name = options.install_name,1555 .install_name = options.install_name,
1568 .entitlements = options.entitlements,1556 .entitlements = options.entitlements,
1569 .pagezero_size = options.pagezero_size,1557 .pagezero_size = options.pagezero_size,
1570 .search_strategy = options.search_strategy,
1571 .headerpad_size = options.headerpad_size,1558 .headerpad_size = options.headerpad_size,
1572 .headerpad_max_install_names = options.headerpad_max_install_names,1559 .headerpad_max_install_names = options.headerpad_max_install_names,
1573 .dead_strip_dylibs = options.dead_strip_dylibs,1560 .dead_strip_dylibs = options.dead_strip_dylibs,
...@@ -1601,6 +1588,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1601,6 +1588,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1601 .cache_parent = cache,1588 .cache_parent = cache,
1602 .self_exe_path = options.self_exe_path,1589 .self_exe_path = options.self_exe_path,
1603 .libc_include_dir_list = libc_dirs.libc_include_dir_list,1590 .libc_include_dir_list = libc_dirs.libc_include_dir_list,
1591 .libc_framework_dir_list = libc_dirs.libc_framework_dir_list,
1604 .sanitize_c = sanitize_c,1592 .sanitize_c = sanitize_c,
1605 .thread_pool = options.thread_pool,1593 .thread_pool = options.thread_pool,
1606 .clang_passthrough_mode = options.clang_passthrough_mode,1594 .clang_passthrough_mode = options.clang_passthrough_mode,
...@@ -1727,15 +1715,18 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1727,15 +1715,18 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17271715
1728 // When linking mingw-w64 there are some import libs we always need.1716 // When linking mingw-w64 there are some import libs we always need.
1729 for (mingw.always_link_libs) |name| {1717 for (mingw.always_link_libs) |name| {
1730 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});1718 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{
1719 .needed = false,
1720 .weak = false,
1721 .path = null,
1722 });
1731 }1723 }
1732 }1724 }
1733 // Generate Windows import libs.1725 // Generate Windows import libs.
1734 if (target.os.tag == .windows) {1726 if (target.os.tag == .windows) {
1735 const count = comp.bin_file.options.system_libs.count();1727 const count = comp.bin_file.options.system_libs.count();
1736 try comp.work_queue.ensureUnusedCapacity(count);1728 try comp.work_queue.ensureUnusedCapacity(count);
1737 var i: usize = 0;1729 for (0..count) |i| {
1738 while (i < count) : (i += 1) {
1739 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });1730 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });
1740 }1731 }
1741 }1732 }
...@@ -2367,17 +2358,17 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2367,17 +2358,17 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
2367 if (comp.bin_file.options.link_libc) {2358 if (comp.bin_file.options.link_libc) {
2368 man.hash.add(comp.bin_file.options.libc_installation != null);2359 man.hash.add(comp.bin_file.options.libc_installation != null);
2369 if (comp.bin_file.options.libc_installation) |libc_installation| {2360 if (comp.bin_file.options.libc_installation) |libc_installation| {
2370 man.hash.addBytes(libc_installation.crt_dir.?);2361 man.hash.addOptionalBytes(libc_installation.crt_dir);
2371 if (target.abi == .msvc) {2362 if (target.abi == .msvc) {
2372 man.hash.addBytes(libc_installation.msvc_lib_dir.?);2363 man.hash.addOptionalBytes(libc_installation.msvc_lib_dir);
2373 man.hash.addBytes(libc_installation.kernel32_lib_dir.?);2364 man.hash.addOptionalBytes(libc_installation.kernel32_lib_dir);
2374 }2365 }
2375 }2366 }
2376 man.hash.addOptionalBytes(comp.bin_file.options.dynamic_linker);2367 man.hash.addOptionalBytes(comp.bin_file.options.dynamic_linker);
2377 }2368 }
2378 man.hash.addOptionalBytes(comp.bin_file.options.soname);2369 man.hash.addOptionalBytes(comp.bin_file.options.soname);
2379 man.hash.addOptional(comp.bin_file.options.version);2370 man.hash.addOptional(comp.bin_file.options.version);
2380 link.hashAddSystemLibs(&man.hash, comp.bin_file.options.system_libs);2371 try link.hashAddSystemLibs(man, comp.bin_file.options.system_libs);
2381 man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys());2372 man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys());
2382 man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined);2373 man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined);
2383 man.hash.add(comp.bin_file.options.bind_global_refs_locally);2374 man.hash.add(comp.bin_file.options.bind_global_refs_locally);
...@@ -2395,10 +2386,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -2395,10 +2386,9 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
23952386
2396 // Mach-O specific stuff2387 // Mach-O specific stuff
2397 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);2388 man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
2398 link.hashAddSystemLibs(&man.hash, comp.bin_file.options.frameworks);2389 link.hashAddFrameworks(&man.hash, comp.bin_file.options.frameworks);
2399 try man.addOptionalFile(comp.bin_file.options.entitlements);2390 try man.addOptionalFile(comp.bin_file.options.entitlements);
2400 man.hash.addOptional(comp.bin_file.options.pagezero_size);2391 man.hash.addOptional(comp.bin_file.options.pagezero_size);
2401 man.hash.addOptional(comp.bin_file.options.search_strategy);
2402 man.hash.addOptional(comp.bin_file.options.headerpad_size);2392 man.hash.addOptional(comp.bin_file.options.headerpad_size);
2403 man.hash.add(comp.bin_file.options.headerpad_max_install_names);2393 man.hash.add(comp.bin_file.options.headerpad_max_install_names);
2404 man.hash.add(comp.bin_file.options.dead_strip_dylibs);2394 man.hash.add(comp.bin_file.options.dead_strip_dylibs);
...@@ -4341,6 +4331,14 @@ pub fn addCCArgs(...@@ -4341,6 +4331,14 @@ pub fn addCCArgs(
4341 try argv.append("-ObjC++");4331 try argv.append("-ObjC++");
4342 }4332 }
43434333
4334 for (comp.libc_framework_dir_list) |framework_dir| {
4335 try argv.appendSlice(&.{ "-iframework", framework_dir });
4336 }
4337
4338 for (comp.bin_file.options.framework_dirs) |framework_dir| {
4339 try argv.appendSlice(&.{ "-F", framework_dir });
4340 }
4341
4344 // According to Rich Felker libc headers are supposed to go before C language headers.4342 // According to Rich Felker libc headers are supposed to go before C language headers.
4345 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics4343 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
4346 // and other compiler specific items.4344 // and other compiler specific items.
...@@ -4823,6 +4821,8 @@ test "classifyFileExt" {...@@ -4823,6 +4821,8 @@ test "classifyFileExt" {
4823const LibCDirs = struct {4821const LibCDirs = struct {
4824 libc_include_dir_list: []const []const u8,4822 libc_include_dir_list: []const []const u8,
4825 libc_installation: ?*const LibCInstallation,4823 libc_installation: ?*const LibCInstallation,
4824 libc_framework_dir_list: []const []const u8,
4825 sysroot: ?[]const u8,
4826};4826};
48274827
4828fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8, target: Target) !LibCDirs {4828fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8, target: Target) !LibCDirs {
...@@ -4853,6 +4853,8 @@ fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8,...@@ -4853,6 +4853,8 @@ fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8,
4853 return LibCDirs{4853 return LibCDirs{
4854 .libc_include_dir_list = list,4854 .libc_include_dir_list = list,
4855 .libc_installation = null,4855 .libc_installation = null,
4856 .libc_framework_dir_list = &.{},
4857 .sysroot = null,
4856 };4858 };
4857}4859}
48584860
...@@ -4863,12 +4865,13 @@ fn detectLibCIncludeDirs(...@@ -4863,12 +4865,13 @@ fn detectLibCIncludeDirs(
4863 is_native_abi: bool,4865 is_native_abi: bool,
4864 link_libc: bool,4866 link_libc: bool,
4865 libc_installation: ?*const LibCInstallation,4867 libc_installation: ?*const LibCInstallation,
4866 has_macos_sdk: bool,
4867) !LibCDirs {4868) !LibCDirs {
4868 if (!link_libc) {4869 if (!link_libc) {
4869 return LibCDirs{4870 return LibCDirs{
4870 .libc_include_dir_list = &[0][]u8{},4871 .libc_include_dir_list = &[0][]u8{},
4871 .libc_installation = null,4872 .libc_installation = null,
4873 .libc_framework_dir_list = &.{},
4874 .sysroot = null,
4872 };4875 };
4873 }4876 }
48744877
...@@ -4879,28 +4882,19 @@ fn detectLibCIncludeDirs(...@@ -4879,28 +4882,19 @@ fn detectLibCIncludeDirs(
4879 // If linking system libraries and targeting the native abi, default to4882 // If linking system libraries and targeting the native abi, default to
4880 // using the system libc installation.4883 // using the system libc installation.
4881 if (is_native_abi and !target.isMinGW()) {4884 if (is_native_abi and !target.isMinGW()) {
4882 if (target.isDarwin()) {
4883 return if (has_macos_sdk)
4884 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.
4885 LibCDirs{
4886 .libc_include_dir_list = &[0][]u8{},
4887 .libc_installation = null,
4888 }
4889 else
4890 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
4891 }
4892 const libc = try arena.create(LibCInstallation);4885 const libc = try arena.create(LibCInstallation);
4893 libc.* = LibCInstallation.findNative(.{ .allocator = arena }) catch |err| switch (err) {4886 libc.* = LibCInstallation.findNative(.{ .allocator = arena, .target = target }) catch |err| switch (err) {
4894 error.CCompilerExitCode,4887 error.CCompilerExitCode,
4895 error.CCompilerCrashed,4888 error.CCompilerCrashed,
4896 error.CCompilerCannotFindHeaders,4889 error.CCompilerCannotFindHeaders,
4897 error.UnableToSpawnCCompiler,4890 error.UnableToSpawnCCompiler,
4891 error.DarwinSdkNotFound,
4898 => |e| {4892 => |e| {
4899 // We tried to integrate with the native system C compiler,4893 // We tried to integrate with the native system C compiler,
4900 // however, it is not installed. So we must rely on our bundled4894 // however, it is not installed. So we must rely on our bundled
4901 // libc files.4895 // libc files.
4902 if (target_util.canBuildLibC(target)) {4896 if (target_util.canBuildLibC(target)) {
4903 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);4897 return detectLibCFromBuilding(arena, zig_lib_dir, target);
4904 }4898 }
4905 return e;4899 return e;
4906 },4900 },
...@@ -4912,7 +4906,7 @@ fn detectLibCIncludeDirs(...@@ -4912,7 +4906,7 @@ fn detectLibCIncludeDirs(
4912 // If not linking system libraries, build and provide our own libc by4906 // If not linking system libraries, build and provide our own libc by
4913 // default if possible.4907 // default if possible.
4914 if (target_util.canBuildLibC(target)) {4908 if (target_util.canBuildLibC(target)) {
4915 return detectLibCFromBuilding(arena, zig_lib_dir, target, has_macos_sdk);4909 return detectLibCFromBuilding(arena, zig_lib_dir, target);
4916 }4910 }
49174911
4918 // If zig can't build the libc for the target and we are targeting the4912 // If zig can't build the libc for the target and we are targeting the
...@@ -4926,18 +4920,21 @@ fn detectLibCIncludeDirs(...@@ -4926,18 +4920,21 @@ fn detectLibCIncludeDirs(
49264920
4927 if (use_system_abi) {4921 if (use_system_abi) {
4928 const libc = try arena.create(LibCInstallation);4922 const libc = try arena.create(LibCInstallation);
4929 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });4923 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true, .target = target });
4930 return detectLibCFromLibCInstallation(arena, target, libc);4924 return detectLibCFromLibCInstallation(arena, target, libc);
4931 }4925 }
49324926
4933 return LibCDirs{4927 return LibCDirs{
4934 .libc_include_dir_list = &[0][]u8{},4928 .libc_include_dir_list = &[0][]u8{},
4935 .libc_installation = null,4929 .libc_installation = null,
4930 .libc_framework_dir_list = &.{},
4931 .sysroot = null,
4936 };4932 };
4937}4933}
49384934
4939fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs {4935fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs {
4940 var list = try std.ArrayList([]const u8).initCapacity(arena, 5);4936 var list = try std.ArrayList([]const u8).initCapacity(arena, 5);
4937 var framework_list = std.ArrayList([]const u8).init(arena);
49414938
4942 list.appendAssumeCapacity(lci.include_dir.?);4939 list.appendAssumeCapacity(lci.include_dir.?);
49434940
...@@ -4965,9 +4962,20 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const...@@ -4965,9 +4962,20 @@ fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const
4965 list.appendAssumeCapacity(config_dir);4962 list.appendAssumeCapacity(config_dir);
4966 }4963 }
49674964
4965 var sysroot: ?[]const u8 = null;
4966
4967 if (target.isDarwin()) d: {
4968 const down1 = std.fs.path.dirname(lci.sys_include_dir.?) orelse break :d;
4969 const down2 = std.fs.path.dirname(down1) orelse break :d;
4970 try framework_list.append(try std.fs.path.join(arena, &.{ down2, "System", "Library", "Frameworks" }));
4971 sysroot = down2;
4972 }
4973
4968 return LibCDirs{4974 return LibCDirs{
4969 .libc_include_dir_list = list.items,4975 .libc_include_dir_list = list.items,
4970 .libc_installation = lci,4976 .libc_installation = lci,
4977 .libc_framework_dir_list = framework_list.items,
4978 .sysroot = sysroot,
4971 };4979 };
4972}4980}
49734981
...@@ -4975,69 +4983,61 @@ fn detectLibCFromBuilding(...@@ -4975,69 +4983,61 @@ fn detectLibCFromBuilding(
4975 arena: Allocator,4983 arena: Allocator,
4976 zig_lib_dir: []const u8,4984 zig_lib_dir: []const u8,
4977 target: std.Target,4985 target: std.Target,
4978 has_macos_sdk: bool,
4979) !LibCDirs {4986) !LibCDirs {
4980 switch (target.os.tag) {4987 if (target.isDarwin())
4981 .macos => return if (has_macos_sdk)4988 return getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
4982 // For Darwin/macOS, we are all set with getDarwinSDK found earlier.4989
4983 LibCDirs{4990 const generic_name = target_util.libCGenericName(target);
4984 .libc_include_dir_list = &[0][]u8{},4991 // Some architectures are handled by the same set of headers.
4985 .libc_installation = null,4992 const arch_name = if (target.abi.isMusl())
4986 }4993 musl.archNameHeaders(target.cpu.arch)
4987 else4994 else if (target.cpu.arch.isThumb())
4988 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target),4995 // ARM headers are valid for Thumb too.
4989 else => {4996 switch (target.cpu.arch) {
4990 const generic_name = target_util.libCGenericName(target);4997 .thumb => "arm",
4991 // Some architectures are handled by the same set of headers.4998 .thumbeb => "armeb",
4992 const arch_name = if (target.abi.isMusl())4999 else => unreachable,
4993 musl.archNameHeaders(target.cpu.arch)5000 }
4994 else if (target.cpu.arch.isThumb())5001 else
4995 // ARM headers are valid for Thumb too.5002 @tagName(target.cpu.arch);
4996 switch (target.cpu.arch) {5003 const os_name = @tagName(target.os.tag);
4997 .thumb => "arm",5004 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
4998 .thumbeb => "armeb",5005 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
4999 else => unreachable,5006 const s = std.fs.path.sep_str;
5000 }5007 const arch_include_dir = try std.fmt.allocPrint(
5001 else5008 arena,
5002 @tagName(target.cpu.arch);5009 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
5003 const os_name = @tagName(target.os.tag);5010 .{ zig_lib_dir, arch_name, os_name, abi_name },
5004 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.5011 );
5005 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);5012 const generic_include_dir = try std.fmt.allocPrint(
5006 const s = std.fs.path.sep_str;5013 arena,
5007 const arch_include_dir = try std.fmt.allocPrint(5014 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
5008 arena,5015 .{ zig_lib_dir, generic_name },
5009 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",5016 );
5010 .{ zig_lib_dir, arch_name, os_name, abi_name },5017 const generic_arch_name = target_util.osArchName(target);
5011 );5018 const arch_os_include_dir = try std.fmt.allocPrint(
5012 const generic_include_dir = try std.fmt.allocPrint(5019 arena,
5013 arena,5020 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
5014 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",5021 .{ zig_lib_dir, generic_arch_name, os_name },
5015 .{ zig_lib_dir, generic_name },5022 );
5016 );5023 const generic_os_include_dir = try std.fmt.allocPrint(
5017 const generic_arch_name = target_util.osArchName(target);5024 arena,
5018 const arch_os_include_dir = try std.fmt.allocPrint(5025 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
5019 arena,5026 .{ zig_lib_dir, os_name },
5020 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",5027 );
5021 .{ zig_lib_dir, generic_arch_name, os_name },
5022 );
5023 const generic_os_include_dir = try std.fmt.allocPrint(
5024 arena,
5025 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
5026 .{ zig_lib_dir, os_name },
5027 );
50285028
5029 const list = try arena.alloc([]const u8, 4);5029 const list = try arena.alloc([]const u8, 4);
5030 list[0] = arch_include_dir;5030 list[0] = arch_include_dir;
5031 list[1] = generic_include_dir;5031 list[1] = generic_include_dir;
5032 list[2] = arch_os_include_dir;5032 list[2] = arch_os_include_dir;
5033 list[3] = generic_os_include_dir;5033 list[3] = generic_os_include_dir;
50345034
5035 return LibCDirs{5035 return LibCDirs{
5036 .libc_include_dir_list = list,5036 .libc_include_dir_list = list,
5037 .libc_installation = null,5037 .libc_installation = null,
5038 };5038 .libc_framework_dir_list = &.{},
5039 },5039 .sysroot = null,
5040 }5040 };
5041}5041}
50425042
5043pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {5043pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
...@@ -5618,6 +5618,11 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -5618,6 +5618,11 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
5618 // to queue up a work item to produce the DLL import library for this.5618 // to queue up a work item to produce the DLL import library for this.
5619 const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);5619 const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);
5620 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {5620 if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
5621 gop.value_ptr.* = .{
5622 .needed = true,
5623 .weak = false,
5624 .path = null,
5625 };
5621 try comp.work_queue.writeItem(.{5626 try comp.work_queue.writeItem(.{
5622 .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,5627 .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,
5623 });5628 });
src/libc_installation.zig+15-1
...@@ -33,6 +33,7 @@ pub const LibCInstallation = struct {...@@ -33,6 +33,7 @@ pub const LibCInstallation = struct {
33 LibCKernel32LibNotFound,33 LibCKernel32LibNotFound,
34 UnsupportedArchitecture,34 UnsupportedArchitecture,
35 WindowsSdkNotFound,35 WindowsSdkNotFound,
36 DarwinSdkNotFound,
36 ZigIsTheCCompiler,37 ZigIsTheCCompiler,
37 };38 };
3839
...@@ -171,6 +172,7 @@ pub const LibCInstallation = struct {...@@ -171,6 +172,7 @@ pub const LibCInstallation = struct {
171172
172 pub const FindNativeOptions = struct {173 pub const FindNativeOptions = struct {
173 allocator: Allocator,174 allocator: Allocator,
175 target: std.Target,
174176
175 /// If enabled, will print human-friendly errors to stderr.177 /// If enabled, will print human-friendly errors to stderr.
176 verbose: bool = false,178 verbose: bool = false,
...@@ -181,7 +183,19 @@ pub const LibCInstallation = struct {...@@ -181,7 +183,19 @@ pub const LibCInstallation = struct {
181 var self: LibCInstallation = .{};183 var self: LibCInstallation = .{};
182184
183 if (is_darwin) {185 if (is_darwin) {
184 @panic("Darwin is handled separately via std.zig.system.darwin module");186 if (!std.zig.system.darwin.isSdkInstalled(args.allocator))
187 return error.DarwinSdkNotFound;
188 const sdk = std.zig.system.darwin.getSdk(args.allocator, args.target) orelse
189 return error.DarwinSdkNotFound;
190 defer args.allocator.free(sdk.path);
191
192 self.include_dir = try fs.path.join(args.allocator, &.{
193 sdk.path, "usr/include",
194 });
195 self.sys_include_dir = try fs.path.join(args.allocator, &.{
196 sdk.path, "usr/include",
197 });
198 return self;
185 } else if (is_windows) {199 } else if (is_windows) {
186 var sdk: ZigWindowsSDK = ZigWindowsSDK.find(args.allocator) catch |err| switch (err) {200 var sdk: ZigWindowsSDK = ZigWindowsSDK.find(args.allocator) catch |err| switch (err) {
187 error.NotFound => return error.WindowsSdkNotFound,201 error.NotFound => return error.WindowsSdkNotFound,
src/link.zig+32-9
...@@ -21,7 +21,20 @@ const Type = @import("type.zig").Type;...@@ -21,7 +21,20 @@ const Type = @import("type.zig").Type;
21const TypedValue = @import("TypedValue.zig");21const TypedValue = @import("TypedValue.zig");
2222
23/// When adding a new field, remember to update `hashAddSystemLibs`.23/// When adding a new field, remember to update `hashAddSystemLibs`.
24/// These are *always* dynamically linked. Static libraries will be
25/// provided as positional arguments.
24pub const SystemLib = struct {26pub const SystemLib = struct {
27 needed: bool,
28 weak: bool,
29 /// This can be null in two cases right now:
30 /// 1. Windows DLLs that zig ships such as advapi32.
31 /// 2. extern "foo" fn declarations where we find out about libraries too late
32 /// TODO: make this non-optional and resolve those two cases somehow.
33 path: ?[]const u8,
34};
35
36/// When adding a new field, remember to update `hashAddFrameworks`.
37pub const Framework = struct {
25 needed: bool = false,38 needed: bool = false,
26 weak: bool = false,39 weak: bool = false,
27};40};
...@@ -31,11 +44,23 @@ pub const SortSection = enum { name, alignment };...@@ -31,11 +44,23 @@ pub const SortSection = enum { name, alignment };
31pub const CacheMode = enum { incremental, whole };44pub const CacheMode = enum { incremental, whole };
3245
33pub fn hashAddSystemLibs(46pub fn hashAddSystemLibs(
34 hh: *Cache.HashHelper,47 man: *Cache.Manifest,
35 hm: std.StringArrayHashMapUnmanaged(SystemLib),48 hm: std.StringArrayHashMapUnmanaged(SystemLib),
49) !void {
50 const keys = hm.keys();
51 man.hash.addListOfBytes(keys);
52 for (hm.values()) |value| {
53 man.hash.add(value.needed);
54 man.hash.add(value.weak);
55 if (value.path) |p| _ = try man.addFile(p, null);
56 }
57}
58
59pub fn hashAddFrameworks(
60 hh: *Cache.HashHelper,
61 hm: std.StringArrayHashMapUnmanaged(Framework),
36) void {62) void {
37 const keys = hm.keys();63 const keys = hm.keys();
38 hh.add(keys.len);
39 hh.addListOfBytes(keys);64 hh.addListOfBytes(keys);
40 for (hm.values()) |value| {65 for (hm.values()) |value| {
41 hh.add(value.needed);66 hh.add(value.needed);
...@@ -183,9 +208,12 @@ pub const Options = struct {...@@ -183,9 +208,12 @@ pub const Options = struct {
183208
184 objects: []Compilation.LinkObject,209 objects: []Compilation.LinkObject,
185 framework_dirs: []const []const u8,210 framework_dirs: []const []const u8,
186 frameworks: std.StringArrayHashMapUnmanaged(SystemLib),211 frameworks: std.StringArrayHashMapUnmanaged(Framework),
212 /// These are *always* dynamically linked. Static libraries will be
213 /// provided as positional arguments.
187 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),214 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
188 wasi_emulated_libs: []const wasi_libc.CRTFile,215 wasi_emulated_libs: []const wasi_libc.CRTFile,
216 // TODO: remove this. libraries are resolved by the frontend.
189 lib_dirs: []const []const u8,217 lib_dirs: []const []const u8,
190 rpath_list: []const []const u8,218 rpath_list: []const []const u8,
191219
...@@ -203,6 +231,7 @@ pub const Options = struct {...@@ -203,6 +231,7 @@ pub const Options = struct {
203231
204 version: ?std.SemanticVersion,232 version: ?std.SemanticVersion,
205 compatibility_version: ?std.SemanticVersion,233 compatibility_version: ?std.SemanticVersion,
234 darwin_sdk_version: ?std.SemanticVersion = null,
206 libc_installation: ?*const LibCInstallation,235 libc_installation: ?*const LibCInstallation,
207236
208 dwarf_format: ?std.dwarf.Format,237 dwarf_format: ?std.dwarf.Format,
...@@ -213,9 +242,6 @@ pub const Options = struct {...@@ -213,9 +242,6 @@ pub const Options = struct {
213 /// (Zig compiler development) Enable dumping of linker's state as JSON.242 /// (Zig compiler development) Enable dumping of linker's state as JSON.
214 enable_link_snapshots: bool = false,243 enable_link_snapshots: bool = false,
215244
216 /// (Darwin) Path and version of the native SDK if detected.
217 native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null,
218
219 /// (Darwin) Install name for the dylib245 /// (Darwin) Install name for the dylib
220 install_name: ?[]const u8 = null,246 install_name: ?[]const u8 = null,
221247
...@@ -225,9 +251,6 @@ pub const Options = struct {...@@ -225,9 +251,6 @@ pub const Options = struct {
225 /// (Darwin) size of the __PAGEZERO segment251 /// (Darwin) size of the __PAGEZERO segment
226 pagezero_size: ?u64 = null,252 pagezero_size: ?u64 = null,
227253
228 /// (Darwin) search strategy for system libraries
229 search_strategy: ?File.MachO.SearchStrategy = null,
230
231 /// (Darwin) set minimum space for future expansion of the load commands254 /// (Darwin) set minimum space for future expansion of the load commands
232 headerpad_size: ?u32 = null,255 headerpad_size: ?u32 = null,
233256
src/link/Coff/lld.zig+2-1
...@@ -88,7 +88,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -88,7 +88,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
88 }88 }
89 }89 }
90 }90 }
91 link.hashAddSystemLibs(&man.hash, self.base.options.system_libs);91 try link.hashAddSystemLibs(&man, self.base.options.system_libs);
92 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());92 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
93 man.hash.addOptional(self.base.options.subsystem);93 man.hash.addOptional(self.base.options.subsystem);
94 man.hash.add(self.base.options.is_test);94 man.hash.add(self.base.options.is_test);
...@@ -405,6 +405,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -405,6 +405,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
405 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));405 try argv.append(try comp.get_libc_crt_file(arena, "mingw32.lib"));
406 try argv.append(try comp.get_libc_crt_file(arena, "mingwex.lib"));406 try argv.append(try comp.get_libc_crt_file(arena, "mingwex.lib"));
407 try argv.append(try comp.get_libc_crt_file(arena, "msvcrt-os.lib"));407 try argv.append(try comp.get_libc_crt_file(arena, "msvcrt-os.lib"));
408 try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib"));
408409
409 for (mingw.always_link_libs) |name| {410 for (mingw.always_link_libs) |name| {
410 if (!self.base.options.system_libs.contains(name)) {411 if (!self.base.options.system_libs.contains(name)) {
src/link/Elf.zig+4-6
...@@ -1428,7 +1428,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1428,7 +1428,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1428 }1428 }
1429 man.hash.addOptionalBytes(self.base.options.soname);1429 man.hash.addOptionalBytes(self.base.options.soname);
1430 man.hash.addOptional(self.base.options.version);1430 man.hash.addOptional(self.base.options.version);
1431 link.hashAddSystemLibs(&man.hash, self.base.options.system_libs);1431 try link.hashAddSystemLibs(&man, self.base.options.system_libs);
1432 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());1432 man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
1433 man.hash.add(allow_shlib_undefined);1433 man.hash.add(allow_shlib_undefined);
1434 man.hash.add(self.base.options.bind_global_refs_locally);1434 man.hash.add(self.base.options.bind_global_refs_locally);
...@@ -1824,8 +1824,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1824,8 +1824,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1824 argv.appendAssumeCapacity("--as-needed");1824 argv.appendAssumeCapacity("--as-needed");
1825 var as_needed = true;1825 var as_needed = true;
18261826
1827 for (system_libs, 0..) |link_lib, i| {1827 for (system_libs_values) |lib_info| {
1828 const lib_as_needed = !system_libs_values[i].needed;1828 const lib_as_needed = !lib_info.needed;
1829 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {1829 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1830 0b00, 0b11 => {},1830 0b00, 0b11 => {},
1831 0b01 => {1831 0b01 => {
...@@ -1842,9 +1842,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v...@@ -1842,9 +1842,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
1842 // libraries and not static libraries (the check for that needs to be earlier),1842 // libraries and not static libraries (the check for that needs to be earlier),
1843 // but they could be full paths to .so files, in which case we1843 // but they could be full paths to .so files, in which case we
1844 // want to avoid prepending "-l".1844 // want to avoid prepending "-l".
1845 const ext = Compilation.classifyFileExt(link_lib);1845 argv.appendAssumeCapacity(lib_info.path.?);
1846 const arg = if (ext == .shared_library) link_lib else try std.fmt.allocPrint(arena, "-l{s}", .{link_lib});
1847 argv.appendAssumeCapacity(arg);
1848 }1846 }
18491847
1850 if (!as_needed) {1848 if (!as_needed) {
src/link/MachO.zig+40-34
...@@ -58,11 +58,6 @@ const Rebase = @import("MachO/dyld_info/Rebase.zig");...@@ -58,11 +58,6 @@ const Rebase = @import("MachO/dyld_info/Rebase.zig");
5858
59pub const base_tag: File.Tag = File.Tag.macho;59pub const base_tag: File.Tag = File.Tag.macho;
6060
61pub const SearchStrategy = enum {
62 paths_first,
63 dylibs_first,
64};
65
66/// Mode of operation of the linker.61/// Mode of operation of the linker.
67pub const Mode = enum {62pub const Mode = enum {
68 /// Incremental mode will preallocate segments/sections and is compatible with63 /// Incremental mode will preallocate segments/sections and is compatible with
...@@ -834,39 +829,50 @@ pub fn resolveLibSystem(...@@ -834,39 +829,50 @@ pub fn resolveLibSystem(
834 out_libs: anytype,829 out_libs: anytype,
835) !void {830) !void {
836 // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}.831 // If we were given the sysroot, try to look there first for libSystem.B.{dylib, tbd}.
837 var libsystem_available = false;832 if (syslibroot) |root| {
838 if (syslibroot != null) blk: {833 const full_dir_path = try std.fs.path.join(arena, &.{ root, "usr", "lib" });
839 // Try stub file first. If we hit it, then we're done as the stub file834 if (try resolveLibSystemInDirs(arena, &.{full_dir_path}, out_libs)) return;
840 // re-exports every single symbol definition.835 }
841 for (search_dirs) |dir| {836
842 if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| {837 // Next, try input search dirs if we are linking on a custom host such as Nix.
843 try out_libs.put(full_path, .{ .needed = true });838 if (try resolveLibSystemInDirs(arena, search_dirs, out_libs)) return;
844 libsystem_available = true;839
845 break :blk;840 // As a fallback, try linking against Zig shipped stub.
846 }841 const libsystem_name = try std.fmt.allocPrint(arena, "libSystem.{d}.tbd", .{
842 target.os.version_range.semver.min.major,
843 });
844 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
845 "libc", "darwin", libsystem_name,
846 });
847 try out_libs.put(full_path, .{
848 .needed = true,
849 .weak = false,
850 .path = full_path,
851 });
852}
853
854fn resolveLibSystemInDirs(arena: Allocator, dirs: []const []const u8, out_libs: anytype) !bool {
855 // Try stub file first. If we hit it, then we're done as the stub file
856 // re-exports every single symbol definition.
857 for (dirs) |dir| {
858 if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| {
859 try out_libs.put(full_path, .{ .needed = true, .weak = false, .path = full_path });
860 return true;
847 }861 }
848 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib862 }
849 // doesn't export libc.dylib which we'll need to resolve subsequently also.863 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
850 for (search_dirs) |dir| {864 // doesn't export libc.dylib which we'll need to resolve subsequently also.
851 if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| {865 for (dirs) |dir| {
852 if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| {866 if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| {
853 try out_libs.put(libsystem_path, .{ .needed = true });867 if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| {
854 try out_libs.put(libc_path, .{ .needed = true });868 try out_libs.put(libsystem_path, .{ .needed = true, .weak = false, .path = libsystem_path });
855 libsystem_available = true;869 try out_libs.put(libc_path, .{ .needed = true, .weak = false, .path = libc_path });
856 break :blk;870 return true;
857 }
858 }871 }
859 }872 }
860 }873 }
861 if (!libsystem_available) {874
862 const libsystem_name = try std.fmt.allocPrint(arena, "libSystem.{d}.tbd", .{875 return false;
863 target.os.version_range.semver.min.major,
864 });
865 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
866 "libc", "darwin", libsystem_name,
867 });
868 try out_libs.put(full_path, .{ .needed = true });
869 }
870}876}
871877
872pub fn resolveSearchDir(878pub fn resolveSearchDir(
src/link/MachO/load_commands.zig+4-5
...@@ -278,11 +278,10 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo...@@ -278,11 +278,10 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo
278 const platform_version = @as(u32, @intCast(ver.major << 16 | ver.minor << 8));278 const platform_version = @as(u32, @intCast(ver.major << 16 | ver.minor << 8));
279 break :blk platform_version;279 break :blk platform_version;
280 };280 };
281 const sdk_version = if (options.native_darwin_sdk) |sdk| blk: {281 const sdk_version: u32 = if (options.darwin_sdk_version) |ver|
282 const ver = sdk.version;282 @intCast(ver.major << 16 | ver.minor << 8)
283 const sdk_version = @as(u32, @intCast(ver.major << 16 | ver.minor << 8));283 else
284 break :blk sdk_version;284 platform_version;
285 } else platform_version;
286 const is_simulator_abi = options.target.abi == .simulator;285 const is_simulator_abi = options.target.abi == .simulator;
287 try lc_writer.writeStruct(macho.build_version_command{286 try lc_writer.writeStruct(macho.build_version_command{
288 .cmdsize = cmdsize,287 .cmdsize = cmdsize,
src/link/MachO/zld.zig+8-82
...@@ -3410,7 +3410,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3410,7 +3410,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3410 // installation sources because they are always a product of the compiler version + target information.3410 // installation sources because they are always a product of the compiler version + target information.
3411 man.hash.add(stack_size);3411 man.hash.add(stack_size);
3412 man.hash.addOptional(options.pagezero_size);3412 man.hash.addOptional(options.pagezero_size);
3413 man.hash.addOptional(options.search_strategy);
3414 man.hash.addOptional(options.headerpad_size);3413 man.hash.addOptional(options.headerpad_size);
3415 man.hash.add(options.headerpad_max_install_names);3414 man.hash.add(options.headerpad_max_install_names);
3416 man.hash.add(gc_sections);3415 man.hash.add(gc_sections);
...@@ -3418,13 +3417,13 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3418,13 +3417,13 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3418 man.hash.add(options.strip);3417 man.hash.add(options.strip);
3419 man.hash.addListOfBytes(options.lib_dirs);3418 man.hash.addListOfBytes(options.lib_dirs);
3420 man.hash.addListOfBytes(options.framework_dirs);3419 man.hash.addListOfBytes(options.framework_dirs);
3421 link.hashAddSystemLibs(&man.hash, options.frameworks);3420 link.hashAddFrameworks(&man.hash, options.frameworks);
3422 man.hash.addListOfBytes(options.rpath_list);3421 man.hash.addListOfBytes(options.rpath_list);
3423 if (is_dyn_lib) {3422 if (is_dyn_lib) {
3424 man.hash.addOptionalBytes(options.install_name);3423 man.hash.addOptionalBytes(options.install_name);
3425 man.hash.addOptional(options.version);3424 man.hash.addOptional(options.version);
3426 }3425 }
3427 link.hashAddSystemLibs(&man.hash, options.system_libs);3426 try link.hashAddSystemLibs(&man, options.system_libs);
3428 man.hash.addOptionalBytes(options.sysroot);3427 man.hash.addOptionalBytes(options.sysroot);
3429 man.hash.addListOfBytes(options.force_undefined_symbols.keys());3428 man.hash.addListOfBytes(options.force_undefined_symbols.keys());
3430 try man.addOptionalFile(options.entitlements);3429 try man.addOptionalFile(options.entitlements);
...@@ -3550,84 +3549,15 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3550,84 +3549,15 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3550 try positionals.append(comp.libcxx_static_lib.?.full_object_path);3549 try positionals.append(comp.libcxx_static_lib.?.full_object_path);
3551 }3550 }
35523551
3553 // Shared and static libraries passed via `-l` flag.
3554 var candidate_libs = std.StringArrayHashMap(link.SystemLib).init(arena);
3555
3556 const system_lib_names = options.system_libs.keys();
3557 for (system_lib_names) |system_lib_name| {
3558 // By this time, we depend on these libs being dynamically linked libraries and not static libraries
3559 // (the check for that needs to be earlier), but they could be full paths to .dylib files, in which
3560 // case we want to avoid prepending "-l".
3561 if (Compilation.classifyFileExt(system_lib_name) == .shared_library) {
3562 try positionals.append(system_lib_name);
3563 continue;
3564 }
3565
3566 const system_lib_info = options.system_libs.get(system_lib_name).?;
3567 try candidate_libs.put(system_lib_name, .{
3568 .needed = system_lib_info.needed,
3569 .weak = system_lib_info.weak,
3570 });
3571 }
3572
3573 var lib_dirs = std.ArrayList([]const u8).init(arena);
3574 for (options.lib_dirs) |dir| {
3575 if (try MachO.resolveSearchDir(arena, dir, options.sysroot)) |search_dir| {
3576 try lib_dirs.append(search_dir);
3577 } else {
3578 log.warn("directory not found for '-L{s}'", .{dir});
3579 }
3580 }
3581
3582 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);3552 var libs = std.StringArrayHashMap(link.SystemLib).init(arena);
35833553
3584 // Assume ld64 default -search_paths_first if no strategy specified.3554 {
3585 const search_strategy = options.search_strategy orelse .paths_first;3555 const vals = options.system_libs.values();
3586 outer: for (candidate_libs.keys()) |lib_name| {3556 try libs.ensureUnusedCapacity(vals.len);
3587 switch (search_strategy) {3557 for (vals) |v| libs.putAssumeCapacity(v.path.?, v);
3588 .paths_first => {
3589 // Look in each directory for a dylib (stub first), and then for archive
3590 for (lib_dirs.items) |dir| {
3591 for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
3592 if (try MachO.resolveLib(arena, dir, lib_name, ext)) |full_path| {
3593 try libs.put(full_path, candidate_libs.get(lib_name).?);
3594 continue :outer;
3595 }
3596 }
3597 } else {
3598 log.warn("library not found for '-l{s}'", .{lib_name});
3599 lib_not_found = true;
3600 }
3601 },
3602 .dylibs_first => {
3603 // First, look for a dylib in each search dir
3604 for (lib_dirs.items) |dir| {
3605 for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| {
3606 if (try MachO.resolveLib(arena, dir, lib_name, ext)) |full_path| {
3607 try libs.put(full_path, candidate_libs.get(lib_name).?);
3608 continue :outer;
3609 }
3610 }
3611 } else for (lib_dirs.items) |dir| {
3612 if (try MachO.resolveLib(arena, dir, lib_name, ".a")) |full_path| {
3613 try libs.put(full_path, candidate_libs.get(lib_name).?);
3614 } else {
3615 log.warn("library not found for '-l{s}'", .{lib_name});
3616 lib_not_found = true;
3617 }
3618 }
3619 },
3620 }
3621 }
3622
3623 if (lib_not_found) {
3624 log.warn("Library search paths:", .{});
3625 for (lib_dirs.items) |dir| {
3626 log.warn(" {s}", .{dir});
3627 }
3628 }3558 }
36293559
3630 try MachO.resolveLibSystem(arena, comp, options.sysroot, target, lib_dirs.items, &libs);3560 try MachO.resolveLibSystem(arena, comp, options.sysroot, target, options.lib_dirs, &libs);
36313561
3632 // frameworks3562 // frameworks
3633 var framework_dirs = std.ArrayList([]const u8).init(arena);3563 var framework_dirs = std.ArrayList([]const u8).init(arena);
...@@ -3647,6 +3577,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3647,6 +3577,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3647 try libs.put(full_path, .{3577 try libs.put(full_path, .{
3648 .needed = info.needed,3578 .needed = info.needed,
3649 .weak = info.weak,3579 .weak = info.weak,
3580 .path = full_path,
3650 });3581 });
3651 continue :outer;3582 continue :outer;
3652 }3583 }
...@@ -3698,11 +3629,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3698,11 +3629,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3698 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));3629 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size}));
3699 }3630 }
37003631
3701 if (options.search_strategy) |strat| switch (strat) {
3702 .paths_first => try argv.append("-search_paths_first"),
3703 .dylibs_first => try argv.append("-search_dylibs_first"),
3704 };
3705
3706 if (options.headerpad_size) |headerpad_size| {3632 if (options.headerpad_size) |headerpad_size| {
3707 try argv.append("-headerpad_size");3633 try argv.append("-headerpad_size");
3708 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{headerpad_size}));3634 try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{headerpad_size}));
src/main.zig+529-281
...@@ -28,6 +28,7 @@ const target_util = @import("target.zig");...@@ -28,6 +28,7 @@ const target_util = @import("target.zig");
28const crash_report = @import("crash_report.zig");28const crash_report = @import("crash_report.zig");
29const Module = @import("Module.zig");29const Module = @import("Module.zig");
30const AstGen = @import("AstGen.zig");30const AstGen = @import("AstGen.zig");
31const mingw = @import("mingw.zig");
31const Server = std.zig.Server;32const Server = std.zig.Server;
3233
33pub const std_options = struct {34pub const std_options = struct {
...@@ -476,7 +477,19 @@ const usage_build_generic =...@@ -476,7 +477,19 @@ const usage_build_generic =
476 \\ -l[lib], --library [lib] Link against system library (only if actually used)477 \\ -l[lib], --library [lib] Link against system library (only if actually used)
477 \\ -needed-l[lib], Link against system library (even if unused)478 \\ -needed-l[lib], Link against system library (even if unused)
478 \\ --needed-library [lib]479 \\ --needed-library [lib]
480 \\ -weak-l[lib] link against system library marking it and all
481 \\ -weak_library [lib] referenced symbols as weak
479 \\ -L[d], --library-directory [d] Add a directory to the library search path482 \\ -L[d], --library-directory [d] Add a directory to the library search path
483 \\ -search_paths_first For each library search path, check for dynamic
484 \\ lib then static lib before proceeding to next path.
485 \\ -search_paths_first_static For each library search path, check for static
486 \\ lib then dynamic lib before proceeding to next path.
487 \\ -search_dylibs_first Search for dynamic libs in all library search
488 \\ paths, then static libs.
489 \\ -search_static_first Search for static libs in all library search
490 \\ paths, then dynamic libs.
491 \\ -search_dylibs_only Only search for dynamic libs.
492 \\ -search_static_only Only search for static libs.
480 \\ -T[script], --script [script] Use a custom linker script493 \\ -T[script], --script [script] Use a custom linker script
481 \\ --version-script [path] Provide a version .map file494 \\ --version-script [path] Provide a version .map file
482 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)495 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
...@@ -527,18 +540,14 @@ const usage_build_generic =...@@ -527,18 +540,14 @@ const usage_build_generic =
527 \\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker540 \\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
528 \\ --stack [size] Override default stack size541 \\ --stack [size] Override default stack size
529 \\ --image-base [addr] Set base address for executable image542 \\ --image-base [addr] Set base address for executable image
530 \\ -weak-l[lib] (Darwin) link against system library and mark it and all referenced symbols as weak
531 \\ -weak_library [lib]
532 \\ -framework [name] (Darwin) link against framework543 \\ -framework [name] (Darwin) link against framework
533 \\ -needed_framework [name] (Darwin) link against framework (even if unused)544 \\ -needed_framework [name] (Darwin) link against framework (even if unused)
534 \\ -needed_library [lib] (Darwin) link against system library (even if unused)545 \\ -needed_library [lib] link against system library (even if unused)
535 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak546 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
536 \\ -F[dir] (Darwin) add search path for frameworks547 \\ -F[dir] (Darwin) add search path for frameworks
537 \\ -install_name=[value] (Darwin) add dylib's install name548 \\ -install_name=[value] (Darwin) add dylib's install name
538 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature549 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
539 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation550 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
540 \\ -search_paths_first (Darwin) search each dir in library search paths for `libx.dylib` then `libx.a`
541 \\ -search_dylibs_first (Darwin) search `libx.dylib` in each dir in library search paths, then `libx.a`
542 \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation551 \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation
543 \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN552 \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN
544 \\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols553 \\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols
...@@ -716,6 +725,39 @@ const ArgsIterator = struct {...@@ -716,6 +725,39 @@ const ArgsIterator = struct {
716 }725 }
717};726};
718727
728/// In contrast to `link.SystemLib`, this stores arguments that may need to be
729/// resolved into static libraries so that we can pass only dynamic libraries
730/// as system libs to `Compilation`.
731const SystemLib = struct {
732 needed: bool,
733 weak: bool,
734
735 preferred_mode: std.builtin.LinkMode,
736 search_strategy: SearchStrategy,
737
738 const SearchStrategy = enum { paths_first, mode_first, no_fallback };
739
740 fn fallbackMode(this: SystemLib) std.builtin.LinkMode {
741 assert(this.search_strategy != .no_fallback);
742 return switch (this.preferred_mode) {
743 .Dynamic => .Static,
744 .Static => .Dynamic,
745 };
746 }
747};
748
749const CliModule = struct {
750 mod: *Package,
751 /// still in CLI arg format
752 deps_str: []const u8,
753};
754
755fn cleanupModules(modules: *std.StringArrayHashMap(CliModule)) void {
756 var it = modules.iterator();
757 while (it.next()) |kv| kv.value_ptr.mod.destroy(modules.allocator);
758 modules.deinit();
759}
760
719fn buildOutputType(761fn buildOutputType(
720 gpa: Allocator,762 gpa: Allocator,
721 arena: Allocator,763 arena: Allocator,
...@@ -849,12 +891,12 @@ fn buildOutputType(...@@ -849,12 +891,12 @@ fn buildOutputType(
849 var minor_subsystem_version: ?u32 = null;891 var minor_subsystem_version: ?u32 = null;
850 var wasi_exec_model: ?std.builtin.WasiExecModel = null;892 var wasi_exec_model: ?std.builtin.WasiExecModel = null;
851 var enable_link_snapshots: bool = false;893 var enable_link_snapshots: bool = false;
852 var native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null;
853 var install_name: ?[]const u8 = null;894 var install_name: ?[]const u8 = null;
854 var hash_style: link.HashStyle = .both;895 var hash_style: link.HashStyle = .both;
855 var entitlements: ?[]const u8 = null;896 var entitlements: ?[]const u8 = null;
856 var pagezero_size: ?u64 = null;897 var pagezero_size: ?u64 = null;
857 var search_strategy: ?link.File.MachO.SearchStrategy = null;898 var lib_search_strategy: SystemLib.SearchStrategy = .paths_first;
899 var lib_preferred_mode: std.builtin.LinkMode = .Dynamic;
858 var headerpad_size: ?u32 = null;900 var headerpad_size: ?u32 = null;
859 var headerpad_max_install_names: bool = false;901 var headerpad_max_install_names: bool = false;
860 var dead_strip_dylibs: bool = false;902 var dead_strip_dylibs: bool = false;
...@@ -862,66 +904,30 @@ fn buildOutputType(...@@ -862,66 +904,30 @@ fn buildOutputType(
862 var error_tracing: ?bool = null;904 var error_tracing: ?bool = null;
863 var pdb_out_path: ?[]const u8 = null;905 var pdb_out_path: ?[]const u8 = null;
864 var dwarf_format: ?std.dwarf.Format = null;906 var dwarf_format: ?std.dwarf.Format = null;
865
866 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.907 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
867 // This array is populated by zig cc frontend and then has to be converted to zig-style908 // This array is populated by zig cc frontend and then has to be converted to zig-style
868 // CPU features.909 // CPU features.
869 var llvm_m_args = std.ArrayList([]const u8).init(gpa);910 var llvm_m_args = std.ArrayList([]const u8).init(arena);
870 defer llvm_m_args.deinit();911 var system_libs = std.StringArrayHashMap(SystemLib).init(arena);
871912 var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(arena);
872 var system_libs = std.StringArrayHashMap(Compilation.SystemLib).init(gpa);913 var clang_argv = std.ArrayList([]const u8).init(arena);
873 defer system_libs.deinit();914 var extra_cflags = std.ArrayList([]const u8).init(arena);
874915 // These are before resolving sysroot.
875 var static_libs = std.ArrayList([]const u8).init(gpa);916 var lib_dir_args = std.ArrayList([]const u8).init(arena);
876 defer static_libs.deinit();917 var rpath_list = std.ArrayList([]const u8).init(arena);
877
878 var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(gpa);
879 defer wasi_emulated_libs.deinit();
880
881 var clang_argv = std.ArrayList([]const u8).init(gpa);
882 defer clang_argv.deinit();
883
884 var extra_cflags = std.ArrayList([]const u8).init(gpa);
885 defer extra_cflags.deinit();
886
887 var lib_dirs = std.ArrayList([]const u8).init(gpa);
888 defer lib_dirs.deinit();
889
890 var rpath_list = std.ArrayList([]const u8).init(gpa);
891 defer rpath_list.deinit();
892
893 var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{};918 var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{};
894919 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
895 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(gpa);920 var link_objects = std.ArrayList(Compilation.LinkObject).init(arena);
896 defer c_source_files.deinit();921 var framework_dirs = std.ArrayList([]const u8).init(arena);
897922 var frameworks: std.StringArrayHashMapUnmanaged(Compilation.Framework) = .{};
898 var link_objects = std.ArrayList(Compilation.LinkObject).init(gpa);
899 defer link_objects.deinit();
900
901 var framework_dirs = std.ArrayList([]const u8).init(gpa);
902 defer framework_dirs.deinit();
903
904 var frameworks: std.StringArrayHashMapUnmanaged(Compilation.SystemLib) = .{};
905
906 // null means replace with the test executable binary923 // null means replace with the test executable binary
907 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);924 var test_exec_args = std.ArrayList(?[]const u8).init(arena);
908 defer test_exec_args.deinit();925 var linker_export_symbol_names = std.ArrayList([]const u8).init(arena);
909
910 var linker_export_symbol_names = std.ArrayList([]const u8).init(gpa);
911 defer linker_export_symbol_names.deinit();
912
913 // Contains every module specified via --mod. The dependencies are added926 // Contains every module specified via --mod. The dependencies are added
914 // after argument parsing is completed. We use a StringArrayHashMap to make927 // after argument parsing is completed. We use a StringArrayHashMap to make
915 // error output consistent.928 // error output consistent.
916 var modules = std.StringArrayHashMap(struct {929 var modules = std.StringArrayHashMap(CliModule).init(gpa);
917 mod: *Package,930 defer cleanupModules(&modules);
918 deps_str: []const u8, // still in CLI arg format
919 }).init(gpa);
920 defer {
921 var it = modules.iterator();
922 while (it.next()) |kv| kv.value_ptr.mod.destroy(gpa);
923 modules.deinit();
924 }
925931
926 // The dependency string for the root package932 // The dependency string for the root package
927 var root_deps_str: ?[]const u8 = null;933 var root_deps_str: ?[]const u8 = null;
...@@ -1061,7 +1067,7 @@ fn buildOutputType(...@@ -1061,7 +1067,7 @@ fn buildOutputType(
1061 } else if (mem.eql(u8, arg, "-rpath")) {1067 } else if (mem.eql(u8, arg, "-rpath")) {
1062 try rpath_list.append(args_iter.nextOrFatal());1068 try rpath_list.append(args_iter.nextOrFatal());
1063 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {1069 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
1064 try lib_dirs.append(args_iter.nextOrFatal());1070 try lib_dir_args.append(args_iter.nextOrFatal());
1065 } else if (mem.eql(u8, arg, "-F")) {1071 } else if (mem.eql(u8, arg, "-F")) {
1066 try framework_dirs.append(args_iter.nextOrFatal());1072 try framework_dirs.append(args_iter.nextOrFatal());
1067 } else if (mem.eql(u8, arg, "-framework")) {1073 } else if (mem.eql(u8, arg, "-framework")) {
...@@ -1085,9 +1091,23 @@ fn buildOutputType(...@@ -1085,9 +1091,23 @@ fn buildOutputType(
1085 fatal("unable to parse pagezero size'{s}': {s}", .{ next_arg, @errorName(err) });1091 fatal("unable to parse pagezero size'{s}': {s}", .{ next_arg, @errorName(err) });
1086 };1092 };
1087 } else if (mem.eql(u8, arg, "-search_paths_first")) {1093 } else if (mem.eql(u8, arg, "-search_paths_first")) {
1088 search_strategy = .paths_first;1094 lib_search_strategy = .paths_first;
1095 lib_preferred_mode = .Dynamic;
1096 } else if (mem.eql(u8, arg, "-search_paths_first_static")) {
1097 lib_search_strategy = .paths_first;
1098 lib_preferred_mode = .Static;
1089 } else if (mem.eql(u8, arg, "-search_dylibs_first")) {1099 } else if (mem.eql(u8, arg, "-search_dylibs_first")) {
1090 search_strategy = .dylibs_first;1100 lib_search_strategy = .mode_first;
1101 lib_preferred_mode = .Dynamic;
1102 } else if (mem.eql(u8, arg, "-search_static_first")) {
1103 lib_search_strategy = .mode_first;
1104 lib_preferred_mode = .Static;
1105 } else if (mem.eql(u8, arg, "-search_dylibs_only")) {
1106 lib_search_strategy = .no_fallback;
1107 lib_preferred_mode = .Dynamic;
1108 } else if (mem.eql(u8, arg, "-search_static_only")) {
1109 lib_search_strategy = .no_fallback;
1110 lib_preferred_mode = .Static;
1091 } else if (mem.eql(u8, arg, "-headerpad")) {1111 } else if (mem.eql(u8, arg, "-headerpad")) {
1092 const next_arg = args_iter.nextOrFatal();1112 const next_arg = args_iter.nextOrFatal();
1093 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {1113 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
...@@ -1104,17 +1124,33 @@ fn buildOutputType(...@@ -1104,17 +1124,33 @@ fn buildOutputType(
1104 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {1124 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
1105 version_script = args_iter.nextOrFatal();1125 version_script = args_iter.nextOrFatal();
1106 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {1126 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
1107 // We don't know whether this library is part of libc or libc++ until1127 // We don't know whether this library is part of libc
1108 // we resolve the target, so we simply append to the list for now.1128 // or libc++ until we resolve the target, so we append
1109 try system_libs.put(args_iter.nextOrFatal(), .{});1129 // to the list for now.
1130 try system_libs.put(args_iter.nextOrFatal(), .{
1131 .needed = false,
1132 .weak = false,
1133 .preferred_mode = lib_preferred_mode,
1134 .search_strategy = lib_search_strategy,
1135 });
1110 } else if (mem.eql(u8, arg, "--needed-library") or1136 } else if (mem.eql(u8, arg, "--needed-library") or
1111 mem.eql(u8, arg, "-needed-l") or1137 mem.eql(u8, arg, "-needed-l") or
1112 mem.eql(u8, arg, "-needed_library"))1138 mem.eql(u8, arg, "-needed_library"))
1113 {1139 {
1114 const next_arg = args_iter.nextOrFatal();1140 const next_arg = args_iter.nextOrFatal();
1115 try system_libs.put(next_arg, .{ .needed = true });1141 try system_libs.put(next_arg, .{
1142 .needed = true,
1143 .weak = false,
1144 .preferred_mode = lib_preferred_mode,
1145 .search_strategy = lib_search_strategy,
1146 });
1116 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {1147 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
1117 try system_libs.put(args_iter.nextOrFatal(), .{ .weak = true });1148 try system_libs.put(args_iter.nextOrFatal(), .{
1149 .needed = false,
1150 .weak = true,
1151 .preferred_mode = lib_preferred_mode,
1152 .search_strategy = lib_search_strategy,
1153 });
1118 } else if (mem.eql(u8, arg, "-D")) {1154 } else if (mem.eql(u8, arg, "-D")) {
1119 try clang_argv.append(arg);1155 try clang_argv.append(arg);
1120 try clang_argv.append(args_iter.nextOrFatal());1156 try clang_argv.append(args_iter.nextOrFatal());
...@@ -1346,8 +1382,12 @@ fn buildOutputType(...@@ -1346,8 +1382,12 @@ fn buildOutputType(
1346 emit_implib_arg_provided = true;1382 emit_implib_arg_provided = true;
1347 } else if (mem.eql(u8, arg, "-dynamic")) {1383 } else if (mem.eql(u8, arg, "-dynamic")) {
1348 link_mode = .Dynamic;1384 link_mode = .Dynamic;
1385 lib_preferred_mode = .Dynamic;
1386 lib_search_strategy = .mode_first;
1349 } else if (mem.eql(u8, arg, "-static")) {1387 } else if (mem.eql(u8, arg, "-static")) {
1350 link_mode = .Static;1388 link_mode = .Static;
1389 lib_preferred_mode = .Static;
1390 lib_search_strategy = .no_fallback;
1351 } else if (mem.eql(u8, arg, "-fdll-export-fns")) {1391 } else if (mem.eql(u8, arg, "-fdll-export-fns")) {
1352 dll_export_fns = true;1392 dll_export_fns = true;
1353 } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) {1393 } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) {
...@@ -1486,17 +1526,33 @@ fn buildOutputType(...@@ -1486,17 +1526,33 @@ fn buildOutputType(
1486 } else if (mem.startsWith(u8, arg, "-T")) {1526 } else if (mem.startsWith(u8, arg, "-T")) {
1487 linker_script = arg[2..];1527 linker_script = arg[2..];
1488 } else if (mem.startsWith(u8, arg, "-L")) {1528 } else if (mem.startsWith(u8, arg, "-L")) {
1489 try lib_dirs.append(arg[2..]);1529 try lib_dir_args.append(arg[2..]);
1490 } else if (mem.startsWith(u8, arg, "-F")) {1530 } else if (mem.startsWith(u8, arg, "-F")) {
1491 try framework_dirs.append(arg[2..]);1531 try framework_dirs.append(arg[2..]);
1492 } else if (mem.startsWith(u8, arg, "-l")) {1532 } else if (mem.startsWith(u8, arg, "-l")) {
1493 // We don't know whether this library is part of libc or libc++ until1533 // We don't know whether this library is part of libc
1494 // we resolve the target, so we simply append to the list for now.1534 // or libc++ until we resolve the target, so we append
1495 try system_libs.put(arg["-l".len..], .{});1535 // to the list for now.
1536 try system_libs.put(arg["-l".len..], .{
1537 .needed = false,
1538 .weak = false,
1539 .preferred_mode = lib_preferred_mode,
1540 .search_strategy = lib_search_strategy,
1541 });
1496 } else if (mem.startsWith(u8, arg, "-needed-l")) {1542 } else if (mem.startsWith(u8, arg, "-needed-l")) {
1497 try system_libs.put(arg["-needed-l".len..], .{ .needed = true });1543 try system_libs.put(arg["-needed-l".len..], .{
1544 .needed = true,
1545 .weak = false,
1546 .preferred_mode = lib_preferred_mode,
1547 .search_strategy = lib_search_strategy,
1548 });
1498 } else if (mem.startsWith(u8, arg, "-weak-l")) {1549 } else if (mem.startsWith(u8, arg, "-weak-l")) {
1499 try system_libs.put(arg["-weak-l".len..], .{ .weak = true });1550 try system_libs.put(arg["-weak-l".len..], .{
1551 .needed = false,
1552 .weak = true,
1553 .preferred_mode = lib_preferred_mode,
1554 .search_strategy = lib_search_strategy,
1555 });
1500 } else if (mem.startsWith(u8, arg, "-D")) {1556 } else if (mem.startsWith(u8, arg, "-D")) {
1501 try clang_argv.append(arg);1557 try clang_argv.append(arg);
1502 } else if (mem.startsWith(u8, arg, "-I")) {1558 } else if (mem.startsWith(u8, arg, "-I")) {
...@@ -1571,7 +1627,6 @@ fn buildOutputType(...@@ -1571,7 +1627,6 @@ fn buildOutputType(
1571 var emit_llvm = false;1627 var emit_llvm = false;
1572 var needed = false;1628 var needed = false;
1573 var must_link = false;1629 var must_link = false;
1574 var force_static_libs = false;
1575 var file_ext: ?Compilation.FileExt = null;1630 var file_ext: ?Compilation.FileExt = null;
1576 while (it.has_next) {1631 while (it.has_next) {
1577 it.next() catch |err| {1632 it.next() catch |err| {
...@@ -1641,10 +1696,13 @@ fn buildOutputType(...@@ -1641,10 +1696,13 @@ fn buildOutputType(
1641 .must_link = must_link,1696 .must_link = must_link,
1642 .loption = true,1697 .loption = true,
1643 });1698 });
1644 } else if (force_static_libs) {
1645 try static_libs.append(it.only_arg);
1646 } else {1699 } else {
1647 try system_libs.put(it.only_arg, .{ .needed = needed });1700 try system_libs.put(it.only_arg, .{
1701 .needed = needed,
1702 .weak = false,
1703 .preferred_mode = lib_preferred_mode,
1704 .search_strategy = lib_search_strategy,
1705 });
1648 }1706 }
1649 },1707 },
1650 .ignore => {},1708 .ignore => {},
...@@ -1740,17 +1798,21 @@ fn buildOutputType(...@@ -1740,17 +1798,21 @@ fn buildOutputType(
1740 mem.eql(u8, linker_arg, "-dy") or1798 mem.eql(u8, linker_arg, "-dy") or
1741 mem.eql(u8, linker_arg, "-call_shared"))1799 mem.eql(u8, linker_arg, "-call_shared"))
1742 {1800 {
1743 force_static_libs = false;1801 lib_search_strategy = .no_fallback;
1802 lib_preferred_mode = .Dynamic;
1744 } else if (mem.eql(u8, linker_arg, "-Bstatic") or1803 } else if (mem.eql(u8, linker_arg, "-Bstatic") or
1745 mem.eql(u8, linker_arg, "-dn") or1804 mem.eql(u8, linker_arg, "-dn") or
1746 mem.eql(u8, linker_arg, "-non_shared") or1805 mem.eql(u8, linker_arg, "-non_shared") or
1747 mem.eql(u8, linker_arg, "-static"))1806 mem.eql(u8, linker_arg, "-static"))
1748 {1807 {
1749 force_static_libs = true;1808 lib_search_strategy = .no_fallback;
1809 lib_preferred_mode = .Static;
1750 } else if (mem.eql(u8, linker_arg, "-search_paths_first")) {1810 } else if (mem.eql(u8, linker_arg, "-search_paths_first")) {
1751 search_strategy = .paths_first;1811 lib_search_strategy = .paths_first;
1812 lib_preferred_mode = .Dynamic;
1752 } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) {1813 } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) {
1753 search_strategy = .dylibs_first;1814 lib_search_strategy = .mode_first;
1815 lib_preferred_mode = .Dynamic;
1754 } else {1816 } else {
1755 try linker_args.append(linker_arg);1817 try linker_args.append(linker_arg);
1756 }1818 }
...@@ -1828,7 +1890,7 @@ fn buildOutputType(...@@ -1828,7 +1890,7 @@ fn buildOutputType(
1828 try linker_args.append("-z");1890 try linker_args.append("-z");
1829 try linker_args.append(it.only_arg);1891 try linker_args.append(it.only_arg);
1830 },1892 },
1831 .lib_dir => try lib_dirs.append(it.only_arg),1893 .lib_dir => try lib_dir_args.append(it.only_arg),
1832 .mcpu => target_mcpu = it.only_arg,1894 .mcpu => target_mcpu = it.only_arg,
1833 .m => try llvm_m_args.append(it.only_arg),1895 .m => try llvm_m_args.append(it.only_arg),
1834 .dep_file => {1896 .dep_file => {
...@@ -1860,7 +1922,12 @@ fn buildOutputType(...@@ -1860,7 +1922,12 @@ fn buildOutputType(
1860 .force_undefined_symbol => {1922 .force_undefined_symbol => {
1861 try force_undefined_symbols.put(gpa, it.only_arg, {});1923 try force_undefined_symbols.put(gpa, it.only_arg, {});
1862 },1924 },
1863 .weak_library => try system_libs.put(it.only_arg, .{ .weak = true }),1925 .weak_library => try system_libs.put(it.only_arg, .{
1926 .needed = false,
1927 .weak = true,
1928 .preferred_mode = lib_preferred_mode,
1929 .search_strategy = lib_search_strategy,
1930 }),
1864 .weak_framework => try frameworks.put(gpa, it.only_arg, .{ .weak = true }),1931 .weak_framework => try frameworks.put(gpa, it.only_arg, .{ .weak = true }),
1865 .headerpad_max_install_names => headerpad_max_install_names = true,1932 .headerpad_max_install_names => headerpad_max_install_names = true,
1866 .compress_debug_sections => {1933 .compress_debug_sections => {
...@@ -2156,11 +2223,26 @@ fn buildOutputType(...@@ -2156,11 +2223,26 @@ fn buildOutputType(
2156 } else if (mem.eql(u8, arg, "-needed_framework")) {2223 } else if (mem.eql(u8, arg, "-needed_framework")) {
2157 try frameworks.put(gpa, linker_args_it.nextOrFatal(), .{ .needed = true });2224 try frameworks.put(gpa, linker_args_it.nextOrFatal(), .{ .needed = true });
2158 } else if (mem.eql(u8, arg, "-needed_library")) {2225 } else if (mem.eql(u8, arg, "-needed_library")) {
2159 try system_libs.put(linker_args_it.nextOrFatal(), .{ .needed = true });2226 try system_libs.put(linker_args_it.nextOrFatal(), .{
2227 .weak = false,
2228 .needed = true,
2229 .preferred_mode = lib_preferred_mode,
2230 .search_strategy = lib_search_strategy,
2231 });
2160 } else if (mem.startsWith(u8, arg, "-weak-l")) {2232 } else if (mem.startsWith(u8, arg, "-weak-l")) {
2161 try system_libs.put(arg["-weak-l".len..], .{ .weak = true });2233 try system_libs.put(arg["-weak-l".len..], .{
2234 .weak = true,
2235 .needed = false,
2236 .preferred_mode = lib_preferred_mode,
2237 .search_strategy = lib_search_strategy,
2238 });
2162 } else if (mem.eql(u8, arg, "-weak_library")) {2239 } else if (mem.eql(u8, arg, "-weak_library")) {
2163 try system_libs.put(linker_args_it.nextOrFatal(), .{ .weak = true });2240 try system_libs.put(linker_args_it.nextOrFatal(), .{
2241 .weak = true,
2242 .needed = false,
2243 .preferred_mode = lib_preferred_mode,
2244 .search_strategy = lib_search_strategy,
2245 });
2164 } else if (mem.eql(u8, arg, "-compatibility_version")) {2246 } else if (mem.eql(u8, arg, "-compatibility_version")) {
2165 const compat_version = linker_args_it.nextOrFatal();2247 const compat_version = linker_args_it.nextOrFatal();
2166 compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| {2248 compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| {
...@@ -2458,105 +2540,6 @@ fn buildOutputType(...@@ -2458,105 +2540,6 @@ fn buildOutputType(
2458 }2540 }
2459 }2541 }
24602542
2461 // Now that we have target info, we can find out if any of the system libraries
2462 // are part of libc or libc++. We remove them from the list and communicate their
2463 // existence via flags instead.
2464 {
2465 // Similarly, if any libs in this list are statically provided, we remove
2466 // them from this list and populate the link_objects array instead.
2467 const sep = fs.path.sep_str;
2468 var test_path = std.ArrayList(u8).init(gpa);
2469 defer test_path.deinit();
2470
2471 var i: usize = 0;
2472 syslib: while (i < system_libs.count()) {
2473 const lib_name = system_libs.keys()[i];
2474
2475 if (target_util.is_libc_lib_name(target_info.target, lib_name)) {
2476 link_libc = true;
2477 system_libs.orderedRemoveAt(i);
2478 continue;
2479 }
2480 if (target_util.is_libcpp_lib_name(target_info.target, lib_name)) {
2481 link_libcpp = true;
2482 system_libs.orderedRemoveAt(i);
2483 continue;
2484 }
2485 switch (target_util.classifyCompilerRtLibName(target_info.target, lib_name)) {
2486 .none => {},
2487 .only_libunwind, .both => {
2488 link_libunwind = true;
2489 system_libs.orderedRemoveAt(i);
2490 continue;
2491 },
2492 .only_compiler_rt => {
2493 std.log.warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name});
2494 system_libs.orderedRemoveAt(i);
2495 continue;
2496 },
2497 }
2498
2499 if (fs.path.isAbsolute(lib_name)) {
2500 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
2501 }
2502
2503 if (target_info.target.os.tag == .wasi) {
2504 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
2505 try wasi_emulated_libs.append(crt_file);
2506 system_libs.orderedRemoveAt(i);
2507 continue;
2508 }
2509 }
2510
2511 for (lib_dirs.items) |lib_dir_path| {
2512 if (cross_target.isDarwin()) break; // Targeting Darwin we let the linker resolve the libraries in the correct order
2513 test_path.clearRetainingCapacity();
2514 try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{
2515 lib_dir_path,
2516 target_info.target.libPrefix(),
2517 lib_name,
2518 target_info.target.staticLibSuffix(),
2519 });
2520 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
2521 error.FileNotFound => continue,
2522 else => |e| fatal("unable to search for static library '{s}': {s}", .{
2523 test_path.items, @errorName(e),
2524 }),
2525 };
2526 try link_objects.append(.{ .path = try arena.dupe(u8, test_path.items) });
2527 system_libs.orderedRemoveAt(i);
2528 continue :syslib;
2529 }
2530
2531 // Unfortunately, in the case of MinGW we also need to look for `libfoo.a`.
2532 if (target_info.target.isMinGW()) {
2533 for (lib_dirs.items) |lib_dir_path| {
2534 test_path.clearRetainingCapacity();
2535 try test_path.writer().print("{s}" ++ sep ++ "lib{s}.a", .{
2536 lib_dir_path, lib_name,
2537 });
2538 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
2539 error.FileNotFound => continue,
2540 else => |e| fatal("unable to search for static library '{s}': {s}", .{
2541 test_path.items, @errorName(e),
2542 }),
2543 };
2544 try link_objects.append(.{ .path = try arena.dupe(u8, test_path.items) });
2545 system_libs.orderedRemoveAt(i);
2546 continue :syslib;
2547 }
2548 }
2549
2550 std.log.scoped(.cli).debug("depending on system for -l{s}", .{lib_name});
2551
2552 i += 1;
2553 }
2554 }
2555 // libc++ depends on libc
2556 if (link_libcpp) {
2557 link_libc = true;
2558 }
2559
2560 if (use_lld) |opt| {2543 if (use_lld) |opt| {
2561 if (opt and cross_target.isDarwin()) {2544 if (opt and cross_target.isDarwin()) {
2562 fatal("LLD requested with Mach-O object format. Only the self-hosted linker is supported for this target.", .{});2545 fatal("LLD requested with Mach-O object format. Only the self-hosted linker is supported for this target.", .{});
...@@ -2575,8 +2558,124 @@ fn buildOutputType(...@@ -2575,8 +2558,124 @@ fn buildOutputType(
2575 want_native_include_dirs = true;2558 want_native_include_dirs = true;
2576 }2559 }
25772560
2578 if (sysroot == null and cross_target.isNativeOs() and2561 // Resolve the library path arguments with respect to sysroot.
2579 (system_libs.count() != 0 or want_native_include_dirs))2562 var lib_dirs = std.ArrayList([]const u8).init(arena);
2563 if (sysroot) |root| {
2564 for (lib_dir_args.items) |dir| {
2565 if (fs.path.isAbsolute(dir)) {
2566 const stripped_dir = dir[fs.path.diskDesignator(dir).len..];
2567 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir });
2568 try lib_dirs.append(full_path);
2569 }
2570 try lib_dirs.append(dir);
2571 }
2572 } else {
2573 lib_dirs = lib_dir_args;
2574 }
2575 lib_dir_args = undefined; // From here we use lib_dirs instead.
2576
2577 const self_exe_path: ?[]const u8 = if (!process.can_spawn)
2578 null
2579 else
2580 introspect.findZigExePath(arena) catch |err| {
2581 fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
2582 };
2583
2584 var zig_lib_directory: Compilation.Directory = d: {
2585 if (override_lib_dir) |unresolved_lib_dir| {
2586 const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir);
2587 break :d .{
2588 .path = lib_dir,
2589 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
2590 fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) });
2591 },
2592 };
2593 } else if (builtin.os.tag == .wasi) {
2594 break :d getWasiPreopen("/lib");
2595 } else if (self_exe_path) |p| {
2596 break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| {
2597 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
2598 };
2599 } else {
2600 unreachable;
2601 }
2602 };
2603 defer zig_lib_directory.handle.close();
2604
2605 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.
2606 // We need to know whether the set of system libraries contains anything besides these
2607 // to decide whether to trigger native path detection logic.
2608 var external_system_libs: std.MultiArrayList(struct {
2609 name: []const u8,
2610 info: SystemLib,
2611 }) = .{};
2612
2613 var resolved_system_libs: std.MultiArrayList(struct {
2614 name: []const u8,
2615 lib: Compilation.SystemLib,
2616 }) = .{};
2617
2618 for (system_libs.keys(), system_libs.values()) |lib_name, info| {
2619 if (target_util.is_libc_lib_name(target_info.target, lib_name)) {
2620 link_libc = true;
2621 continue;
2622 }
2623 if (target_util.is_libcpp_lib_name(target_info.target, lib_name)) {
2624 link_libcpp = true;
2625 continue;
2626 }
2627 switch (target_util.classifyCompilerRtLibName(target_info.target, lib_name)) {
2628 .none => {},
2629 .only_libunwind, .both => {
2630 link_libunwind = true;
2631 continue;
2632 },
2633 .only_compiler_rt => {
2634 std.log.warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name});
2635 continue;
2636 },
2637 }
2638
2639 if (target_info.target.os.tag == .windows) {
2640 const exists = mingw.libExists(arena, target_info.target, zig_lib_directory, lib_name) catch |err| {
2641 fatal("failed to check zig installation for DLL import libs: {s}", .{
2642 @errorName(err),
2643 });
2644 };
2645 if (exists) {
2646 try resolved_system_libs.append(arena, .{
2647 .name = lib_name,
2648 .lib = .{
2649 .needed = true,
2650 .weak = false,
2651 .path = null,
2652 },
2653 });
2654 continue;
2655 }
2656 }
2657
2658 if (fs.path.isAbsolute(lib_name)) {
2659 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
2660 }
2661
2662 if (target_info.target.os.tag == .wasi) {
2663 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
2664 try wasi_emulated_libs.append(crt_file);
2665 continue;
2666 }
2667 }
2668
2669 try external_system_libs.append(arena, .{
2670 .name = lib_name,
2671 .info = info,
2672 });
2673 }
2674 // After this point, external_system_libs is used instead of system_libs.
2675
2676 // Trigger native system library path detection if necessary.
2677 if (sysroot == null and cross_target.isNativeOs() and cross_target.isNativeAbi() and
2678 (external_system_libs.len != 0 or want_native_include_dirs))
2580 {2679 {
2581 const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {2680 const paths = std.zig.system.NativePaths.detect(arena, target_info) catch |err| {
2582 fatal("unable to detect native system paths: {s}", .{@errorName(err)});2681 fatal("unable to detect native system paths: {s}", .{@errorName(err)});
...@@ -2585,83 +2684,181 @@ fn buildOutputType(...@@ -2585,83 +2684,181 @@ fn buildOutputType(
2585 warn("{s}", .{warning});2684 warn("{s}", .{warning});
2586 }2685 }
25872686
2588 const has_sysroot = if (comptime builtin.target.isDarwin()) outer: {
2589 if (std.zig.system.darwin.isDarwinSDKInstalled(arena)) {
2590 const sdk = std.zig.system.darwin.getDarwinSDK(arena, target_info.target) orelse
2591 break :outer false;
2592 native_darwin_sdk = sdk;
2593 try clang_argv.ensureUnusedCapacity(2);
2594 clang_argv.appendAssumeCapacity("-isysroot");
2595 clang_argv.appendAssumeCapacity(sdk.path);
2596 break :outer true;
2597 } else break :outer false;
2598 } else false;
2599
2600 try clang_argv.ensureUnusedCapacity(paths.include_dirs.items.len * 2);2687 try clang_argv.ensureUnusedCapacity(paths.include_dirs.items.len * 2);
2601 const isystem_flag = if (has_sysroot) "-iwithsysroot" else "-isystem";
2602 for (paths.include_dirs.items) |include_dir| {2688 for (paths.include_dirs.items) |include_dir| {
2603 clang_argv.appendAssumeCapacity(isystem_flag);2689 clang_argv.appendAssumeCapacity("-isystem");
2604 clang_argv.appendAssumeCapacity(include_dir);2690 clang_argv.appendAssumeCapacity(include_dir);
2605 }2691 }
26062692
2607 try clang_argv.ensureUnusedCapacity(paths.framework_dirs.items.len * 2);2693 try framework_dirs.appendSlice(paths.framework_dirs.items);
2608 try framework_dirs.ensureUnusedCapacity(paths.framework_dirs.items.len);2694 try lib_dirs.appendSlice(paths.lib_dirs.items);
2609 const iframework_flag = if (has_sysroot) "-iframeworkwithsysroot" else "-iframework";2695 try rpath_list.appendSlice(paths.rpaths.items);
2610 for (paths.framework_dirs.items) |framework_dir| {
2611 clang_argv.appendAssumeCapacity(iframework_flag);
2612 clang_argv.appendAssumeCapacity(framework_dir);
2613 framework_dirs.appendAssumeCapacity(framework_dir);
2614 }
2615
2616 for (paths.lib_dirs.items) |lib_dir| {
2617 try lib_dirs.append(lib_dir);
2618 }
2619 for (paths.rpaths.items) |rpath| {
2620 try rpath_list.append(rpath);
2621 }
2622 }2696 }
26232697
2698 // If any libs in this list are statically provided, we omit them from the
2699 // resolved list and populate the link_objects array instead.
2624 {2700 {
2625 // Resolve static libraries into full paths.
2626 const sep = fs.path.sep_str;
2627
2628 var test_path = std.ArrayList(u8).init(gpa);2701 var test_path = std.ArrayList(u8).init(gpa);
2629 defer test_path.deinit();2702 defer test_path.deinit();
26302703
2631 for (static_libs.items) |static_lib| {2704 var checked_paths = std.ArrayList(u8).init(gpa);
2632 for (lib_dirs.items) |lib_dir_path| {2705 defer checked_paths.deinit();
2633 test_path.clearRetainingCapacity();2706
2634 try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{2707 var failed_libs = std.ArrayList(struct {
2635 lib_dir_path,2708 name: []const u8,
2636 target_info.target.libPrefix(),2709 strategy: SystemLib.SearchStrategy,
2637 static_lib,2710 checked_paths: []const u8,
2638 target_info.target.staticLibSuffix(),2711 preferred_mode: std.builtin.LinkMode,
2639 });2712 }).init(arena);
2640 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {2713
2641 error.FileNotFound => continue,2714 syslib: for (external_system_libs.items(.name), external_system_libs.items(.info)) |lib_name, info| {
2642 else => |e| fatal("unable to search for static library '{s}': {s}", .{2715 // Checked in the first pass above while looking for libc libraries.
2643 test_path.items, @errorName(e),2716 assert(!fs.path.isAbsolute(lib_name));
2644 }),2717
2645 };2718 checked_paths.clearRetainingCapacity();
2646 try link_objects.append(.{ .path = try arena.dupe(u8, test_path.items) });2719
2647 break;2720 switch (info.search_strategy) {
2648 } else {2721 .mode_first, .no_fallback => {
2649 var search_paths = std.ArrayList(u8).init(arena);2722 // check for preferred mode
2650 for (lib_dirs.items) |lib_dir_path| {2723 for (lib_dirs.items) |lib_dir_path| {
2651 try search_paths.writer().print("\n {s}" ++ sep ++ "{s}{s}{s}", .{2724 if (try accessLibPath(
2652 lib_dir_path,2725 &test_path,
2653 target_info.target.libPrefix(),2726 &checked_paths,
2654 static_lib,2727 lib_dir_path,
2655 target_info.target.staticLibSuffix(),2728 lib_name,
2729 target_info.target,
2730 info.preferred_mode,
2731 )) {
2732 const path = try arena.dupe(u8, test_path.items);
2733 switch (info.preferred_mode) {
2734 .Static => try link_objects.append(.{ .path = path }),
2735 .Dynamic => try resolved_system_libs.append(arena, .{
2736 .name = lib_name,
2737 .lib = .{
2738 .needed = info.needed,
2739 .weak = info.weak,
2740 .path = path,
2741 },
2742 }),
2743 }
2744 continue :syslib;
2745 }
2746 }
2747 // check for fallback mode
2748 if (info.search_strategy == .no_fallback) {
2749 try failed_libs.append(.{
2750 .name = lib_name,
2751 .strategy = info.search_strategy,
2752 .checked_paths = try arena.dupe(u8, checked_paths.items),
2753 .preferred_mode = info.preferred_mode,
2754 });
2755 continue :syslib;
2756 }
2757 for (lib_dirs.items) |lib_dir_path| {
2758 if (try accessLibPath(
2759 &test_path,
2760 &checked_paths,
2761 lib_dir_path,
2762 lib_name,
2763 target_info.target,
2764 info.fallbackMode(),
2765 )) {
2766 const path = try arena.dupe(u8, test_path.items);
2767 switch (info.fallbackMode()) {
2768 .Static => try link_objects.append(.{ .path = path }),
2769 .Dynamic => try resolved_system_libs.append(arena, .{
2770 .name = lib_name,
2771 .lib = .{
2772 .needed = info.needed,
2773 .weak = info.weak,
2774 .path = path,
2775 },
2776 }),
2777 }
2778 continue :syslib;
2779 }
2780 }
2781 try failed_libs.append(.{
2782 .name = lib_name,
2783 .strategy = info.search_strategy,
2784 .checked_paths = try arena.dupe(u8, checked_paths.items),
2785 .preferred_mode = info.preferred_mode,
2656 });2786 });
2657 }2787 continue :syslib;
2658 try search_paths.appendSlice("\n suggestion: use full paths to static libraries on the command line rather than using -l and -L arguments");2788 },
2659 fatal("static library '{s}' not found. search paths: {s}", .{2789 .paths_first => {
2660 static_lib, search_paths.items,2790 for (lib_dirs.items) |lib_dir_path| {
2791 // check for preferred mode
2792 if (try accessLibPath(
2793 &test_path,
2794 &checked_paths,
2795 lib_dir_path,
2796 lib_name,
2797 target_info.target,
2798 info.preferred_mode,
2799 )) {
2800 const path = try arena.dupe(u8, test_path.items);
2801 switch (info.preferred_mode) {
2802 .Static => try link_objects.append(.{ .path = path }),
2803 .Dynamic => try resolved_system_libs.append(arena, .{
2804 .name = lib_name,
2805 .lib = .{
2806 .needed = info.needed,
2807 .weak = info.weak,
2808 .path = path,
2809 },
2810 }),
2811 }
2812 continue :syslib;
2813 }
2814
2815 // check for fallback mode
2816 if (try accessLibPath(
2817 &test_path,
2818 &checked_paths,
2819 lib_dir_path,
2820 lib_name,
2821 target_info.target,
2822 info.fallbackMode(),
2823 )) {
2824 const path = try arena.dupe(u8, test_path.items);
2825 switch (info.fallbackMode()) {
2826 .Static => try link_objects.append(.{ .path = path }),
2827 .Dynamic => try resolved_system_libs.append(arena, .{
2828 .name = lib_name,
2829 .lib = .{
2830 .needed = info.needed,
2831 .weak = info.weak,
2832 .path = path,
2833 },
2834 }),
2835 }
2836 continue :syslib;
2837 }
2838 }
2839 try failed_libs.append(.{
2840 .name = lib_name,
2841 .strategy = info.search_strategy,
2842 .checked_paths = try arena.dupe(u8, checked_paths.items),
2843 .preferred_mode = info.preferred_mode,
2844 });
2845 continue :syslib;
2846 },
2847 }
2848 @compileError("unreachable");
2849 }
2850
2851 if (failed_libs.items.len > 0) {
2852 for (failed_libs.items) |f| {
2853 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths;
2854 std.log.err("unable to find {s} system library '{s}' using strategy '{s}'. searched paths:{s}", .{
2855 @tagName(f.preferred_mode), f.name, @tagName(f.strategy), searched_paths,
2661 });2856 });
2662 }2857 }
2858 process.exit(1);
2663 }2859 }
2664 }2860 }
2861 // After this point, resolved_system_libs is used instead of external_system_libs.
26652862
2666 const object_format = target_info.target.ofmt;2863 const object_format = target_info.target.ofmt;
26672864
...@@ -2912,35 +3109,6 @@ fn buildOutputType(...@@ -2912,35 +3109,6 @@ fn buildOutputType(
2912 }3109 }
2913 }3110 }
29143111
2915 const self_exe_path: ?[]const u8 = if (!process.can_spawn)
2916 null
2917 else
2918 introspect.findZigExePath(arena) catch |err| {
2919 fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
2920 };
2921
2922 var zig_lib_directory: Compilation.Directory = d: {
2923 if (override_lib_dir) |unresolved_lib_dir| {
2924 const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir);
2925 break :d .{
2926 .path = lib_dir,
2927 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
2928 fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) });
2929 },
2930 };
2931 } else if (builtin.os.tag == .wasi) {
2932 break :d getWasiPreopen("/lib");
2933 } else if (self_exe_path) |p| {
2934 break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| {
2935 fatal("unable to find zig installation directory: {s}", .{@errorName(err)});
2936 };
2937 } else {
2938 unreachable;
2939 }
2940 };
2941
2942 defer zig_lib_directory.handle.close();
2943
2944 var thread_pool: ThreadPool = undefined;3112 var thread_pool: ThreadPool = undefined;
2945 try thread_pool.init(.{ .allocator = gpa });3113 try thread_pool.init(.{ .allocator = gpa });
2946 defer thread_pool.deinit();3114 defer thread_pool.deinit();
...@@ -3086,8 +3254,8 @@ fn buildOutputType(...@@ -3086,8 +3254,8 @@ fn buildOutputType(
3086 .link_objects = link_objects.items,3254 .link_objects = link_objects.items,
3087 .framework_dirs = framework_dirs.items,3255 .framework_dirs = framework_dirs.items,
3088 .frameworks = frameworks,3256 .frameworks = frameworks,
3089 .system_lib_names = system_libs.keys(),3257 .system_lib_names = resolved_system_libs.items(.name),
3090 .system_lib_infos = system_libs.values(),3258 .system_lib_infos = resolved_system_libs.items(.lib),
3091 .wasi_emulated_libs = wasi_emulated_libs.items,3259 .wasi_emulated_libs = wasi_emulated_libs.items,
3092 .link_libc = link_libc,3260 .link_libc = link_libc,
3093 .link_libcpp = link_libcpp,3261 .link_libcpp = link_libcpp,
...@@ -3192,11 +3360,9 @@ fn buildOutputType(...@@ -3192,11 +3360,9 @@ fn buildOutputType(
3192 .wasi_exec_model = wasi_exec_model,3360 .wasi_exec_model = wasi_exec_model,
3193 .debug_compile_errors = debug_compile_errors,3361 .debug_compile_errors = debug_compile_errors,
3194 .enable_link_snapshots = enable_link_snapshots,3362 .enable_link_snapshots = enable_link_snapshots,
3195 .native_darwin_sdk = native_darwin_sdk,
3196 .install_name = install_name,3363 .install_name = install_name,
3197 .entitlements = entitlements,3364 .entitlements = entitlements,
3198 .pagezero_size = pagezero_size,3365 .pagezero_size = pagezero_size,
3199 .search_strategy = search_strategy,
3200 .headerpad_size = headerpad_size,3366 .headerpad_size = headerpad_size,
3201 .headerpad_max_install_names = headerpad_max_install_names,3367 .headerpad_max_install_names = headerpad_max_install_names,
3202 .dead_strip_dylibs = dead_strip_dylibs,3368 .dead_strip_dylibs = dead_strip_dylibs,
...@@ -4069,10 +4235,12 @@ pub fn cmdLibC(gpa: Allocator, args: []const []const u8) !void {...@@ -4069,10 +4235,12 @@ pub fn cmdLibC(gpa: Allocator, args: []const []const u8) !void {
4069 if (!cross_target.isNative()) {4235 if (!cross_target.isNative()) {
4070 fatal("unable to detect libc for non-native target", .{});4236 fatal("unable to detect libc for non-native target", .{});
4071 }4237 }
4238 const target_info = try detectNativeTargetInfo(cross_target);
40724239
4073 var libc = LibCInstallation.findNative(.{4240 var libc = LibCInstallation.findNative(.{
4074 .allocator = gpa,4241 .allocator = gpa,
4075 .verbose = true,4242 .verbose = true,
4243 .target = target_info.target,
4076 }) catch |err| {4244 }) catch |err| {
4077 fatal("unable to detect native libc: {s}", .{@errorName(err)});4245 fatal("unable to detect native libc: {s}", .{@errorName(err)});
4078 };4246 };
...@@ -6068,3 +6236,83 @@ fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {...@@ -6068,3 +6236,83 @@ fn renderOptions(color: Color) std.zig.ErrorBundle.RenderOptions {
6068 .include_reference_trace = ttyconf != .no_color,6236 .include_reference_trace = ttyconf != .no_color,
6069 };6237 };
6070}6238}
6239
6240fn accessLibPath(
6241 test_path: *std.ArrayList(u8),
6242 checked_paths: *std.ArrayList(u8),
6243 lib_dir_path: []const u8,
6244 lib_name: []const u8,
6245 target: std.Target,
6246 link_mode: std.builtin.LinkMode,
6247) !bool {
6248 const sep = fs.path.sep_str;
6249
6250 if (target.isDarwin() and link_mode == .Dynamic) tbd: {
6251 // Prefer .tbd over .dylib.
6252 test_path.clearRetainingCapacity();
6253 try test_path.writer().print("{s}" ++ sep ++ "lib{s}.tbd", .{ lib_dir_path, lib_name });
6254 try checked_paths.writer().print("\n {s}", .{test_path.items});
6255 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
6256 error.FileNotFound => break :tbd,
6257 else => |e| fatal("unable to search for tbd library '{s}': {s}", .{
6258 test_path.items, @errorName(e),
6259 }),
6260 };
6261 return true;
6262 }
6263
6264 main_check: {
6265 test_path.clearRetainingCapacity();
6266 try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{
6267 lib_dir_path,
6268 target.libPrefix(),
6269 lib_name,
6270 switch (link_mode) {
6271 .Static => target.staticLibSuffix(),
6272 .Dynamic => target.dynamicLibSuffix(),
6273 },
6274 });
6275 try checked_paths.writer().print("\n {s}", .{test_path.items});
6276 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
6277 error.FileNotFound => break :main_check,
6278 else => |e| fatal("unable to search for {s} library '{s}': {s}", .{
6279 @tagName(link_mode), test_path.items, @errorName(e),
6280 }),
6281 };
6282 return true;
6283 }
6284
6285 // In the case of Darwin, the main check will be .dylib, so here we
6286 // additionally check for .so files.
6287 if (target.isDarwin() and link_mode == .Dynamic) so: {
6288 test_path.clearRetainingCapacity();
6289 try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, lib_name });
6290 try checked_paths.writer().print("\n {s}", .{test_path.items});
6291 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
6292 error.FileNotFound => break :so,
6293 else => |e| fatal("unable to search for so library '{s}': {s}", .{
6294 test_path.items, @errorName(e),
6295 }),
6296 };
6297 return true;
6298 }
6299
6300 // In the case of MinGW, the main check will be .lib but we also need to
6301 // look for `libfoo.a`.
6302 if (target.isMinGW() and link_mode == .Static) mingw: {
6303 test_path.clearRetainingCapacity();
6304 try test_path.writer().print("{s}" ++ sep ++ "lib{s}.a", .{
6305 lib_dir_path, lib_name,
6306 });
6307 try checked_paths.writer().print("\n {s}", .{test_path.items});
6308 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
6309 error.FileNotFound => break :mingw,
6310 else => |e| fatal("unable to search for static library '{s}': {s}", .{
6311 test_path.items, @errorName(e),
6312 }),
6313 };
6314 return true;
6315 }
6316
6317 return false;
6318}
src/mingw.zig+25-7
...@@ -283,7 +283,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -283,7 +283,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
283 defer arena_allocator.deinit();283 defer arena_allocator.deinit();
284 const arena = arena_allocator.allocator();284 const arena = arena_allocator.allocator();
285285
286 const def_file_path = findDef(comp, arena, lib_name) catch |err| switch (err) {286 const def_file_path = findDef(arena, comp.getTarget(), comp.zig_lib_directory, lib_name) catch |err| switch (err) {
287 error.FileNotFound => {287 error.FileNotFound => {
288 log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name });288 log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name });
289 // In this case we will end up putting foo.lib onto the linker line and letting the linker289 // In this case we will end up putting foo.lib onto the linker line and letting the linker
...@@ -431,10 +431,28 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {...@@ -431,10 +431,28 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
431 });431 });
432}432}
433433
434/// This function body is verbose but all it does is test 3 different paths and see if a .def file exists.434pub fn libExists(
435fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8 {435 allocator: Allocator,
436 const target = comp.getTarget();436 target: std.Target,
437 zig_lib_directory: Cache.Directory,
438 lib_name: []const u8,
439) !bool {
440 const s = findDef(allocator, target, zig_lib_directory, lib_name) catch |err| switch (err) {
441 error.FileNotFound => return false,
442 else => |e| return e,
443 };
444 defer allocator.free(s);
445 return true;
446}
437447
448/// This function body is verbose but all it does is test 3 different paths and
449/// see if a .def file exists.
450fn findDef(
451 allocator: Allocator,
452 target: std.Target,
453 zig_lib_directory: Cache.Directory,
454 lib_name: []const u8,
455) ![]u8 {
438 const lib_path = switch (target.cpu.arch) {456 const lib_path = switch (target.cpu.arch) {
439 .x86 => "lib32",457 .x86 => "lib32",
440 .x86_64 => "lib64",458 .x86_64 => "lib64",
...@@ -451,7 +469,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8...@@ -451,7 +469,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8
451 {469 {
452 // Try the archtecture-specific path first.470 // Try the archtecture-specific path first.
453 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def";471 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "{s}" ++ s ++ "{s}.def";
454 if (comp.zig_lib_directory.path) |p| {472 if (zig_lib_directory.path) |p| {
455 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name });473 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_path, lib_name });
456 } else {474 } else {
457 try override_path.writer().print(fmt_path, .{ lib_path, lib_name });475 try override_path.writer().print(fmt_path, .{ lib_path, lib_name });
...@@ -468,7 +486,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8...@@ -468,7 +486,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8
468 // Try the generic version.486 // Try the generic version.
469 override_path.shrinkRetainingCapacity(0);487 override_path.shrinkRetainingCapacity(0);
470 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def";488 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def";
471 if (comp.zig_lib_directory.path) |p| {489 if (zig_lib_directory.path) |p| {
472 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });490 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
473 } else {491 } else {
474 try override_path.writer().print(fmt_path, .{lib_name});492 try override_path.writer().print(fmt_path, .{lib_name});
...@@ -485,7 +503,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8...@@ -485,7 +503,7 @@ fn findDef(comp: *Compilation, allocator: Allocator, lib_name: []const u8) ![]u8
485 // Try the generic version and preprocess it.503 // Try the generic version and preprocess it.
486 override_path.shrinkRetainingCapacity(0);504 override_path.shrinkRetainingCapacity(0);
487 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in";505 const fmt_path = "libc" ++ s ++ "mingw" ++ s ++ "lib-common" ++ s ++ "{s}.def.in";
488 if (comp.zig_lib_directory.path) |p| {506 if (zig_lib_directory.path) |p| {
489 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });507 try override_path.writer().print("{s}" ++ s ++ fmt_path, .{ p, lib_name });
490 } else {508 } else {
491 try override_path.writer().print(fmt_path, .{lib_name});509 try override_path.writer().print(fmt_path, .{lib_name});
src/target.zig+9
...@@ -366,6 +366,15 @@ pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {...@@ -366,6 +366,15 @@ pub fn is_libc_lib_name(target: std.Target, name: []const u8) bool {
366 if (eqlIgnoreCase(ignore_case, name, "m"))366 if (eqlIgnoreCase(ignore_case, name, "m"))
367 return true;367 return true;
368368
369 if (eqlIgnoreCase(ignore_case, name, "uuid"))
370 return true;
371 if (eqlIgnoreCase(ignore_case, name, "mingw32"))
372 return true;
373 if (eqlIgnoreCase(ignore_case, name, "msvcrt-os"))
374 return true;
375 if (eqlIgnoreCase(ignore_case, name, "mingwex"))
376 return true;
377
369 return false;378 return false;
370 }379 }
371380
test/link/macho/bugs/13056/build.zig+1-1
...@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {...@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) void {
16fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {16fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.OptimizeMode) void {
17 const target: std.zig.CrossTarget = .{ .os_tag = .macos };17 const target: std.zig.CrossTarget = .{ .os_tag = .macos };
18 const target_info = std.zig.system.NativeTargetInfo.detect(target) catch unreachable;18 const target_info = std.zig.system.NativeTargetInfo.detect(target) catch unreachable;
19 const sdk = std.zig.system.darwin.getDarwinSDK(b.allocator, target_info.target) orelse19 const sdk = std.zig.system.darwin.getSdk(b.allocator, target_info.target) orelse
20 @panic("macOS SDK is required to run the test");20 @panic("macOS SDK is required to run the test");
2121
22 const exe = b.addExecutable(.{22 const exe = b.addExecutable(.{
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());