no platform load command found in ‘libxyz.a’, assuming: macOS

This is a linker warning I see frequently since Xcode 15.0. It appears it’s a result of Apple’s new linker, “ld_prime”, which replaced “ld64” that was in use [by Apple] since around 2005 (per Quinn the Eskimo).

☝️ “ld_prime” might be an internal code name, or perhaps is just Quinn’s personal nomenclature. The actual binary and project name is simply ld (not to be confused with the original ld, the old old linker, that Apple used until ld64 replaced it in 2005).

The old linker – “ld64” – was retroactively renamed ld-classic. They emit almost identical version strings, making them easy to confuse at a glance, but for subtly different program and project names:

👾 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld -v
@(#)PROGRAM:ld PROJECT:ld-1053.12
BUILD 15:44:24 Feb  3 2024
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
will use ld-classic for: armv6 armv7 armv7s arm64_32 i386 armv6m armv7k armv7m armv7em
LTO support using: LLVM version 15.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 15.0.0 (tapi-1500.3.2.2)

👾 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld-classic -v
@(#)PROGRAM:ld-classic  PROJECT:ld64-951.9
BUILD 15:44:42 Feb  3 2024
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
LTO support using: LLVM version 15.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 15.0.0 (tapi-1500.3.2.2)

Tangentially, I believe the similarity of their version output is entirely intentional, as a lot of programs (particularly within build systems like CMake) make assumptions about the output, for better or worse.

Apple’s new linker appears to be much more pedantic than the old one – it warns about a lot of things that the old one didn’t care about. One of these is missing platform load commands:

/Users/SadPanda/Documents/vmaf/libvmaf/ld:1:1: no platform load command found in 'src/libvmaf.a[62](cpuid.obj)', assuming: macOS

This doesn’t technically break anything – assuming it guessed the platform correctly, which I suspect it just takes as being the host’s platform – but it’s super annoying because it’s emitted for every afflicted object file the linker sees (that’s individual files, even if they’re buried in archive files – e.g. libfoo.a). You can have hundreds or even thousands of these warnings for a single library. Worse, they’re emitted when you link against the library, not just when you build it. And with nested static libraries they can propagate up a build chain endlessly.

If we look at the offending file with otool, we see that indeed it has no platform load command:

👾 otool -vl cpuid.obj
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 152
  segname 
   vmaddr 0x0000000000000000
   vmsize 0x000000000000002d
  fileoff 208
 filesize 45
  maxprot rwx
 initprot rwx
   nsects 1
    flags (none)
Section
  sectname __text
   segname __TEXT
      addr 0x0000000000000000
      size 0x000000000000002d
    offset 208
     align 2^4 (16)
    reloff 0
    nreloc 0
      type S_REGULAR
attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
 reserved1 0
 reserved2 0
Load command 1
     cmd LC_SYMTAB
 cmdsize 24
  symoff 256
   nsyms 4
  stroff 320
 strsize 56

For reference, here’s an example of the load command it’s looking for:

Load command 1
      cmd LC_BUILD_VERSION
  cmdsize 24
 platform MACOS
    minos 14.2
      sdk 14.4
   ntools 0

Why is it missing?

There’s likely many reasons for this, but they all come down to the same general reason: something is wrong with one [or more] of the tools in the toolchain that created the object file. All object files should contain this load command, on Apple platforms. Though the linker currently treats it as optional, the warning is likely a hint from Apple that it may become required in future. More importantly, without it the linker cannot know which SDK the file is compatible with, and therefore cannot validate that it’s linking the right things.

In the example case above, the problem tool is nasm. It’s an open-source, non-Apple x86-family assembler. It’s been around for nearly thirty years – its first platform was DOS. Though it supports Apple’s platforms, it is predominately focused on Linux & Windows. So it’s not entirely surprising that it’s causing issues.

It also hasn’t released even a minor patch update since 2022 (with version 2.16.01), so nominally it predates and doesn’t support Xcode 15 (announced & released mid-2023).

However, the absence of the LC_BUILD_VERSION command was in fact a problem even before the new Apple linker in Xcode 15, because of cross-compiling (e.g. targeting the iOS simulator on a Mac). There was even a patch to address the problem, submitted by Byoungchan Lee way back in 2021, which was never accepted (it seems to have been completely ignored – not even a response on the mailing list).

Workarounds?

No good ones, that I can find. Stoically ignoring the warning for now is probably the best option.

It is still possible (in Xcode 15, at least) to switch to using the old linker instead, using the -Wl,-ld_classic flags, although that’s not a long-term solution and may have downsides (e.g. some folks report significantly smaller object files with the new linker).

It’s probably possible to manually insert the missing load command – if your build process is amenable to that – although it’s not apparent to me what tool or command invocation you would use to do that. Possibly ld itself, though its documentation provides no insight into this.

For some projects, you might be able to switch to a different assembler (e.g. Apple’s native as from Clang, or Yasm, etc). Apple’s toolchains don’t have this problem (so far as I’ve seen) but are of course not available on other platforms (though, being based on Clang, you can probably get essentially the same thing direct from Clang). I haven’t tested whether Yasm has the issue.

Leave a Comment