| ... | ... | @@ -189,7 +189,9 @@ pub const NativeTargetInfo = struct { |
| 189 | 189 | |
| 190 | 190 | /// Detects the native CPU model & features, operating system & version, and C ABI & dynamic linker. |
| 191 | 191 | /// On Linux, this is additionally responsible for detecting the native glibc version when applicable. |
| 192 | | /// TODO Remove the allocator requirement from this. |
| 192 | /// Any resources this function allocates are released before returning, and so there is no |
| 193 | /// deinitialization method. |
| 194 | /// TODO Remove the Allocator requirement from this function. |
| 193 | 195 | pub fn detect(allocator: *Allocator) DetectError!NativeTargetInfo { |
| 194 | 196 | const arch = Target.current.cpu.arch; |
| 195 | 197 | const os_tag = Target.current.os.tag; |
| ... | ... | @@ -203,15 +205,9 @@ pub const NativeTargetInfo = struct { |
| 203 | 205 | return detectAbiAndDynamicLinker(allocator, cpu, os); |
| 204 | 206 | } |
| 205 | 207 | |
| 206 | | /// Must be the same `Allocator` passed to `detect`. |
| 207 | | pub fn deinit(self: *NativeTargetInfo, allocator: *Allocator) void { |
| 208 | | if (self.dynamic_linker) |dl| allocator.free(dl); |
| 209 | | self.* = undefined; |
| 210 | | } |
| 211 | | |
| 212 | 208 | /// The returned memory has the same lifetime as the `NativeTargetInfo`. |
| 213 | 209 | pub fn dynamicLinker(self: *const NativeTargetInfo) ?[]const u8 { |
| 214 | | const m = self.dynamic_linker_max orelse return null; |
| 210 | const m: usize = self.dynamic_linker_max orelse return null; |
| 215 | 211 | return self.dynamic_linker_buffer[0 .. m + 1]; |
| 216 | 212 | } |
| 217 | 213 | |
| ... | ... | @@ -228,13 +224,14 @@ pub const NativeTargetInfo = struct { |
| 228 | 224 | /// linked, then it should answer both the C ABI question and the dynamic linker question. |
| 229 | 225 | /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then |
| 230 | 226 | /// we fall back to the defaults. |
| 227 | /// TODO Remove the Allocator requirement from this function. |
| 231 | 228 | fn detectAbiAndDynamicLinker( |
| 232 | 229 | allocator: *Allocator, |
| 233 | 230 | cpu: Target.Cpu, |
| 234 | 231 | os: Target.Os, |
| 235 | 232 | ) DetectError!NativeTargetInfo { |
| 236 | 233 | if (!comptime Target.current.hasDynamicLinker()) { |
| 237 | | return defaultAbiAndDynamicLinker(allocator, cpu, os); |
| 234 | return defaultAbiAndDynamicLinker(cpu, os); |
| 238 | 235 | } |
| 239 | 236 | // The current target's ABI cannot be relied on for this. For example, we may build the zig |
| 240 | 237 | // compiler for target riscv64-linux-musl and provide a tarball for users to download. |
| ... | ... | @@ -242,15 +239,15 @@ pub const NativeTargetInfo = struct { |
| 242 | 239 | // and supported by Zig. But that means that we must detect the system ABI here rather than |
| 243 | 240 | // relying on `Target.current`. |
| 244 | 241 | const LdInfo = struct { |
| 245 | | ld_path: []u8, |
| 242 | ld_path_buffer: [255]u8, |
| 243 | ld_path_max: u8, |
| 246 | 244 | abi: Target.Abi, |
| 247 | | }; |
| 248 | | var ld_info_list = std.ArrayList(LdInfo).init(allocator); |
| 249 | | defer { |
| 250 | | for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path); |
| 251 | | ld_info_list.deinit(); |
| 252 | | } |
| 253 | 245 | |
| 246 | pub fn ldPath(self: *const @This()) []const u8 { |
| 247 | const m: usize = self.ld_path_max; |
| 248 | return self.ld_path_buffer[0 .. m + 1]; |
| 249 | } |
| 250 | }; |
| 254 | 251 | const all_abis = comptime blk: { |
| 255 | 252 | assert(@enumToInt(Target.Abi.none) == 0); |
| 256 | 253 | const fields = std.meta.fields(Target.Abi)[1..]; |
| ... | ... | @@ -260,6 +257,9 @@ pub const NativeTargetInfo = struct { |
| 260 | 257 | } |
| 261 | 258 | break :blk array; |
| 262 | 259 | }; |
| 260 | var ld_info_list_buffer: [all_abis.len]LdInfo = undefined; |
| 261 | var ld_info_list_len: usize = 0; |
| 262 | |
| 263 | 263 | for (all_abis) |abi| { |
| 264 | 264 | // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and |
| 265 | 265 | // skip adding it to `ld_info_list`. |
| ... | ... | @@ -268,17 +268,17 @@ pub const NativeTargetInfo = struct { |
| 268 | 268 | .os = os, |
| 269 | 269 | .abi = abi, |
| 270 | 270 | }; |
| 271 | | var buf: [255]u8 = undefined; |
| 272 | | const standard_ld_path = if (target.standardDynamicLinkerPath(&buf)) |s| |
| 273 | | try mem.dupe(allocator, u8, s) |
| 274 | | else |
| 275 | | continue; |
| 276 | | errdefer allocator.free(standard_ld_path); |
| 277 | | try ld_info_list.append(.{ |
| 278 | | .ld_path = standard_ld_path, |
| 271 | const ld_info = &ld_info_list_buffer[ld_info_list_len]; |
| 272 | ld_info_list_len += 1; |
| 273 | |
| 274 | ld_info.* = .{ |
| 275 | .ld_path_buffer = undefined, |
| 276 | .ld_path_max = undefined, |
| 279 | 277 | .abi = abi, |
| 280 | | }); |
| 278 | }; |
| 279 | ld_info.ld_path_max = target.standardDynamicLinkerPath(&ld_info.ld_path_buffer) orelse continue; |
| 281 | 280 | } |
| 281 | const ld_info_list = ld_info_list_buffer[0..ld_info_list_len]; |
| 282 | 282 | |
| 283 | 283 | // Best case scenario: the executable is dynamically linked, and we can iterate |
| 284 | 284 | // over our own shared objects and find a dynamic linker. |
| ... | ... | @@ -292,8 +292,8 @@ pub const NativeTargetInfo = struct { |
| 292 | 292 | // Look for dynamic linker. |
| 293 | 293 | // This is O(N^M) but typical case here is N=2 and M=10. |
| 294 | 294 | find_ld: for (lib_paths) |lib_path| { |
| 295 | | for (ld_info_list.toSlice()) |ld_info| { |
| 296 | | const standard_ld_basename = fs.path.basename(ld_info.ld_path); |
| 295 | for (ld_info_list) |ld_info| { |
| 296 | const standard_ld_basename = fs.path.basename(ld_info.ldPath()); |
| 297 | 297 | if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) { |
| 298 | 298 | found_ld_info = ld_info; |
| 299 | 299 | found_ld_path = lib_path; |
| ... | ... | @@ -355,7 +355,7 @@ pub const NativeTargetInfo = struct { |
| 355 | 355 | error.UnexpectedEndOfFile, |
| 356 | 356 | error.NameTooLong, |
| 357 | 357 | // Finally, we fall back on the standard path. |
| 358 | | => defaultAbiAndDynamicLinker(allocator, cpu, os), |
| 358 | => defaultAbiAndDynamicLinker(cpu, os), |
| 359 | 359 | }; |
| 360 | 360 | } |
| 361 | 361 | |
| ... | ... | @@ -502,7 +502,7 @@ pub const NativeTargetInfo = struct { |
| 502 | 502 | }; |
| 503 | 503 | } |
| 504 | 504 | |
| 505 | | fn defaultAbiAndDynamicLinker(allocator: *Allocator, cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { |
| 505 | fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { |
| 506 | 506 | var result: NativeTargetInfo = .{ |
| 507 | 507 | .target = .{ |
| 508 | 508 | .cpu = cpu, |
| ... | ... | @@ -510,9 +510,7 @@ pub const NativeTargetInfo = struct { |
| 510 | 510 | .abi = Target.Abi.default(cpu.arch, os), |
| 511 | 511 | }, |
| 512 | 512 | }; |
| 513 | | if (result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer)) |s| { |
| 514 | | result.dynamic_linker_max = @intCast(u8, s.len - 1); |
| 515 | | } |
| 513 | result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer); |
| 516 | 514 | return result; |
| 517 | 515 | } |
| 518 | 516 | }; |