Fix: Mach-O Linker Error ‘No such file or directory’ for .a on Device

Fix: Mach-O Linker Error 'No such file or directory' for .a on Device

Written by

in

Quick answer: The linker is being handed a path to a .a file that was never produced for the device build, usually because the library’s own target is still set to build for the simulator architecture only. Set the dependency target’s architectures to match your app, build it for a real device destination, then clean and rebuild.

Why this happens

The message looks like a missing file, and it is — but not because the file was deleted. Look closely at the path in the error:

arm-apple-darwin10-g++-4.2.1: .../Build/Products/Debug-iphoneos/libThree20.a: No such file or directory

The linker is running for the device (Debug-iphoneos, -arch armv7) and is being told to link libThree20.a from the device products folder. That folder is empty of that library because the library target was never built for the device. The simulator build works because the simulator products folder does contain a slice the simulator linker can use.

Historically this became common when Xcode stopped letting a dependency target inherit the architecture settings of the app that depends on it. Each target builds with its own ARCHS / VALID_ARCHS / EXCLUDED_ARCHS values, so a library pinned to a simulator architecture produces nothing usable for a device link, and the app’s link step fails on a path that resolves to nothing.

The same class of failure appears today with any prebuilt or vendored static library that ships only an x86_64 or arm64-simulator slice, with CocoaPods projects whose build settings drifted, and with test targets whose host application is misconfigured.

How to fix it

1. Make the library target build for the device

This is the root fix. Select the library target itself — not your app target — and open Build Settings.

  • Set Architectures (ARCHS) to $(ARCHS_STANDARD).
  • Clear any hard-coded value in Excluded Architectures (EXCLUDED_ARCHS) that removes arm64.
  • Set Build Active Architecture Only (ONLY_ACTIVE_ARCH) to No for Release, and make sure Debug is not forcing a simulator-only architecture.

Repeat for every dependency target in the chain. If your app links five libraries, all five need device-capable architectures.

Then confirm the product actually exists. Build the library scheme for a real device destination (Any iOS Device (arm64)), and check the output:

xcrun lipo -info ~/Library/Developer/Xcode/DerivedData/<YourApp>-*/Build/Products/Debug-iphoneos/libThree20.a

You want to see arm64 in the output. If lipo reports only x86_64 or arm64 with a simulator platform, the library is still not being built for the device and nothing downstream will work.

2. Verify the dependency is wired up, not just referenced

A library can appear in Link Binary With Libraries while nothing ever builds it. Open your app target’s Build Phases:

  • Under Target Dependencies, the library target must be listed. Without it, Xcode has no reason to build the library before linking your app.
  • Under Link Binary With Libraries, the .a must be present and must not be shown in red.

If the entry is red, remove it and add it again from the library’s build products. A stale reference to a product that no longer exists produces exactly this “No such file or directory” error.

Also check the scheme: Product → Scheme → Edit Scheme → Build should have Find Implicit Dependencies enabled, or the library target explicitly added to the build list.

3. Check Library Search Paths for stale entries

If Library Search Paths contains an absolute path to an old build folder, a checkout that moved, or a Debug-iphonesimulator directory, the linker will look there and find nothing.

In Build Settings, filter for Library Search Paths and reduce it to relative, inherited entries:

$(inherited)
$(PROJECT_DIR)/Vendor/Three20/build

Avoid absolute paths under DerivedData — those folders are disposable and change names.

4. Clean the build products, not just the project

Architecture mismatches survive a normal Clean because the stale products live in DerivedData. Delete the folder for the project and rebuild:

rm -rf ~/Library/Developer/Xcode/DerivedData/<YourApp>-*

Then build for the device again. If the error disappears and comes back on the next clean build, the problem is in step 1 or 2, not in caching.

5. For vendored binaries, check the slices you actually shipped

If the .a came from a third party, inspect it before blaming Xcode:

xcrun lipo -info Vendor/libSomething.a

A library built only for the simulator cannot be linked into a device build, no matter what build settings you change. You need a device slice, or a source build, or an XCFramework that carries both.

6. If the error mentions a .xctest bundle

Test targets fail differently but for a related reason: the test bundle has no host. Select the test target, open General, and check Host Application. If it shows a custom value that no longer matches your app, switch it back to your app target. Then clean and run the tests again.

How to prevent it

  • Set ARCHS to $(ARCHS_STANDARD) on every target in the project, including dependencies, and never hard-code a single architecture.
  • Keep EXCLUDED_ARCHS empty unless you have a specific, documented reason.
  • Prefer XCFrameworks over bare .a files for anything you ship — they carry device and simulator slices together.
  • Use relative, $(inherited)-based search paths; never point at DerivedData.
  • After adding a library, build once for a device destination before writing any code against it.
  • Commit project.pbxproj changes for architecture settings so a teammate’s clean checkout behaves the same.

FAQ

Why does the simulator build succeed while the device build fails?

Because the two builds use different product folders and different architectures. The simulator link finds a slice in Debug-iphonesimulator; the device link looks in Debug-iphoneos and finds nothing, since the library target never produced a device slice.

Is this the same as Undefined symbols for architecture arm64?

No. Undefined symbols means the library was found but a symbol inside it is missing — usually a missing framework or a category that needs -ObjC. No such file or directory means the linker never got a file to read at all.

Can I fix it by adding -all_load or -ObjC?

No. Those flags change which symbols get pulled out of a library that was successfully found. They cannot create a library file that does not exist for the architecture you are building.

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.