From fd006c1c74a43827a6f1c32e289ba57cafa874be Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Feb 2020 17:20:40 -0500 Subject: [PATCH] std.zig.system.NativeTargetInfo.detect: almost no Allocator --- lib/std/process.zig | 4 +++ lib/std/target.zig | 12 ++++---- lib/std/zig/system.zig | 62 ++++++++++++++++++-------------------- src-self-hosted/stage2.zig | 4 +-- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/lib/std/process.zig b/lib/std/process.zig index 118b5d9ab4..01b9947518 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -609,6 +609,10 @@ pub fn getBaseAddress() usize { } /// Caller owns the result value and each inner slice. +/// TODO Remove the `Allocator` requirement from this API, which will remove the `Allocator` +/// requirement from `std.zig.system.NativeTargetInfo.detect`. Most likely this will require +/// introducing a new, lower-level function which takes a callback function, and then this +/// function which takes an allocator can exist on top of it. pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 { switch (builtin.link_mode) { .Static => return &[_][:0]u8{}, diff --git a/lib/std/target.zig b/lib/std/target.zig index 33019b6bbe..379ae72afe 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1084,16 +1084,16 @@ pub const Target = struct { } } - /// The result will be a slice of `buffer`, pointing at position 0. + /// The result will be a byte index *pointing at the final byte*. In other words, length minus one. /// A return value of `null` means the concept of a dynamic linker is not meaningful for that target. - pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?[]u8 { + pub fn standardDynamicLinkerPath(self: Target, buffer: *[255]u8) ?u8 { const S = struct { - fn print(b: *[255]u8, comptime fmt: []const u8, args: var) []u8 { - return std.fmt.bufPrint(b, fmt, args) catch unreachable; + fn print(b: *[255]u8, comptime fmt: []const u8, args: var) u8 { + return @intCast(u8, (std.fmt.bufPrint(b, fmt, args) catch unreachable).len - 1); } - fn copy(b: *[255]u8, s: []const u8) []u8 { + fn copy(b: *[255]u8, s: []const u8) u8 { mem.copy(u8, b, s); - return b[0..s.len]; + return @intCast(u8, s.len - 1); } }; const print = S.print; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index d2828a88a1..e8c95f5125 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -189,7 +189,9 @@ pub const NativeTargetInfo = struct { /// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker. /// On Linux, this is additionally responsible for detecting the native glibc version when applicable. - /// TODO Remove the allocator requirement from this. + /// Any resources this function allocates are released before returning, and so there is no + /// deinitialization method. + /// TODO Remove the Allocator requirement from this function. pub fn detect(allocator: *Allocator) DetectError!NativeTargetInfo { const arch = Target.current.cpu.arch; const os_tag = Target.current.os.tag; @@ -203,15 +205,9 @@ pub const NativeTargetInfo = struct { return detectAbiAndDynamicLinker(allocator, cpu, os); } - /// Must be the same `Allocator` passed to `detect`. - pub fn deinit(self: *NativeTargetInfo, allocator: *Allocator) void { - if (self.dynamic_linker) |dl| allocator.free(dl); - self.* = undefined; - } - /// The returned memory has the same lifetime as the `NativeTargetInfo`. pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 { - const m = self.dynamic_linker_max orelse return null; + const m: usize = self.dynamic_linker_max orelse return null; return self.dynamic_linker_buffer[0 .. m + 1]; } @@ -228,13 +224,14 @@ pub const NativeTargetInfo = struct { /// linked, then it should answer both the C ABI question and the dynamic linker question. /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then /// we fall back to the defaults. + /// TODO Remove the Allocator requirement from this function. fn detectAbiAndDynamicLinker( allocator: *Allocator, cpu: Target.Cpu, os: Target.Os, ) DetectError!NativeTargetInfo { if (!comptime Target.current.hasDynamicLinker()) { - return defaultAbiAndDynamicLinker(allocator, cpu, os); + return defaultAbiAndDynamicLinker(cpu, os); } // The current target's ABI cannot be relied on for this. For example, we may build the zig // compiler for target riscv64-linux-musl and provide a tarball for users to download. @@ -242,15 +239,15 @@ pub const NativeTargetInfo = struct { // and supported by Zig. But that means that we must detect the system ABI here rather than // relying on `Target.current`. const LdInfo = struct { - ld_path: []u8, + ld_path_buffer: [255]u8, + ld_path_max: u8, abi: Target.Abi, - }; - var ld_info_list = std.ArrayList(LdInfo).init(allocator); - defer { - for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path); - ld_info_list.deinit(); - } + pub fn ldPath(self: *const @This()) []const u8 { + const m: usize = self.ld_path_max; + return self.ld_path_buffer[0 .. m + 1]; + } + }; const all_abis = comptime blk: { assert(@enumToInt(Target.Abi.none) == 0); const fields = std.meta.fields(Target.Abi)[1..]; @@ -260,6 +257,9 @@ pub const NativeTargetInfo = struct { } break :blk array; }; + var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; + var ld_info_list_len: usize = 0; + for (all_abis) |abi| { // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and // skip adding it to `ld_info_list`. @@ -268,17 +268,17 @@ pub const NativeTargetInfo = struct { .os = os, .abi = abi, }; - var buf: [255]u8 = undefined; - const standard_ld_path = if (target.standardDynamicLinkerPath(&buf)) |s| - try mem.dupe(allocator, u8, s) - else - continue; - errdefer allocator.free(standard_ld_path); - try ld_info_list.append(.{ - .ld_path = standard_ld_path, + const ld_info = &ld_info_list_buffer[ld_info_list_len]; + ld_info_list_len += 1; + + ld_info.* = .{ + .ld_path_buffer = undefined, + .ld_path_max = undefined, .abi = abi, - }); + }; + ld_info.ld_path_max = target.standardDynamicLinkerPath(&ld_info.ld_path_buffer) orelse continue; } + const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; // Best case scenario: the executable is dynamically linked, and we can iterate // over our own shared objects and find a dynamic linker. @@ -292,8 +292,8 @@ pub const NativeTargetInfo = struct { // Look for dynamic linker. // This is O(N^M) but typical case here is N=2 and M=10. find_ld: for (lib_paths) |lib_path| { - for (ld_info_list.toSlice()) |ld_info| { - const standard_ld_basename = fs.path.basename(ld_info.ld_path); + for (ld_info_list) |ld_info| { + const standard_ld_basename = fs.path.basename(ld_info.ldPath()); if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) { found_ld_info = ld_info; found_ld_path = lib_path; @@ -355,7 +355,7 @@ pub const NativeTargetInfo = struct { error.UnexpectedEndOfFile, error.NameTooLong, // Finally, we fall back on the standard path. - => defaultAbiAndDynamicLinker(allocator, cpu, os), + => defaultAbiAndDynamicLinker(cpu, os), }; } @@ -502,7 +502,7 @@ pub const NativeTargetInfo = struct { }; } - fn defaultAbiAndDynamicLinker(allocator: *Allocator, cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { + fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { var result: NativeTargetInfo = .{ .target = .{ .cpu = cpu, @@ -510,9 +510,7 @@ pub const NativeTargetInfo = struct { .abi = Target.Abi.default(cpu.arch, os), }, }; - if (result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer)) |s| { - result.dynamic_linker_max = @intCast(u8, s.len - 1); - } + result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer); return result; } }; diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 5358c4fedc..cd3f49edfa 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1170,8 +1170,8 @@ fn crossTargetToTarget(cross_target: CrossTarget, dynamic_linker_ptr: *?[*:0]u8) } if (!have_native_dl) { var buf: [255]u8 = undefined; - dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |s| - try mem.dupeZ(std.heap.c_allocator, u8, s) + dynamic_linker_ptr.* = if (adjusted_target.standardDynamicLinkerPath(&buf)) |m| + try mem.dupeZ(std.heap.c_allocator, u8, buf[0 .. @as(usize, m) + 1]) else null; }