fix(native): name numeric Mach-O build-version platforms and tools (#2065)

Squash merge of https://github.com/morluto/rea/pull/2065.

Co-authored-by: TonyWu <2038838159@qq.com>
This commit is contained in:
TonyWu 2026-10-13 23:49:37 +08:00 committed by GitHub
parent 168bfe5060
commit 77e71d55ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 186 additions and 2 deletions

View File

@ -63,6 +63,56 @@ const DYLIB_FIELDS = [
const DYLIB_ENCODING_FIELDS = ["time stamp", "options"];
const EMPTY_VALUE_FIELDS = new Set(["options", "segname", "sectname"]);
/**
* Non-verbose otool prints LC_BUILD_VERSION platform and tool codes as
* numbers. Name the codes declared in the SDK's <mach-o/loader.h>, without
* the PLATFORM_/TOOL_ prefix, so build metadata uses the same symbolic style
* as LC_VERSION_MIN_* platforms. Unknown codes keep their printed value.
*/
const BUILD_PLATFORM_NAMES: ReadonlyMap<string, string> = new Map([
["1", "MACOS"],
["2", "IOS"],
["3", "TVOS"],
["4", "WATCHOS"],
["5", "BRIDGEOS"],
["6", "MACCATALYST"],
["7", "IOSSIMULATOR"],
["8", "TVOSSIMULATOR"],
["9", "WATCHOSSIMULATOR"],
["10", "DRIVERKIT"],
["11", "VISIONOS"],
["12", "VISIONOSSIMULATOR"],
["13", "FIRMWARE"],
["14", "SEPOS"],
["15", "MACOS_EXCLAVECORE"],
["16", "MACOS_EXCLAVEKIT"],
["17", "IOS_EXCLAVECORE"],
["18", "IOS_EXCLAVEKIT"],
["19", "TVOS_EXCLAVECORE"],
["20", "TVOS_EXCLAVEKIT"],
["21", "WATCHOS_EXCLAVECORE"],
["22", "WATCHOS_EXCLAVEKIT"],
["23", "VISIONOS_EXCLAVECORE"],
["24", "VISIONOS_EXCLAVEKIT"],
]);
const BUILD_TOOL_NAMES: ReadonlyMap<string, string> = new Map([
["1", "CLANG"],
["2", "SWIFT"],
["3", "LD"],
["4", "LLD"],
["1024", "METAL"],
["1025", "AIRLLD"],
["1026", "AIRNT"],
["1027", "AIRNT_PLUGIN"],
["1028", "AIRPACK"],
["1031", "GPUARCHIVER"],
["1032", "METAL_FRAMEWORK"],
]);
const buildCodeName = (
names: ReadonlyMap<string, string>,
value: string | null,
): string | null => (value === null ? null : (names.get(value) ?? value));
/**
* otool emits LF, but a capture replayed from another host or toolchain can
* carry CRLF. The section/command boundaries below match a bare `\n`, so a
@ -295,7 +345,10 @@ const collectBuild = (
if (numberField(fields, "ntools") !== tools.length)
throw new TypeError("otool build-tool count does not match ntools");
state.builds.push({
platform: stringField(fields, "platform"),
platform: buildCodeName(
BUILD_PLATFORM_NAMES,
stringField(fields, "platform"),
),
minimum_os: stringField(fields, "minos"),
sdk: stringField(fields, "sdk"),
tools,
@ -434,7 +487,7 @@ const parseBuildTools = (
const tool = /^tool\s+(.+)$/u.exec(lines[index] ?? "")?.[1];
const version = /^version\s+(.+)$/u.exec(lines[index + 1] ?? "")?.[1];
if (tool !== undefined && version !== undefined)
tools.push({ name: tool, version });
tools.push({ name: BUILD_TOOL_NAMES.get(tool) ?? tool, version });
}
return tools;
};

View File

@ -229,6 +229,62 @@ it("normalizes legacy version-minimum commands into build metadata", () => {
]);
});
it("names numeric build-version platforms and tools", () => {
const load = parseOtoolLoadCommands(
withOtoolMachHeader(
[
"Load command 0",
" cmd LC_BUILD_VERSION",
" cmdsize 48",
" platform 1",
" minos 11.0",
" sdk 26.5",
" ntools 2",
" tool 3",
" version 1267.0",
" tool 1029",
" version 1.0",
"Load command 1",
" cmd LC_BUILD_VERSION",
" cmdsize 24",
" platform 99",
" minos 1.0",
" sdk 1.0",
" ntools 0",
"Load command 2",
" cmd LC_BUILD_VERSION",
" cmdsize 32",
" platform MACCATALYST",
" minos 14.0",
" sdk 14.2",
" ntools 1",
" tool SWIFT",
" version 5.9",
"",
].join("\n"),
),
);
expect(load.builds).toEqual([
{
platform: "MACOS",
minimum_os: "11.0",
sdk: "26.5",
tools: [
{ name: "LD", version: "1267.0" },
{ name: "1029", version: "1.0" },
],
},
{ platform: "99", minimum_os: "1.0", sdk: "1.0", tools: [] },
{
platform: "MACCATALYST",
minimum_os: "14.0",
sdk: "14.2",
tools: [{ name: "SWIFT", version: "5.9" }],
},
]);
expect(load.commands[0]?.fields.platform).toBe(1);
});
it("does not classify LC_LOAD_DYLINKER as a dylib dependency", async () => {
const load = parseOtoolLoadCommands(
await nativeFixture("native-macho-header/otool-header-load.txt"),
@ -273,3 +329,78 @@ it("limits thread-state entrypoints instead of reporting none silently", async (
"Thread-state entrypoints (LC_UNIXTHREAD/LC_THREAD) are retained as raw load commands; file offsets are not derived.",
);
});
it.each([
["1", "MACOS"],
["2", "IOS"],
["3", "TVOS"],
["4", "WATCHOS"],
["5", "BRIDGEOS"],
["6", "MACCATALYST"],
["7", "IOSSIMULATOR"],
["8", "TVOSSIMULATOR"],
["9", "WATCHOSSIMULATOR"],
["10", "DRIVERKIT"],
["11", "VISIONOS"],
["12", "VISIONOSSIMULATOR"],
["13", "FIRMWARE"],
["14", "SEPOS"],
["15", "MACOS_EXCLAVECORE"],
["16", "MACOS_EXCLAVEKIT"],
["17", "IOS_EXCLAVECORE"],
["18", "IOS_EXCLAVEKIT"],
["19", "TVOS_EXCLAVECORE"],
["20", "TVOS_EXCLAVEKIT"],
["21", "WATCHOS_EXCLAVECORE"],
["22", "WATCHOS_EXCLAVEKIT"],
["23", "VISIONOS_EXCLAVECORE"],
["24", "VISIONOS_EXCLAVEKIT"],
] as const)("names build platform %s as %s", (code, name) => {
const load = parseOtoolLoadCommands(
withOtoolMachHeader(
[
"Load command 0",
"cmd LC_BUILD_VERSION",
"cmdsize 24",
`platform ${code}`,
"minos 1.0",
"sdk 1.0",
"ntools 0",
"",
].join("\n"),
),
);
expect(load.builds[0]?.platform).toBe(name);
});
it.each([
["1", "CLANG"],
["2", "SWIFT"],
["3", "LD"],
["4", "LLD"],
["1024", "METAL"],
["1025", "AIRLLD"],
["1026", "AIRNT"],
["1027", "AIRNT_PLUGIN"],
["1028", "AIRPACK"],
["1031", "GPUARCHIVER"],
["1032", "METAL_FRAMEWORK"],
] as const)("names build tool %s as %s", (code, name) => {
const load = parseOtoolLoadCommands(
withOtoolMachHeader(
[
"Load command 0",
"cmd LC_BUILD_VERSION",
"cmdsize 32",
"platform 1",
"minos 1.0",
"sdk 1.0",
"ntools 1",
`tool ${code}`,
"version 1.0",
"",
].join("\n"),
),
);
expect(load.builds[0]?.tools).toEqual([{ name, version: "1.0" }]);
});