I'm porting a sizeable codebase to iOS. The simplified version of my scenario is as follows:
- I have a C++ library, built from the command line. I can run code from it from the iOS simulator, so I believe it's correctly built.
- I have the skeleton iOS application created by Xcode
I want to add logging to the C++ library. I have a trace() method which takes fmt, ...
. I compile that .cpp using -x Objective-c++
, the code is as follows:
void trace (const char* sFmt, ...)
{
va_list args;
va_start(args, sFmt);
NSString* sFmt2 = [ NSString stringWithUTF8String: sFmt ];
NSLogv(sFmt2, args);
va_end(args);
}
The library compiles just fine. However, when I try to link the app, I get a linke开发者_JAVA技巧r error:
".objc_class_name_NSString", referenced from: literal-pointer@__OBJC@__cls_refs@NSString in lib.a(trace.o)
This is strange because I can use NSString and NSLog from a .mm file in the project itself. The Foundation framework is linked. Moreover, just to test, instead of calling NSString from my library I added a helper foobar() to the .mm in the project, which does this
void foobar (const char* sFmt)
{
NSLog([NSString stringWithUTF8String:sFmt]);
}
When this is called from the library function above, it works!
Everything I read about this kind of error involves a "just updated my SDK" scenario, which is not my case. I started doing iOS stuff literally two days ago, I haven't changed the default project settings, etc.
My guess is that name mangling is failing at some point, because I know NSString is indeed linked, but it seems the name refrenced by the library is different to the linked one.
Any ideas?
Your linker output indicates that your command-line-built library is lib.a, which indicates to me that it's a static library. I'd guess that, not being a dylib, it doesn't know how to use the dyloader to find missing symbols at runtime. Relatedly, I suspect that the iOS project will link in these System libraries dynamically (even though non-OS developers can't create dynamic frameworks), whereas your static C++ library will expect those symbols to be resolved at link time.
I suspect that any of these three things would resolve the issue: (in descending order of attractiveness)
- statically link against the right libraries when building the C++ library
- make the C++ library a dylib instead of a static library (so it will expect to find missing symbols at runtime using the dyloader)
- link your whole app statically (so the NSString class symbols are present at app link time) (This is a bad idea, if it's even possible at all, but would likely solve the problem.)
Hope this helps!
I was able to fix this by using libtool
instead of ld
, passing it -framework Foundation
, and passing -fobjc-abi-version=2
to gcc
.
精彩评论