Skip to content

Parse Mach-O minimum OS / SDK version load commands - #67

Merged
staticfloat merged 2 commits into
masterfrom
macho-min-os-version
Nov 7, 2026
Merged

staticfloat merged 2 commits into
masterfrom
macho-min-os-version

Conversation

@staticfloat

@staticfloat staticfloat commented Nov 7, 2026 •

Copy link
Copy Markdown
Collaborator

Adds typed load commands for LC_VERSION_MIN_{MACOSX,IPHONEOS,TVOS,WATCHOS} (MachOVersionMinCmd) and LC_BUILD_VERSION (MachOBuildVersionCmd), which were previously read as MachOUnknownCmd, along with the missing LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS, LC_NOTE and LC_BUILD_VERSION constants and the PLATFORM_* identifiers.

New exported accessors, defined on the load commands, their refs, and on a MachOHandle (returning nothing when no such command is present):

  • min_os_version(x)::Union{VersionNumber,Nothing}
  • sdk_version(x)::Union{VersionNumber,Nothing}
  • build_platform(x)::Union{UInt32,Nothing} (a PLATFORM_* value)
julia> oh = only(readmeta(open("test/libjulias/libjulia.1.10.10.dylib")));

julia> min_os_version(oh), sdk_version(oh), build_platform(oh) == MachO.PLATFORM_MACOS
(v"11.0.0", v"13.3.0", true)

Tests cover LC_VERSION_MIN_MACOSX in the existing mac64/macfat fixtures and LC_BUILD_VERSION in the arm64 libjulia fixture.

Also bumps the version to 0.6.1.

Motivation: BinaryBuilder2's toolchain tests need to check the deployment target of built Mach-O files without parsing load commands by hand.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Jnarj1zM4Bdd5y4XcS7DFQ

@codecov

codecov Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.84848% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.21%. Comparing base (036c99a) to head (7a791c8).

Files with missing lines Patch % Lines
src/MachO/LoadCmds/VersionCmds.jl 84.84% 5 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #67      +/-   ##
==========================================
+ Coverage   72.32%   73.21%   +0.89%     
==========================================
  Files          47       48       +1     
  Lines        1514     1572      +58     
==========================================
+ Hits         1095     1151      +56     
- Misses        419      421       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

staticfloat and others added 2 commits November 6, 2026 23:17
Add typed load commands for LC_VERSION_MIN_{MACOSX,IPHONEOS,TVOS,WATCHOS}
(`MachOVersionMinCmd`) and LC_BUILD_VERSION (`MachOBuildVersionCmd`),
which were previously read as `MachOUnknownCmd`, along with the missing
LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS,
LC_NOTE and LC_BUILD_VERSION constants and the PLATFORM_* identifiers.

New exported accessors, defined on the load commands, their refs, and on
a `MachOHandle` (returning `nothing` when no such command is present):

  - min_os_version(x)::Union{VersionNumber,Nothing}
  - sdk_version(x)::Union{VersionNumber,Nothing}
  - build_platform(x)::Union{UInt32,Nothing}  (a PLATFORM_* value)

Tests cover LC_VERSION_MIN_MACOSX in the existing mac64/macfat fixtures
and LC_BUILD_VERSION in the arm64 libjulia fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jnarj1zM4Bdd5y4XcS7DFQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jnarj1zM4Bdd5y4XcS7DFQ
@staticfloat
staticfloat merged commit c3e7dfa into master Nov 7, 2026
17 checks passed
@staticfloat
staticfloat deleted the macho-min-os-version branch November 7, 2026 07:23
staticfloat added a commit to JuliaPackaging/BinaryBuilder2.jl that referenced this pull request Nov 7, 2026
… targets

macOS target platforms without an `os_version` tag used to get inconsistent
treatment across the toolchains:

- CToolchain passed no `-mmacosx-version-min` / `-Wl,-sdk_version` at all
  (leaving the deployment target to compiler defaults) and emitted
  "TODO: macOS builds should always denote their `os_version`!"; its GCC
  `clock_gettime` workaround assumed darwin 14 regardless of architecture.
- The macOS `as` wrapper only pinned `-mmacosx-version-min` when the
  triplet carried an `os_version`.
- BinutilsToolchain set MACOSX_DEPLOYMENT_TARGET to darwin 14 (10.10) for
  x86_64 and darwin 20 (11.0) for aarch64.
- CMakeToolchain assumed darwin 14.5 for every architecture, which is wrong
  for aarch64 (no Apple Silicon support before macOS 11).

Add `macos_target_kernel_version(platform)` (with
`default_macos_kernel_version(arch)`), which returns the platform's
`os_version` or the per-arch default used by BinutilsToolchain (x86_64 ->
10.10, matching BinaryBuilder 1; aarch64 -> 11.0), and use it in all four
places. Untagged macOS builds now always get an explicit deployment target,
and the warning is gone.

The platform is resolved at each use rather than rewritten when it enters
the toolchain, so the user-visible triplet (and therefore cache keys and
artifact names) is unchanged. This is consistent with BinaryBuilder2's
`add_os_version()`, which already tags packaged macOS artifacts from
BinutilsToolchain's MACOSX_DEPLOYMENT_TARGET; the C, `as` and CMake flags
now agree with the version that ends up in the JLL's platform tag.

Behaviour changes for untagged targets: x86_64 now gets
-mmacosx-version-min=10.10 (cc and as) and CMAKE_SYSTEM_VERSION 14.0 (was
14.5); aarch64 gets -mmacosx-version-min=11.0, CMAKE_SYSTEM_VERSION 20.0
and no longer gets the GCC `-D_DARWIN_FEATURE_CLOCK_GETTIME=0` workaround.
Tagged targets are unaffected.

Tests: new MacOSVersionTests.jl pins the helper, the cc/clang flags and
wrappers, MACOSX_DEPLOYMENT_TARGET and the CMake toolchain file for tagged
and untagged targets. The "macos as deployment target" testset now reads
each object's minimum OS version with ObjectFile's `min_os_version()`
(added in ObjectFile 0.6.1, JuliaIO/ObjectFile.jl#67; ObjectFile becomes a
test dependency) instead of parsing `otool -l` output, and checks the
generated `as` wrapper for untagged targets too. Its end-to-end
assemble/compile checks stay on the tagged `supported_platforms()`: the
cctools binaries are only shipped as `*-apple-darwin20-*`, so wrappers for
any other macOS triplet (untagged included) currently point at missing
`as`/`otool`/`nm`/... binaries. That lookup bug is pre-existing and is
fixed separately.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JnariyenmVWJ8o6jSi8kmT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant