mirror of
https://github.com/ziglang/zig.git
synced 2025-12-30 18:13:19 +00:00
macho: handle mismatched and missing platform errors
This commit is contained in:
parent
1cae41bbbb
commit
79b3285aa2
@ -396,16 +396,24 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
self.dylibs_map.clearRetainingCapacity();
|
||||
self.referenced_dylibs.clearRetainingCapacity();
|
||||
|
||||
const cpu_arch = self.base.options.target.cpu.arch;
|
||||
var dependent_libs = std.fifo.LinearFifo(struct {
|
||||
id: Dylib.Id,
|
||||
parent: u16,
|
||||
}, .Dynamic).init(arena);
|
||||
|
||||
var parse_error_ctx: union {
|
||||
none: void,
|
||||
var parse_error_ctx: struct {
|
||||
detected_arch: std.Target.Cpu.Arch,
|
||||
} = .{ .none = {} };
|
||||
detected_platform: ?Platform,
|
||||
detected_stub_targets: []const []const u8,
|
||||
} = .{
|
||||
.detected_arch = undefined,
|
||||
.detected_platform = null,
|
||||
.detected_stub_targets = &[0][]const u8{},
|
||||
};
|
||||
defer {
|
||||
for (parse_error_ctx.detected_stub_targets) |target| self.base.allocator.free(target);
|
||||
self.base.allocator.free(parse_error_ctx.detected_stub_targets);
|
||||
}
|
||||
|
||||
for (libs.keys(), libs.values()) |path, lib| {
|
||||
const in_file = try std.fs.cwd().openFile(path, .{});
|
||||
@ -418,25 +426,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
false,
|
||||
&dependent_libs,
|
||||
&parse_error_ctx,
|
||||
) catch |err| switch (err) {
|
||||
error.DylibAlreadyExists => {},
|
||||
error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
|
||||
error.MissingArchFatLib => try self.reportParseError(
|
||||
path,
|
||||
"missing architecture in universal file, expected '{s}'",
|
||||
.{@tagName(cpu_arch)},
|
||||
),
|
||||
error.InvalidArch => try self.reportParseError(
|
||||
path,
|
||||
"invalid architecture '{s}', expected '{s}'",
|
||||
.{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
|
||||
),
|
||||
else => |e| try self.reportParseError(
|
||||
path,
|
||||
"parsing library failed with error '{s}'",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
};
|
||||
) catch |err| try self.handleAndReportParseError(path, err, parse_error_ctx);
|
||||
}
|
||||
|
||||
self.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {
|
||||
@ -586,7 +576,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
.version = 0,
|
||||
});
|
||||
{
|
||||
const platform = load_commands.Platform.fromOptions(&self.base.options);
|
||||
const platform = Platform.fromTarget(self.base.options.target);
|
||||
const sdk_version: ?std.SemanticVersion = if (self.base.options.sysroot) |path|
|
||||
load_commands.inferSdkVersionFromSdkPath(path)
|
||||
else
|
||||
@ -738,7 +728,8 @@ fn resolveLib(
|
||||
const ParseError = error{
|
||||
UnknownFileType,
|
||||
MissingArchFatLib,
|
||||
InvalidArch,
|
||||
InvalidTarget,
|
||||
InvalidLibStubTargets,
|
||||
DylibAlreadyExists,
|
||||
IncompatibleDylibVersion,
|
||||
OutOfMemory,
|
||||
@ -798,19 +789,24 @@ fn parseObject(
|
||||
};
|
||||
errdefer object.deinit(gpa);
|
||||
try object.parse(gpa);
|
||||
try self.objects.append(gpa, object);
|
||||
|
||||
const cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {
|
||||
macho.CPU_TYPE_ARM64 => .aarch64,
|
||||
macho.CPU_TYPE_X86_64 => .x86_64,
|
||||
else => unreachable,
|
||||
};
|
||||
const self_cpu_arch = self.base.options.target.cpu.arch;
|
||||
error_ctx.detected_arch = cpu_arch;
|
||||
|
||||
if (self_cpu_arch != cpu_arch) {
|
||||
error_ctx.detected_arch = cpu_arch;
|
||||
return error.InvalidArch;
|
||||
if (object.getPlatform()) |platform| {
|
||||
error_ctx.detected_platform = platform;
|
||||
}
|
||||
|
||||
if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;
|
||||
if (error_ctx.detected_platform) |platform| {
|
||||
if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;
|
||||
}
|
||||
|
||||
try self.objects.append(gpa, object);
|
||||
}
|
||||
|
||||
pub fn parseLibrary(
|
||||
@ -825,14 +821,12 @@ pub fn parseLibrary(
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const cpu_arch = self.base.options.target.cpu.arch;
|
||||
|
||||
if (fat.isFatLibrary(file)) {
|
||||
const offset = try self.parseFatLibrary(file, cpu_arch);
|
||||
const offset = try self.parseFatLibrary(file, self.base.options.target.cpu.arch);
|
||||
try file.seekTo(offset);
|
||||
|
||||
if (Archive.isArchive(file, offset)) {
|
||||
try self.parseArchive(path, offset, must_link, cpu_arch, error_ctx);
|
||||
try self.parseArchive(path, offset, must_link, error_ctx);
|
||||
} else if (Dylib.isDylib(file, offset)) {
|
||||
try self.parseDylib(file, path, offset, dependent_libs, .{
|
||||
.needed = lib.needed,
|
||||
@ -840,7 +834,7 @@ pub fn parseLibrary(
|
||||
}, error_ctx);
|
||||
} else return error.UnknownFileType;
|
||||
} else if (Archive.isArchive(file, 0)) {
|
||||
try self.parseArchive(path, 0, must_link, cpu_arch, error_ctx);
|
||||
try self.parseArchive(path, 0, must_link, error_ctx);
|
||||
} else if (Dylib.isDylib(file, 0)) {
|
||||
try self.parseDylib(file, path, 0, dependent_libs, .{
|
||||
.needed = lib.needed,
|
||||
@ -850,7 +844,7 @@ pub fn parseLibrary(
|
||||
self.parseLibStub(file, path, dependent_libs, .{
|
||||
.needed = lib.needed,
|
||||
.weak = lib.weak,
|
||||
}) catch |err| switch (err) {
|
||||
}, error_ctx) catch |err| switch (err) {
|
||||
error.NotLibStub, error.UnexpectedToken => return error.UnknownFileType,
|
||||
else => |e| return e,
|
||||
};
|
||||
@ -872,7 +866,6 @@ fn parseArchive(
|
||||
path: []const u8,
|
||||
fat_offset: u64,
|
||||
must_link: bool,
|
||||
cpu_arch: std.Target.Cpu.Arch,
|
||||
error_ctx: anytype,
|
||||
) ParseError!void {
|
||||
const gpa = self.base.allocator;
|
||||
@ -899,14 +892,20 @@ fn parseArchive(
|
||||
var object = try archive.parseObject(gpa, off); // TODO we are doing all this work to pull the header only!
|
||||
defer object.deinit(gpa);
|
||||
|
||||
const parsed_cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {
|
||||
const cpu_arch: std.Target.Cpu.Arch = switch (object.header.cputype) {
|
||||
macho.CPU_TYPE_ARM64 => .aarch64,
|
||||
macho.CPU_TYPE_X86_64 => .x86_64,
|
||||
else => unreachable,
|
||||
};
|
||||
if (cpu_arch != parsed_cpu_arch) {
|
||||
error_ctx.detected_arch = parsed_cpu_arch;
|
||||
return error.InvalidArch;
|
||||
error_ctx.detected_arch = cpu_arch;
|
||||
|
||||
if (object.getPlatform()) |platform| {
|
||||
error_ctx.detected_platform = platform;
|
||||
}
|
||||
|
||||
if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;
|
||||
if (error_ctx.detected_platform) |platform| {
|
||||
if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@ -945,8 +944,6 @@ fn parseDylib(
|
||||
error_ctx: anytype,
|
||||
) ParseError!void {
|
||||
const gpa = self.base.allocator;
|
||||
const self_cpu_arch = self.base.options.target.cpu.arch;
|
||||
|
||||
const file_stat = try file.stat();
|
||||
const file_size = math.cast(usize, file_stat.size - offset) orelse return error.Overflow;
|
||||
|
||||
@ -969,12 +966,16 @@ fn parseDylib(
|
||||
macho.CPU_TYPE_X86_64 => .x86_64,
|
||||
else => unreachable,
|
||||
};
|
||||
if (self_cpu_arch != cpu_arch) {
|
||||
error_ctx.detected_arch = cpu_arch;
|
||||
return error.InvalidArch;
|
||||
error_ctx.detected_arch = cpu_arch;
|
||||
|
||||
if (dylib.getPlatform(contents)) |platform| {
|
||||
error_ctx.detected_platform = platform;
|
||||
}
|
||||
|
||||
// TODO verify platform
|
||||
if (self.base.options.target.cpu.arch != cpu_arch) return error.InvalidTarget;
|
||||
if (error_ctx.detected_platform) |platform| {
|
||||
if (!Platform.fromTarget(self.base.options.target).eqlTarget(platform)) return error.InvalidTarget;
|
||||
}
|
||||
|
||||
try self.addDylib(dylib, .{
|
||||
.needed = dylib_options.needed,
|
||||
@ -988,6 +989,7 @@ fn parseLibStub(
|
||||
path: []const u8,
|
||||
dependent_libs: anytype,
|
||||
dylib_options: DylibOpts,
|
||||
error_ctx: anytype,
|
||||
) ParseError!void {
|
||||
const gpa = self.base.allocator;
|
||||
var lib_stub = try LibStub.loadFromFile(gpa, file);
|
||||
@ -995,7 +997,20 @@ fn parseLibStub(
|
||||
|
||||
if (lib_stub.inner.len == 0) return error.NotLibStub;
|
||||
|
||||
// TODO verify platform
|
||||
// Verify target
|
||||
{
|
||||
var matcher = try Dylib.TargetMatcher.init(gpa, self.base.options.target);
|
||||
defer matcher.deinit();
|
||||
|
||||
const first_tbd = lib_stub.inner[0];
|
||||
const targets = try first_tbd.targets(gpa);
|
||||
if (!matcher.matchesTarget(targets)) {
|
||||
error_ctx.detected_stub_targets = targets;
|
||||
return error.InvalidLibStubTargets;
|
||||
}
|
||||
for (targets) |t| gpa.free(t);
|
||||
gpa.free(targets);
|
||||
}
|
||||
|
||||
var dylib = Dylib{ .weak = dylib_options.weak };
|
||||
errdefer dylib.deinit(gpa);
|
||||
@ -1104,7 +1119,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype, error_ctx: anyt
|
||||
self.parseLibStub(file, full_path, dependent_libs, .{
|
||||
.dependent = true,
|
||||
.weak = weak,
|
||||
}) catch |err| switch (err) {
|
||||
}, error_ctx) catch |err| switch (err) {
|
||||
error.NotLibStub, error.UnexpectedToken => continue,
|
||||
else => |e| return e,
|
||||
};
|
||||
@ -4830,6 +4845,53 @@ pub fn getSectionPrecedence(header: macho.section_64) u8 {
|
||||
return (@as(u8, @intCast(segment_precedence)) << 4) + section_precedence;
|
||||
}
|
||||
|
||||
pub fn handleAndReportParseError(self: *MachO, path: []const u8, err: ParseError, parse_error_ctx: anytype) !void {
|
||||
const cpu_arch = self.base.options.target.cpu.arch;
|
||||
switch (err) {
|
||||
error.DylibAlreadyExists => {},
|
||||
error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
|
||||
error.MissingArchFatLib => try self.reportParseError(
|
||||
path,
|
||||
"missing architecture in universal file, expected '{s}'",
|
||||
.{@tagName(cpu_arch)},
|
||||
),
|
||||
error.InvalidTarget => if (parse_error_ctx.detected_platform) |platform| {
|
||||
try self.reportParseError(path, "invalid target '{s}-{}', expected '{s}-{}'", .{
|
||||
@tagName(parse_error_ctx.detected_arch),
|
||||
platform.fmtTarget(),
|
||||
@tagName(cpu_arch),
|
||||
Platform.fromTarget(self.base.options.target).fmtTarget(),
|
||||
});
|
||||
} else {
|
||||
try self.reportParseError(
|
||||
path,
|
||||
"invalid architecture '{s}', expected '{s}'",
|
||||
.{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
|
||||
);
|
||||
},
|
||||
error.InvalidLibStubTargets => {
|
||||
var targets_string = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer targets_string.deinit();
|
||||
try targets_string.writer().writeAll("(");
|
||||
for (parse_error_ctx.detected_stub_targets) |t| {
|
||||
try targets_string.writer().print("{s}, ", .{t});
|
||||
}
|
||||
try targets_string.resize(targets_string.items.len - 2);
|
||||
try targets_string.writer().writeAll(")");
|
||||
try self.reportParseError(path, "invalid targets '{s}', expected '{s}-{}'", .{
|
||||
targets_string.items,
|
||||
@tagName(cpu_arch),
|
||||
Platform.fromTarget(self.base.options.target).fmtTarget(),
|
||||
});
|
||||
},
|
||||
else => |e| try self.reportParseError(
|
||||
path,
|
||||
"parsing positional argument failed with error '{s}'",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reportParseError(self: *MachO, path: []const u8, comptime format: []const u8, args: anytype) !void {
|
||||
const gpa = self.base.allocator;
|
||||
try self.misc_errors.ensureUnusedCapacity(gpa, 1);
|
||||
@ -5140,66 +5202,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index, logger: anytype) void {
|
||||
}
|
||||
}
|
||||
|
||||
const MachO = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const meta = std.meta;
|
||||
|
||||
const aarch64 = @import("../arch/aarch64/bits.zig");
|
||||
const calcUuid = @import("MachO/uuid.zig").calcUuid;
|
||||
const codegen = @import("../codegen.zig");
|
||||
const dead_strip = @import("MachO/dead_strip.zig");
|
||||
const fat = @import("MachO/fat.zig");
|
||||
const link = @import("../link.zig");
|
||||
const llvm_backend = @import("../codegen/llvm.zig");
|
||||
const load_commands = @import("MachO/load_commands.zig");
|
||||
const stubs = @import("MachO/stubs.zig");
|
||||
const tapi = @import("tapi.zig");
|
||||
const target_util = @import("../target.zig");
|
||||
const thunks = @import("MachO/thunks.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const zld = @import("MachO/zld.zig");
|
||||
|
||||
const Air = @import("../Air.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @import("MachO/Archive.zig");
|
||||
pub const Atom = @import("MachO/Atom.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const CodeSignature = @import("MachO/CodeSignature.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Dwarf = File.Dwarf;
|
||||
const DwarfInfo = @import("MachO/DwarfInfo.zig");
|
||||
const Dylib = @import("MachO/Dylib.zig");
|
||||
const File = link.File;
|
||||
const Object = @import("MachO/Object.zig");
|
||||
const LibStub = tapi.LibStub;
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||
const Md5 = std.crypto.hash.Md5;
|
||||
const Module = @import("../Module.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Relocation = @import("MachO/Relocation.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const Trie = @import("MachO/Trie.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const Value = @import("../value.zig").Value;
|
||||
|
||||
pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
|
||||
pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc);
|
||||
pub const LazyBind = @import("MachO/dyld_info/bind.zig").LazyBind(*const MachO, SymbolWithLoc);
|
||||
pub const Rebase = @import("MachO/dyld_info/Rebase.zig");
|
||||
|
||||
pub const base_tag: File.Tag = File.Tag.macho;
|
||||
pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));
|
||||
|
||||
@ -5332,3 +5334,64 @@ pub const default_pagezero_vmsize: u64 = 0x100000000;
|
||||
/// the table of load commands. This should be plenty for any
|
||||
/// potential future extensions.
|
||||
pub const default_headerpad_size: u32 = 0x1000;
|
||||
|
||||
const MachO = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const build_options = @import("build_options");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const dwarf = std.dwarf;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
const meta = std.meta;
|
||||
|
||||
const aarch64 = @import("../arch/aarch64/bits.zig");
|
||||
const calcUuid = @import("MachO/uuid.zig").calcUuid;
|
||||
const codegen = @import("../codegen.zig");
|
||||
const dead_strip = @import("MachO/dead_strip.zig");
|
||||
const fat = @import("MachO/fat.zig");
|
||||
const link = @import("../link.zig");
|
||||
const llvm_backend = @import("../codegen/llvm.zig");
|
||||
const load_commands = @import("MachO/load_commands.zig");
|
||||
const stubs = @import("MachO/stubs.zig");
|
||||
const tapi = @import("tapi.zig");
|
||||
const target_util = @import("../target.zig");
|
||||
const thunks = @import("MachO/thunks.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const zld = @import("MachO/zld.zig");
|
||||
|
||||
const Air = @import("../Air.zig");
|
||||
const Allocator = mem.Allocator;
|
||||
const Archive = @import("MachO/Archive.zig");
|
||||
pub const Atom = @import("MachO/Atom.zig");
|
||||
const Cache = std.Build.Cache;
|
||||
const CodeSignature = @import("MachO/CodeSignature.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const Dwarf = File.Dwarf;
|
||||
const DwarfInfo = @import("MachO/DwarfInfo.zig");
|
||||
const Dylib = @import("MachO/Dylib.zig");
|
||||
const File = link.File;
|
||||
const Object = @import("MachO/Object.zig");
|
||||
const LibStub = tapi.LibStub;
|
||||
const Liveness = @import("../Liveness.zig");
|
||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||
const Md5 = std.crypto.hash.Md5;
|
||||
const Module = @import("../Module.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Platform = load_commands.Platform;
|
||||
const Relocation = @import("MachO/Relocation.zig");
|
||||
const StringTable = @import("strtab.zig").StringTable;
|
||||
const TableSection = @import("table_section.zig").TableSection;
|
||||
const Trie = @import("MachO/Trie.zig");
|
||||
const Type = @import("../type.zig").Type;
|
||||
const TypedValue = @import("../TypedValue.zig");
|
||||
const Value = @import("../value.zig").Value;
|
||||
|
||||
pub const DebugSymbols = @import("MachO/DebugSymbols.zig");
|
||||
pub const Bind = @import("MachO/dyld_info/bind.zig").Bind(*const MachO, SymbolWithLoc);
|
||||
pub const LazyBind = @import("MachO/dyld_info/bind.zig").LazyBind(*const MachO, SymbolWithLoc);
|
||||
pub const Rebase = @import("MachO/dyld_info/Rebase.zig");
|
||||
|
||||
@ -178,6 +178,26 @@ pub fn parseFromBinary(
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns Platform composed from the first encountered build version type load command:
|
||||
/// either LC_BUILD_VERSION or LC_VERSION_MIN_*.
|
||||
pub fn getPlatform(self: Dylib, data: []align(@alignOf(u64)) const u8) ?Platform {
|
||||
var it = LoadCommandIterator{
|
||||
.ncmds = self.header.?.ncmds,
|
||||
.buffer = data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],
|
||||
};
|
||||
while (it.next()) |cmd| {
|
||||
switch (cmd.cmd()) {
|
||||
.BUILD_VERSION,
|
||||
.VERSION_MIN_MACOSX,
|
||||
.VERSION_MIN_IPHONEOS,
|
||||
.VERSION_MIN_TVOS,
|
||||
.VERSION_MIN_WATCHOS,
|
||||
=> return Platform.fromLoadCommand(cmd),
|
||||
else => {},
|
||||
}
|
||||
} else return null;
|
||||
}
|
||||
|
||||
fn addObjCClassSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void {
|
||||
const expanded = &[_][]const u8{
|
||||
try std.fmt.allocPrint(allocator, "_OBJC_CLASS_$_{s}", .{sym_name}),
|
||||
@ -212,27 +232,27 @@ fn addWeakSymbol(self: *Dylib, allocator: Allocator, sym_name: []const u8) !void
|
||||
try self.symbols.putNoClobber(allocator, try allocator.dupe(u8, sym_name), true);
|
||||
}
|
||||
|
||||
const TargetMatcher = struct {
|
||||
pub const TargetMatcher = struct {
|
||||
allocator: Allocator,
|
||||
target: CrossTarget,
|
||||
cpu_arch: std.Target.Cpu.Arch,
|
||||
os_tag: std.Target.Os.Tag,
|
||||
abi: std.Target.Abi,
|
||||
target_strings: std.ArrayListUnmanaged([]const u8) = .{},
|
||||
|
||||
pub fn init(allocator: Allocator, target: CrossTarget) !TargetMatcher {
|
||||
pub fn init(allocator: Allocator, target: std.Target) !TargetMatcher {
|
||||
var self = TargetMatcher{
|
||||
.allocator = allocator,
|
||||
.target = target,
|
||||
.cpu_arch = target.cpu.arch,
|
||||
.os_tag = target.os.tag,
|
||||
.abi = target.abi,
|
||||
};
|
||||
const apple_string = try targetToAppleString(allocator, target);
|
||||
const apple_string = try toAppleTargetTriple(allocator, self.cpu_arch, self.os_tag, self.abi);
|
||||
try self.target_strings.append(allocator, apple_string);
|
||||
|
||||
const abi = target.abi orelse .none;
|
||||
if (abi == .simulator) {
|
||||
if (self.abi == .simulator) {
|
||||
// For Apple simulator targets, linking gets tricky as we need to link against the simulator
|
||||
// hosts dylibs too.
|
||||
const host_target = try targetToAppleString(allocator, .{
|
||||
.cpu_arch = target.cpu_arch.?,
|
||||
.os_tag = .macos,
|
||||
});
|
||||
const host_target = try toAppleTargetTriple(allocator, self.cpu_arch, .macos, .none);
|
||||
try self.target_strings.append(allocator, host_target);
|
||||
}
|
||||
|
||||
@ -246,7 +266,7 @@ const TargetMatcher = struct {
|
||||
self.target_strings.deinit(self.allocator);
|
||||
}
|
||||
|
||||
inline fn cpuArchToAppleString(cpu_arch: std.Target.Cpu.Arch) []const u8 {
|
||||
inline fn fmtCpuArch(cpu_arch: std.Target.Cpu.Arch) []const u8 {
|
||||
return switch (cpu_arch) {
|
||||
.aarch64 => "arm64",
|
||||
.x86_64 => "x86_64",
|
||||
@ -254,7 +274,7 @@ const TargetMatcher = struct {
|
||||
};
|
||||
}
|
||||
|
||||
inline fn abiToAppleString(abi: std.Target.Abi) ?[]const u8 {
|
||||
inline fn fmtAbi(abi: std.Target.Abi) ?[]const u8 {
|
||||
return switch (abi) {
|
||||
.none => null,
|
||||
.simulator => "simulator",
|
||||
@ -263,14 +283,18 @@ const TargetMatcher = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn targetToAppleString(allocator: Allocator, target: CrossTarget) ![]const u8 {
|
||||
const cpu_arch = cpuArchToAppleString(target.cpu_arch.?);
|
||||
const os_tag = @tagName(target.os_tag.?);
|
||||
const target_abi = abiToAppleString(target.abi orelse .none);
|
||||
if (target_abi) |abi| {
|
||||
return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ cpu_arch, os_tag, abi });
|
||||
pub fn toAppleTargetTriple(
|
||||
allocator: Allocator,
|
||||
cpu_arch: std.Target.Cpu.Arch,
|
||||
os_tag: std.Target.Os.Tag,
|
||||
abi: std.Target.Abi,
|
||||
) ![]const u8 {
|
||||
const cpu_arch_s = fmtCpuArch(cpu_arch);
|
||||
const os_tag_s = @tagName(os_tag);
|
||||
if (fmtAbi(abi)) |abi_s| {
|
||||
return std.fmt.allocPrint(allocator, "{s}-{s}-{s}", .{ cpu_arch_s, os_tag_s, abi_s });
|
||||
}
|
||||
return std.fmt.allocPrint(allocator, "{s}-{s}", .{ cpu_arch, os_tag });
|
||||
return std.fmt.allocPrint(allocator, "{s}-{s}", .{ cpu_arch_s, os_tag_s });
|
||||
}
|
||||
|
||||
fn hasValue(stack: []const []const u8, needle: []const u8) bool {
|
||||
@ -280,7 +304,7 @@ const TargetMatcher = struct {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn matchesTarget(self: TargetMatcher, targets: []const []const u8) bool {
|
||||
pub fn matchesTarget(self: TargetMatcher, targets: []const []const u8) bool {
|
||||
for (self.target_strings.items) |t| {
|
||||
if (hasValue(targets, t)) return true;
|
||||
}
|
||||
@ -288,26 +312,7 @@ const TargetMatcher = struct {
|
||||
}
|
||||
|
||||
fn matchesArch(self: TargetMatcher, archs: []const []const u8) bool {
|
||||
return hasValue(archs, cpuArchToAppleString(self.target.cpu_arch.?));
|
||||
}
|
||||
|
||||
pub fn matchesTargetTbd(self: TargetMatcher, tbd: Tbd) !bool {
|
||||
var arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const targets = switch (tbd) {
|
||||
.v3 => |v3| blk: {
|
||||
var targets = std.ArrayList([]const u8).init(arena.allocator());
|
||||
for (v3.archs) |arch| {
|
||||
const target = try std.fmt.allocPrint(arena.allocator(), "{s}-{s}", .{ arch, v3.platform });
|
||||
try targets.append(target);
|
||||
}
|
||||
break :blk targets.items;
|
||||
},
|
||||
.v4 => |v4| v4.targets,
|
||||
};
|
||||
|
||||
return self.matchesTarget(targets);
|
||||
return hasValue(archs, fmtCpuArch(self.cpu_arch));
|
||||
}
|
||||
};
|
||||
|
||||
@ -342,15 +347,16 @@ pub fn parseFromStub(
|
||||
|
||||
log.debug(" (install_name '{s}')", .{umbrella_lib.installName()});
|
||||
|
||||
var matcher = try TargetMatcher.init(allocator, .{
|
||||
.cpu_arch = target.cpu.arch,
|
||||
.os_tag = target.os.tag,
|
||||
.abi = target.abi,
|
||||
});
|
||||
var matcher = try TargetMatcher.init(allocator, target);
|
||||
defer matcher.deinit();
|
||||
|
||||
for (lib_stub.inner, 0..) |elem, stub_index| {
|
||||
if (!(try matcher.matchesTargetTbd(elem))) continue;
|
||||
const targets = try elem.targets(allocator);
|
||||
defer {
|
||||
for (targets) |t| allocator.free(t);
|
||||
allocator.free(targets);
|
||||
}
|
||||
if (!matcher.matchesTarget(targets)) continue;
|
||||
|
||||
if (stub_index > 0) {
|
||||
// TODO I thought that we could switch on presence of `parent-umbrella` map;
|
||||
@ -541,8 +547,8 @@ const fat = @import("fat.zig");
|
||||
const tapi = @import("../tapi.zig");
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
const LibStub = tapi.LibStub;
|
||||
const LoadCommandIterator = macho.LoadCommandIterator;
|
||||
const MachO = @import("../MachO.zig");
|
||||
const Platform = @import("load_commands.zig").Platform;
|
||||
const Tbd = tapi.Tbd;
|
||||
|
||||
@ -940,7 +940,7 @@ pub fn parseDwarfInfo(self: Object) DwarfInfo {
|
||||
return di;
|
||||
}
|
||||
|
||||
/// Returns Options.Platform composed from the first encountered build version type load command:
|
||||
/// Returns Platform composed from the first encountered build version type load command:
|
||||
/// either LC_BUILD_VERSION or LC_VERSION_MIN_*.
|
||||
pub fn getPlatform(self: Object) ?Platform {
|
||||
var it = LoadCommandIterator{
|
||||
|
||||
@ -77,7 +77,7 @@ fn calcLCsSize(gpa: Allocator, options: *const link.Options, ctx: CalcLCsSizeCtx
|
||||
// LC_SOURCE_VERSION
|
||||
sizeofcmds += @sizeOf(macho.source_version_command);
|
||||
// LC_BUILD_VERSION or LC_VERSION_MIN_
|
||||
if (Platform.fromOptions(options).isBuildVersionCompatible()) {
|
||||
if (Platform.fromTarget(options.target).isBuildVersionCompatible()) {
|
||||
// LC_BUILD_VERSION
|
||||
sizeofcmds += @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
|
||||
} else {
|
||||
@ -353,11 +353,11 @@ pub const Platform = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fromOptions(options: *const link.Options) Platform {
|
||||
pub fn fromTarget(target: std.Target) Platform {
|
||||
return .{
|
||||
.os_tag = options.target.os.tag,
|
||||
.abi = options.target.abi,
|
||||
.version = options.target.os.version_range.semver.min,
|
||||
.os_tag = target.os.tag,
|
||||
.abi = target.abi,
|
||||
.version = target.os.version_range.semver.min,
|
||||
};
|
||||
}
|
||||
|
||||
@ -383,6 +383,28 @@ pub const Platform = struct {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn fmtTarget(plat: Platform) std.fmt.Formatter(formatTarget) {
|
||||
return .{ .data = plat };
|
||||
}
|
||||
|
||||
pub fn formatTarget(
|
||||
plat: Platform,
|
||||
comptime unused_fmt_string: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = unused_fmt_string;
|
||||
_ = options;
|
||||
try writer.print("{s}", .{@tagName(plat.os_tag)});
|
||||
if (plat.abi != .none) {
|
||||
try writer.print("-{s}", .{@tagName(plat.abi)});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eqlTarget(plat: Platform, other: Platform) bool {
|
||||
return plat.os_tag == other.os_tag and plat.abi == other.abi;
|
||||
}
|
||||
};
|
||||
|
||||
const SupportedPlatforms = struct {
|
||||
|
||||
@ -347,11 +347,17 @@ pub fn linkWithZld(
|
||||
|
||||
var parse_error_ctx: struct {
|
||||
detected_arch: std.Target.Cpu.Arch,
|
||||
detected_os: std.Target.Os.Tag,
|
||||
detected_platform: ?Platform,
|
||||
detected_stub_targets: []const []const u8,
|
||||
} = .{
|
||||
.detected_arch = undefined,
|
||||
.detected_os = undefined,
|
||||
.detected_platform = null,
|
||||
.detected_stub_targets = &[0][]const u8{},
|
||||
};
|
||||
defer {
|
||||
for (parse_error_ctx.detected_stub_targets) |t| gpa.free(t);
|
||||
gpa.free(parse_error_ctx.detected_stub_targets);
|
||||
}
|
||||
|
||||
for (positionals.items) |obj| {
|
||||
const in_file = try std.fs.cwd().openFile(obj.path, .{});
|
||||
@ -363,25 +369,7 @@ pub fn linkWithZld(
|
||||
obj.must_link,
|
||||
&dependent_libs,
|
||||
&parse_error_ctx,
|
||||
) catch |err| switch (err) {
|
||||
error.DylibAlreadyExists => {},
|
||||
error.UnknownFileType => try macho_file.reportParseError(obj.path, "unknown file type", .{}),
|
||||
error.MissingArchFatLib => try macho_file.reportParseError(
|
||||
obj.path,
|
||||
"missing architecture in universal file, expected '{s}'",
|
||||
.{@tagName(cpu_arch)},
|
||||
),
|
||||
error.InvalidArch => try macho_file.reportParseError(
|
||||
obj.path,
|
||||
"invalid architecture '{s}', expected '{s}'",
|
||||
.{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
|
||||
),
|
||||
else => |e| try macho_file.reportParseError(
|
||||
obj.path,
|
||||
"parsing positional argument failed with error '{s}'",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
};
|
||||
) catch |err| try macho_file.handleAndReportParseError(obj.path, err, parse_error_ctx);
|
||||
}
|
||||
|
||||
for (libs.keys(), libs.values()) |path, lib| {
|
||||
@ -395,25 +383,7 @@ pub fn linkWithZld(
|
||||
false,
|
||||
&dependent_libs,
|
||||
&parse_error_ctx,
|
||||
) catch |err| switch (err) {
|
||||
error.DylibAlreadyExists => {},
|
||||
error.UnknownFileType => try macho_file.reportParseError(path, "unknown file type", .{}),
|
||||
error.MissingArchFatLib => try macho_file.reportParseError(
|
||||
path,
|
||||
"missing architecture in universal file, expected '{s}'",
|
||||
.{@tagName(cpu_arch)},
|
||||
),
|
||||
error.InvalidArch => try macho_file.reportParseError(
|
||||
path,
|
||||
"invalid architecture '{s}', expected '{s}'",
|
||||
.{ @tagName(parse_error_ctx.detected_arch), @tagName(cpu_arch) },
|
||||
),
|
||||
else => |e| try macho_file.reportParseError(
|
||||
path,
|
||||
"parsing library failed with error '{s}'",
|
||||
.{@errorName(e)},
|
||||
),
|
||||
};
|
||||
) catch |err| try macho_file.handleAndReportParseError(path, err, parse_error_ctx);
|
||||
}
|
||||
|
||||
macho_file.parseDependentLibs(&dependent_libs, &parse_error_ctx) catch |err| {
|
||||
@ -590,7 +560,7 @@ pub fn linkWithZld(
|
||||
.version = 0,
|
||||
});
|
||||
{
|
||||
const platform = load_commands.Platform.fromOptions(&macho_file.base.options);
|
||||
const platform = Platform.fromTarget(macho_file.base.options.target);
|
||||
const sdk_version: ?std.SemanticVersion = if (macho_file.base.options.sysroot) |path|
|
||||
load_commands.inferSdkVersionFromSdkPath(path)
|
||||
else
|
||||
@ -1252,6 +1222,7 @@ const MachO = @import("../MachO.zig");
|
||||
const Md5 = std.crypto.hash.Md5;
|
||||
const LibStub = @import("../tapi.zig").LibStub;
|
||||
const Object = @import("Object.zig");
|
||||
const Platform = load_commands.Platform;
|
||||
const Section = MachO.Section;
|
||||
const StringTable = @import("../strtab.zig").StringTable;
|
||||
const SymbolWithLoc = MachO.SymbolWithLoc;
|
||||
|
||||
@ -81,6 +81,30 @@ pub const Tbd = union(enum) {
|
||||
v3: TbdV3,
|
||||
v4: TbdV4,
|
||||
|
||||
/// Caller owns memory.
|
||||
pub fn targets(self: Tbd, gpa: Allocator) error{OutOfMemory}![]const []const u8 {
|
||||
var out = std.ArrayList([]const u8).init(gpa);
|
||||
defer out.deinit();
|
||||
|
||||
switch (self) {
|
||||
.v3 => |v3| {
|
||||
try out.ensureTotalCapacityPrecise(v3.archs.len);
|
||||
for (v3.archs) |arch| {
|
||||
const target = try std.fmt.allocPrint(gpa, "{s}-{s}", .{ arch, v3.platform });
|
||||
out.appendAssumeCapacity(target);
|
||||
}
|
||||
},
|
||||
.v4 => |v4| {
|
||||
try out.ensureTotalCapacityPrecise(v4.targets.len);
|
||||
for (v4.targets) |t| {
|
||||
out.appendAssumeCapacity(try gpa.dupe(u8, t));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
|
||||
pub fn currentVersion(self: Tbd) ?VersionField {
|
||||
return switch (self) {
|
||||
.v3 => |v3| v3.current_version,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user