aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/Build/Step/Compile.zig139
-rw-r--r--lib/std/zig/system/NativePaths.zig106
-rw-r--r--lib/std/zig/system/darwin.zig54
3 files changed, 124 insertions, 175 deletions
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index 89cc2ecfd9..335a7e2df7 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -149,13 +149,6 @@ entitlements: ?[]const u8 = null,
/// (Darwin) Size of the pagezero segment.
pagezero_size: ?u64 = null,
-/// (Darwin) Search strategy for searching system libraries. Either `paths_first` or `dylibs_first`.
-/// The former lowers to `-search_paths_first` linker option, while the latter to `-search_dylibs_first`
-/// option.
-/// By default, if no option is specified, the linker assumes `paths_first` as the default
-/// search strategy.
-search_strategy: ?enum { paths_first, dylibs_first } = null,
-
/// (Darwin) Set size of the padding between the end of load commands
/// and start of `__TEXT,__text` section.
headerpad_size: ?u32 = null,
@@ -242,7 +235,11 @@ pub const SystemLib = struct {
name: []const u8,
needed: bool,
weak: bool,
- use_pkg_config: enum {
+ use_pkg_config: UsePkgConfig,
+ preferred_link_mode: std.builtin.LinkMode,
+ search_strategy: SystemLib.SearchStrategy,
+
+ pub const UsePkgConfig = enum {
/// Don't use pkg-config, just pass -lfoo where foo is name.
no,
/// Try to get information on how to link the library from pkg-config.
@@ -251,7 +248,9 @@ pub const SystemLib = struct {
/// Try to get information on how to link the library from pkg-config.
/// If that fails, error out.
force,
- },
+ };
+
+ pub const SearchStrategy = enum { paths_first, mode_first, no_fallback };
};
const FrameworkLinkInfo = struct {
@@ -718,74 +717,29 @@ pub fn defineCMacroRaw(self: *Compile, name_and_value: []const u8) void {
self.c_macros.append(b.dupe(name_and_value)) catch @panic("OOM");
}
-/// This one has no integration with anything, it just puts -lname on the command line.
-/// Prefer to use `linkSystemLibrary` instead.
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryName(self: *Compile, name: []const u8) void {
- const b = self.step.owner;
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(name),
- .needed = false,
- .weak = false,
- .use_pkg_config = .no,
- },
- }) catch @panic("OOM");
+ return linkSystemLibrary2(self, name, .{ .use_pkg_config = .no });
}
-/// This one has no integration with anything, it just puts -needed-lname on the command line.
-/// Prefer to use `linkSystemLibraryNeeded` instead.
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryNeededName(self: *Compile, name: []const u8) void {
- const b = self.step.owner;
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(name),
- .needed = true,
- .weak = false,
- .use_pkg_config = .no,
- },
- }) catch @panic("OOM");
+ return linkSystemLibrary2(self, name, .{ .needed = true, .use_pkg_config = .no });
}
-/// Darwin-only. This one has no integration with anything, it just puts -weak-lname on the
-/// command line. Prefer to use `linkSystemLibraryWeak` instead.
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryWeakName(self: *Compile, name: []const u8) void {
- const b = self.step.owner;
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(name),
- .needed = false,
- .weak = true,
- .use_pkg_config = .no,
- },
- }) catch @panic("OOM");
+ return linkSystemLibrary2(self, name, .{ .weak = true, .use_pkg_config = .no });
}
-/// This links against a system library, exclusively using pkg-config to find the library.
-/// Prefer to use `linkSystemLibrary` instead.
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
- const b = self.step.owner;
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(lib_name),
- .needed = false,
- .weak = false,
- .use_pkg_config = .force,
- },
- }) catch @panic("OOM");
+ return linkSystemLibrary2(self, lib_name, .{ .use_pkg_config = .force });
}
-/// This links against a system library, exclusively using pkg-config to find the library.
-/// Prefer to use `linkSystemLibraryNeeded` instead.
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryNeededPkgConfigOnly(self: *Compile, lib_name: []const u8) void {
- const b = self.step.owner;
- self.link_objects.append(.{
- .system_lib = .{
- .name = b.dupe(lib_name),
- .needed = true,
- .weak = false,
- .use_pkg_config = .force,
- },
- }) catch @panic("OOM");
+ return linkSystemLibrary2(self, lib_name, .{ .needed = true, .use_pkg_config = .force });
}
/// 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 {
}
pub fn linkSystemLibrary(self: *Compile, name: []const u8) void {
- self.linkSystemLibraryInner(name, .{});
+ self.linkSystemLibrary2(name, .{});
}
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryNeeded(self: *Compile, name: []const u8) void {
- self.linkSystemLibraryInner(name, .{ .needed = true });
+ return linkSystemLibrary2(self, name, .{ .needed = true });
}
+/// deprecated: use linkSystemLibrary2
pub fn linkSystemLibraryWeak(self: *Compile, name: []const u8) void {
- self.linkSystemLibraryInner(name, .{ .weak = true });
+ return linkSystemLibrary2(self, name, .{ .weak = true });
}
-fn linkSystemLibraryInner(self: *Compile, name: []const u8, opts: struct {
+pub const LinkSystemLibraryOptions = struct {
needed: bool = false,
weak: bool = false,
-}) void {
+ use_pkg_config: SystemLib.UsePkgConfig = .yes,
+ preferred_link_mode: std.builtin.LinkMode = .Dynamic,
+ search_strategy: SystemLib.SearchStrategy = .paths_first,
+};
+
+pub fn linkSystemLibrary2(
+ self: *Compile,
+ name: []const u8,
+ options: LinkSystemLibraryOptions,
+) void {
const b = self.step.owner;
if (isLibCLibrary(name)) {
self.linkLibC();
@@ -913,9 +878,11 @@ fn linkSystemLibraryInner(self: *Compile, name: []const u8, opts: struct {
self.link_objects.append(.{
.system_lib = .{
.name = b.dupe(name),
- .needed = opts.needed,
- .weak = opts.weak,
- .use_pkg_config = .yes,
+ .needed = options.needed,
+ .weak = options.weak,
+ .use_pkg_config = options.use_pkg_config,
+ .preferred_link_mode = options.preferred_link_mode,
+ .search_strategy = options.search_strategy,
},
}) catch @panic("OOM");
}
@@ -1385,6 +1352,8 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
try transitive_deps.add(self.link_objects.items);
var prev_has_cflags = false;
+ var prev_search_strategy: SystemLib.SearchStrategy = .paths_first;
+ var prev_preferred_link_mode: std.builtin.LinkMode = .Dynamic;
for (transitive_deps.link_objects.items) |link_object| {
switch (link_object) {
@@ -1420,6 +1389,28 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
},
.system_lib => |system_lib| {
+ if ((system_lib.search_strategy != prev_search_strategy or
+ system_lib.preferred_link_mode != prev_preferred_link_mode) and
+ self.linkage != .static)
+ {
+ switch (system_lib.search_strategy) {
+ .no_fallback => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_dylibs_only"),
+ .Static => try zig_args.append("-search_static_only"),
+ },
+ .paths_first => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_paths_first"),
+ .Static => try zig_args.append("-search_paths_first_static"),
+ },
+ .mode_first => switch (system_lib.preferred_link_mode) {
+ .Dynamic => try zig_args.append("-search_dylibs_first"),
+ .Static => try zig_args.append("-search_static_first"),
+ },
+ }
+ prev_search_strategy = system_lib.search_strategy;
+ prev_preferred_link_mode = system_lib.preferred_link_mode;
+ }
+
const prefix: []const u8 = prefix: {
if (system_lib.needed) break :prefix "-needed-l";
if (system_lib.weak) break :prefix "-weak-l";
@@ -1662,10 +1653,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
const size = try std.fmt.allocPrint(b.allocator, "{x}", .{pagezero_size});
try zig_args.appendSlice(&[_][]const u8{ "-pagezero_size", size });
}
- if (self.search_strategy) |strat| switch (strat) {
- .paths_first => try zig_args.append("-search_paths_first"),
- .dylibs_first => try zig_args.append("-search_dylibs_first"),
- };
if (self.headerpad_size) |headerpad_size| {
const size = try std.fmt.allocPrint(b.allocator, "{x}", .{headerpad_size});
try zig_args.appendSlice(&[_][]const u8{ "-headerpad", size });
diff --git a/lib/std/zig/system/NativePaths.zig b/lib/std/zig/system/NativePaths.zig
index f9798695ad..4c8f1286b8 100644
--- a/lib/std/zig/system/NativePaths.zig
+++ b/lib/std/zig/system/NativePaths.zig
@@ -1,6 +1,5 @@
const std = @import("../../std.zig");
const builtin = @import("builtin");
-const ArrayList = std.ArrayList;
const Allocator = std.mem.Allocator;
const process = std.process;
const mem = std.mem;
@@ -8,28 +7,18 @@ const mem = std.mem;
const NativePaths = @This();
const NativeTargetInfo = std.zig.system.NativeTargetInfo;
-include_dirs: ArrayList([:0]u8),
-lib_dirs: ArrayList([:0]u8),
-framework_dirs: ArrayList([:0]u8),
-rpaths: ArrayList([:0]u8),
-warnings: ArrayList([:0]u8),
+arena: Allocator,
+include_dirs: std.ArrayListUnmanaged([]const u8) = .{},
+lib_dirs: std.ArrayListUnmanaged([]const u8) = .{},
+framework_dirs: std.ArrayListUnmanaged([]const u8) = .{},
+rpaths: std.ArrayListUnmanaged([]const u8) = .{},
+warnings: std.ArrayListUnmanaged([]const u8) = .{},
-pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths {
+pub fn detect(arena: Allocator, native_info: NativeTargetInfo) !NativePaths {
const native_target = native_info.target;
-
- var self: NativePaths = .{
- .include_dirs = ArrayList([:0]u8).init(allocator),
- .lib_dirs = ArrayList([:0]u8).init(allocator),
- .framework_dirs = ArrayList([:0]u8).init(allocator),
- .rpaths = ArrayList([:0]u8).init(allocator),
- .warnings = ArrayList([:0]u8).init(allocator),
- };
- errdefer self.deinit();
-
+ var self: NativePaths = .{ .arena = arena };
var is_nix = false;
- if (process.getEnvVarOwned(allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
- defer allocator.free(nix_cflags_compile);
-
+ if (process.getEnvVarOwned(arena, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
is_nix = true;
var it = mem.tokenizeScalar(u8, nix_cflags_compile, ' ');
while (true) {
@@ -58,9 +47,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
error.EnvironmentVariableNotFound => {},
error.OutOfMemory => |e| return e,
}
- if (process.getEnvVarOwned(allocator, "NIX_LDFLAGS")) |nix_ldflags| {
- defer allocator.free(nix_ldflags);
-
+ if (process.getEnvVarOwned(arena, "NIX_LDFLAGS")) |nix_ldflags| {
is_nix = true;
var it = mem.tokenizeScalar(u8, nix_ldflags, ' ');
while (true) {
@@ -89,17 +76,16 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
return self;
}
+ // TODO: consider also adding homebrew paths
+ // TODO: consider also adding macports paths
if (comptime builtin.target.isDarwin()) {
- try self.addIncludeDir("/usr/include");
- try self.addLibDir("/usr/lib");
- try self.addFrameworkDir("/System/Library/Frameworks");
-
- if (builtin.target.os.version_range.semver.min.major < 11) {
- try self.addIncludeDir("/usr/local/include");
- try self.addLibDir("/usr/local/lib");
- try self.addFrameworkDir("/Library/Frameworks");
+ if (std.zig.system.darwin.isSdkInstalled(arena)) sdk: {
+ const sdk = std.zig.system.darwin.getSdk(arena, native_target) orelse break :sdk;
+ try self.addLibDir(try std.fs.path.join(arena, &.{ sdk.path, "usr/lib" }));
+ try self.addFrameworkDir(try std.fs.path.join(arena, &.{ sdk.path, "System/Library/Frameworks" }));
+ try self.addIncludeDir(try std.fs.path.join(arena, &.{ sdk.path, "usr/include" }));
+ return self;
}
-
return self;
}
@@ -115,8 +101,7 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
}
if (builtin.os.tag != .windows) {
- const triple = try native_target.linuxTriple(allocator);
- defer allocator.free(triple);
+ const triple = try native_target.linuxTriple(arena);
const qual = native_target.ptrBitWidth();
@@ -172,69 +157,42 @@ pub fn detect(allocator: Allocator, native_info: NativeTargetInfo) !NativePaths
return self;
}
-pub fn deinit(self: *NativePaths) void {
- deinitArray(&self.include_dirs);
- deinitArray(&self.lib_dirs);
- deinitArray(&self.framework_dirs);
- deinitArray(&self.rpaths);
- deinitArray(&self.warnings);
- self.* = undefined;
-}
-
-fn deinitArray(array: *ArrayList([:0]u8)) void {
- for (array.items) |item| {
- array.allocator.free(item);
- }
- array.deinit();
-}
-
pub fn addIncludeDir(self: *NativePaths, s: []const u8) !void {
- return self.appendArray(&self.include_dirs, s);
+ return self.include_dirs.append(self.arena, s);
}
pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
- const item = try std.fmt.allocPrintZ(self.include_dirs.allocator, fmt, args);
- errdefer self.include_dirs.allocator.free(item);
- try self.include_dirs.append(item);
+ const item = try std.fmt.allocPrint(self.arena, fmt, args);
+ try self.include_dirs.append(self.arena, item);
}
pub fn addLibDir(self: *NativePaths, s: []const u8) !void {
- return self.appendArray(&self.lib_dirs, s);
+ try self.lib_dirs.append(self.arena, s);
}
pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
- const item = try std.fmt.allocPrintZ(self.lib_dirs.allocator, fmt, args);
- errdefer self.lib_dirs.allocator.free(item);
- try self.lib_dirs.append(item);
+ const item = try std.fmt.allocPrint(self.arena, fmt, args);
+ try self.lib_dirs.append(self.arena, item);
}
pub fn addWarning(self: *NativePaths, s: []const u8) !void {
- return self.appendArray(&self.warnings, s);
+ return self.warnings.append(self.arena, s);
}
pub fn addFrameworkDir(self: *NativePaths, s: []const u8) !void {
- return self.appendArray(&self.framework_dirs, s);
+ return self.framework_dirs.append(self.arena, s);
}
pub fn addFrameworkDirFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
- const item = try std.fmt.allocPrintZ(self.framework_dirs.allocator, fmt, args);
- errdefer self.framework_dirs.allocator.free(item);
- try self.framework_dirs.append(item);
+ const item = try std.fmt.allocPrint(self.arena, fmt, args);
+ try self.framework_dirs.append(self.arena, item);
}
pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: anytype) !void {
- const item = try std.fmt.allocPrintZ(self.warnings.allocator, fmt, args);
- errdefer self.warnings.allocator.free(item);
- try self.warnings.append(item);
+ const item = try std.fmt.allocPrint(self.arena, fmt, args);
+ try self.warnings.append(self.arena, item);
}
pub fn addRPath(self: *NativePaths, s: []const u8) !void {
- return self.appendArray(&self.rpaths, s);
-}
-
-fn appendArray(self: *NativePaths, array: *ArrayList([:0]u8), s: []const u8) !void {
- _ = self;
- const item = try array.allocator.dupeZ(u8, s);
- errdefer array.allocator.free(item);
- try array.append(item);
+ try self.rpaths.append(self.arena, s);
}
diff --git a/lib/std/zig/system/darwin.zig b/lib/std/zig/system/darwin.zig
index e29dc68d64..992c0d814d 100644
--- a/lib/std/zig/system/darwin.zig
+++ b/lib/std/zig/system/darwin.zig
@@ -8,28 +8,34 @@ pub const macos = @import("darwin/macos.zig");
/// Check if SDK is installed on Darwin without triggering CLT installation popup window.
/// Note: simply invoking `xcrun` will inevitably trigger the CLT installation popup.
-/// Therefore, we resort to the same tool used by Homebrew, namely, invoking `xcode-select --print-path`
-/// and checking if the status is nonzero or the returned string in nonempty.
-/// https://github.com/Homebrew/brew/blob/e119bdc571dcb000305411bc1e26678b132afb98/Library/Homebrew/brew.sh#L630
-pub fn isDarwinSDKInstalled(allocator: Allocator) bool {
- const argv = &[_][]const u8{ "/usr/bin/xcode-select", "--print-path" };
- const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return false;
+/// Therefore, we resort to invoking `xcode-select --print-path` and checking
+/// if the status is nonzero.
+/// stderr from xcode-select is ignored.
+/// If error.OutOfMemory occurs in Allocator, this function returns null.
+pub fn isSdkInstalled(allocator: Allocator) bool {
+ const result = std.process.Child.exec(.{
+ .allocator = allocator,
+ .argv = &.{ "/usr/bin/xcode-select", "--print-path" },
+ }) catch return false;
+
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
- if (result.stderr.len != 0 or result.term.Exited != 0) {
- // We don't actually care if there were errors as this is best-effort check anyhow.
- return false;
- }
- return result.stdout.len > 0;
+
+ return switch (result.term) {
+ .Exited => |code| if (code == 0) result.stdout.len > 0 else false,
+ else => false,
+ };
}
/// Detect SDK on Darwin.
/// Calls `xcrun --sdk <target_sdk> --show-sdk-path` which fetches the path to the SDK sysroot (if any).
/// Subsequently calls `xcrun --sdk <target_sdk> --show-sdk-version` which fetches version of the SDK.
/// The caller needs to deinit the resulting struct.
-pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {
+/// stderr from xcrun is ignored.
+/// If error.OutOfMemory occurs in Allocator, this function returns null.
+pub fn getSdk(allocator: Allocator, target: Target) ?Sdk {
const is_simulator_abi = target.abi == .simulator;
const sdk = switch (target.os.tag) {
.macos => "macosx",
@@ -40,30 +46,28 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {
};
const path = path: {
const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-path" };
- const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
+ const result = std.process.Child.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
- if (result.stderr.len != 0 or result.term.Exited != 0) {
- // We don't actually care if there were errors as this is best-effort check anyhow
- // and in the worst case the user can specify the sysroot manually.
- return null;
+ switch (result.term) {
+ .Exited => |code| if (code != 0) return null,
+ else => return null,
}
const path = allocator.dupe(u8, mem.trimRight(u8, result.stdout, "\r\n")) catch return null;
break :path path;
};
const version = version: {
const argv = &[_][]const u8{ "/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-version" };
- const result = std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
+ const result = std.process.Child.exec(.{ .allocator = allocator, .argv = argv }) catch return null;
defer {
allocator.free(result.stderr);
allocator.free(result.stdout);
}
- if (result.stderr.len != 0 or result.term.Exited != 0) {
- // We don't actually care if there were errors as this is best-effort check anyhow
- // and in the worst case the user can specify the sysroot manually.
- return null;
+ switch (result.term) {
+ .Exited => |code| if (code != 0) return null,
+ else => return null,
}
const raw_version = mem.trimRight(u8, result.stdout, "\r\n");
const version = parseSdkVersion(raw_version) orelse Version{
@@ -73,7 +77,7 @@ pub fn getDarwinSDK(allocator: Allocator, target: Target) ?DarwinSDK {
};
break :version version;
};
- return DarwinSDK{
+ return Sdk{
.path = path,
.version = version,
};
@@ -96,11 +100,11 @@ fn parseSdkVersion(raw: []const u8) ?Version {
return Version.parse(buffer[0..len]) catch null;
}
-pub const DarwinSDK = struct {
+pub const Sdk = struct {
path: []const u8,
version: Version,
- pub fn deinit(self: DarwinSDK, allocator: Allocator) void {
+ pub fn deinit(self: Sdk, allocator: Allocator) void {
allocator.free(self.path);
}
};