Fix: Undefined symbols for architecture arm64 in Xcode

Fix: Undefined symbols for architecture arm64 in Xcode

Written by

in

Quick answer: This is a linker error: the arm64 slice of the pod’s static library either has no arm64 code or is never passed to the linker. Add $(inherited) to Other Linker Flags so the CocoaPods-generated flags survive, then confirm the library actually contains an arm64 slice with lipo -info. If the slice is missing, update or replace the pod.

The build fails at the link stage with a wall of near-identical messages:

Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_FBSession", referenced from: someFile
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1

Each line names one Objective-C class (or C function) that the linker could not resolve to real code in any binary it was given.

Why this happens

Undefined symbols for architecture arm64 is a linker error, not a compiler error. The compiler was satisfied by your #import — it only needed the declaration. The linker is the stage that must find the actual class object behind _OBJC_CLASS_$_FBSession inside a .a or framework, for the specific CPU architecture being built. It found nothing.

There are two distinct causes, and the warning buried in the build log tells you which one you have:

Ignoring file ~/Library/Developer/Xcode/DerivedData/SomeApp/Build/Products/Debug-iphoneos/libPods.a,
file was built for archive which is not the architecture being linked (arm64)

That message means the library exists but contains no arm64 slice — it was compiled for armv7/armv7s only. The linker skips the file entirely, and every symbol it should have supplied becomes undefined. This was the situation in the original thread: the pods simply had not been rebuilt for 64-bit yet.

The second cause is that the flags telling the linker to link the pod at all are missing. CocoaPods does not edit your target’s build settings directly; it writes an .xcconfig file containing OTHER_LDFLAGS entries like -framework FBSDKCoreKit. If your target’s Other Linker Flags setting holds a hardcoded value without $(inherited), that value replaces the pod-generated one instead of extending it, and the linker never hears about the pod.

One historical note: the old workaround of removing arm64 from Architectures and building armv7 only is no longer available. Current Xcode does not build armv7 for devices at all, so arm64 is the only device architecture you can target. The diagnosis is unchanged, but the escape hatch is gone.

How to fix it

1. Restore $(inherited) in Other Linker Flags

This is the most common fix and the accepted answer in the thread.

  1. Select the project in the navigator, then your app target.
  2. Open Build Settings, switch the filter to All and Combined.
  3. Search for Other Linker Flags.
  4. If the value is a literal list, add $(inherited) as the first entry. Double-click the value to edit it as a list, one flag per line.
  5. Repeat for every configuration (Debug, Release, and any custom ones).

While you are there, check the target’s Configuration assignment. At the project level, each configuration should point at the CocoaPods xcconfig (Pods-YourApp.debug.xcconfig and so on). If someone set it to None, all pod-generated settings — linker flags included — are silently dropped.

2. Confirm the library really contains an arm64 slice

Run lipo on the exact .a file named in the warning:

lipo -info ~/Library/Developer/Xcode/DerivedData/SomeApp/Build/Products/Debug-iphoneos/libPods.a

A healthy result lists arm64 among the architectures. If it only shows armv7 or armv7s, the binary predates 64-bit support and no build setting will rescue it — go to step 5.

For a framework-based pod, inspect the framework binary inside the .framework bundle the same way.

3. Reinstall the pods and open the workspace

Stale integration is the second most common cause. From the project folder:

cd ~/Projects/YourApp
pod deintegrate
pod install --repo-update
open YourApp.xcworkspace

pod deintegrate strips the old CocoaPods build phases and xcconfig references so pod install can write clean ones. Then make sure you are building the .xcworkspace, not the .xcodeproj. Opening the project file directly is the single most frequent reason pod linker flags disappear from a build that used to work.

4. Clear the stale build products

The warning points into DerivedData, which caches the old libPods.a. Delete the project’s DerivedData folder, then use Product ▸ Clean Build Folder (⇧⌘K) and rebuild. This matters especially after switching Xcode versions or changing architecture settings, because the cached archive can survive a normal clean.

5. If the pod genuinely has no arm64 slice

Update it first:

pod update PodName

If the pod is abandoned and still ships an armv7-only binary, the practical options are to replace it, vendor the source and build it yourself, or drop it. There is no build setting that makes a 32-bit-only static library link into an arm64 build.

Two related flags worth knowing:

  • -ObjC in Other Linker Flags forces the linker to load Objective-C classes and categories from static libraries. Without it, a library that only contributes categories can produce undefined symbols even when the file is linked.
  • EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64 is the setting for simulator-only architecture mismatches on Apple Silicon. It does not apply here — that failure reports building for iOS Simulator, but linking in object file built for iOS, a different message.

How to prevent it

  • Always open the .xcworkspace after adding pods, and never commit a project that only builds from the .xcodeproj.
  • Commit Podfile.lock and run pod install (not pod update) after every pull that touches the Podfile.
  • Never hardcode Other Linker Flags without $(inherited) — the same rule applies to FRAMEWORK_SEARCH_PATHS and LIBRARY_SEARCH_PATHS.
  • Delete DerivedData after changing Xcode versions, architecture settings, or switching between Intel and Apple Silicon Macs.
  • Before adopting a pod, check that it still ships an arm64 slice or builds from source.

FAQ

Does the position of $(inherited) in Other Linker Flags matter?

No. $(inherited) expands to whatever the xcconfig supplied, and the linker accepts flags in any order. Put it first by convention so it is obvious the setting is inheriting rather than overriding.

Why does the project build for the simulator but fail for the device?

The simulator build uses the arm64 or x86_64 simulator slice, and many pods ship a simulator-only binary or build from source for that SDK. The device build needs a real arm64 device slice, which is exactly the one that is missing or unlinked.

I removed arm64 from Architectures and it still fails. Why?

Because current Xcode no longer builds armv7 for devices, so removing arm64 leaves no valid device architecture. That workaround only ever applied to the Xcode 5 era. Fix the missing slice or the missing linker flags instead.

Sources & credits

Parts of this guide are adapted from content licensed under CC BY-SA 3.0; this article is shared under the same license.