Undefined symbols: "_objc_readClassPair" when opening existing project in Xcode 7

I wanted to look into a memory issue with the new Address Sanitizer in Xcode 7, so I grabbed both the GM and the 7.1 beta.


When I opened my existing workspace containing various Objective-C frameworks and an Objective-C app, I can't get it to build though.

I always get this error:


Undefined symbols for architecture x86_64:

"_objc_readClassPair", referenced from:

__ARCLite__load() in libarclite_macosx.a(arclite.o)

ld: symbol(s) not found for architecture x86_64

clang: error: linker command failed with exit code 1 (use -v to see invocation)


The same project builds fine in Xcode 6 with identical settings.


Not sure if this is a bug or an added setting in Xcode 7 that I'm missing.

Replies

What platform are you developing for?

What deployment target?

Are you using any static libraries? If so, please check that the static library deployment target matches the deployment target of the code that you’re linking the static library into.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I'm having the same problem. I'm building against the OS X 10.8 SDK (copied from the Xcode 5.1.1 bundle). My deployment target is also 10.8.


The root of the problem seems to be that clang is automatically linking in the static library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_macosx.a. As the linker error notes, this library references the symbol objc_readClassPair. However, that function wasn't added to libobjc until OS X 10.10. Hence, when linking against an earlier version, the symbol can't be found, and linking fails.


I can get my project to link successfully by building against the 10.11 SDK. However, the resulting binary is still going to reference a function that isn't present on pre-10.10 systems. If _ARCLite__load is invoked on such a system, objc_readClassPair will be NULL, so presumably the app is going to crash. For that reason, this seems like a bug.

I was able to overcome this same issue, in some of our projects, by turning off the build setting called "Implicitly Link Objective-C Runtime Support"

Some of our other projects still have this issue (I suspect the ones that are actually using ARC, but I'm not sure yet.)

Thank you, this fixed it for me

I'm building against the OS X 10.8 SDK (copied from the Xcode 5.1.1 bundle).

Huh? You copied the SDK from one version of Xcode and are using it in another? That’s not supported. The SDKs included in a given version of Xcode are the only SDKs supported by that SDK.

Why are you doing this?

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Yeah, turning off "Implicitly Link Objective-C Runtime Support" mostly fixed it for me, too, except that projects that use ARC still failed to link. However, I was able to overcome that by adding "-Xlinker -U -Xlinker _objc_readClassPair" to the "Other Linker Flags" setting for those projects. That tells the linker that it's OK for _objc_readClassPair to be undefined.


And I think that this genuinely is OK, because the linker is making _objc_readClassPair a weak import. Presumably, this is because libarclite was (correctly) compiled with a pre-10.10 deployment target, and (hopefully) any code that wants to use objc_readClassPair is checking if it's NULL first. Thus, I think I was probably wrong to call this a bug.

How else are we supposed to check for usage of API that wasn't available in previous SDKs? Although API availability is annotated in the documentation, of course, it's all too common that developers accidentially use functions from newer SDKs while still deploying for older SDKs. Unfortunately, the compiler gives no warning unless the project is compiled as a test with the oldest SDK (that is, the deployment target) the app should be able to support. At least that's still true for obj-c.

How else are we supposed to check for usage of API that wasn't available in previous SDKs?

I agree that Objective-C makes it hard to check this. However, using an old SDK on a new Xcode has two problems:

  • It prevents you from using new APIs in the new SDK.

  • It’s totally unsupported and you will run into weird problems.

Unfortunately, the compiler gives no warning unless the project is compiled as a test with the oldest SDK …

If you just want to compile as a test, that’s fine, but the person whose post sparked my comment (cstawarz on 15 Sep) was hitting problems at the link step, which implies more than just a compiler test.

Finally, there’s at least one third-party tool that can help out with this problem.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the third-party tool hint, didn't know about that. I will check it out.

Then what happened to the "we will always include two SDKs in XCode?"

10.11 is not even out yet? How would one ship an app now with XCode 7? I know its legal and an app might even work, but its all pre-release quality at this point.

You ask an interesting question. Last year around this time (IIRC), there was an Xcode beta that had OS X 10.10 and iOS 8 beta SDKs. When iOS 8 was released, the released Xcode went back to OS X 10.9 SDK, and there was immediately a new Xcode beta that put back the OS X 10.10 beta SDK that people had been using. It was a little confusing.


This year, it looks like Apple did the more obvious thing, of moving both the new OS X and iOS SDKs to release status at the same time. Because OS X 10.11 has already gone "GM release candidate", this is not really "pre-release quality". Rather, Apple is telling us that the SDK is not going to change for release, even if the OS itself has some last-minute fixes.


I'm not sure where you think the "two SDKs" promise came from. Did Apple say that?

Rather, Apple is telling us that the SDK is not going to change for release, even if the OS itself has some last-minute fixes.

Right. Xcode 7 and all of the SDKs within it are considered GM; you can use it to build and submit production apps.

I'm not sure where you think the "two SDKs" promise came from. Did Apple say that?

Not that I recall.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I agree that Objective-C makes it hard to check this.

I just happened to stumble across another approach you can use for this, namely, build with the latest Xcode and SDK and redefine the availability macros to flag any potential uses of unavailable APIs. I haven’t experimented with this myself, but it seems like an avenue worth exploring.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you, this fixed it for me

There's a few instructions on the internet (Stackoverflow and such) that tell you to do just this: Copy an old SDK into the current Xcode. The reason is that - even when setting the Deployment Target back to say 10.8, apps built with Xcode 7.2.1 won't run on anything less than 10.10 Yosemite. Even compiling the empty template app creats an app that fils to launch properly on 10.9 and 10.8 - empty menu and no window showing up.

Apparently, even yithout a single line of custom code, such apps appear to make use of 10.10 SDK features somehow.

So what would be the supported way to build a 10.8-compatible app with Xcode 7.2.1?