Weakly link static library via -weak_library - ios

Question:
Is it possible to weakly link a static library (Obj-C)?
Short Details
I do want my custom static framework (MyFramework.framework) to weakly link my other custom static library (libMyLibrary.a).
The functionality behind libMyLibrary.a is optional and can be omitted if there is NO libMyLibrary.a being linked by any 3rd party application that uses MyFramework.framework.
I am using -weak_library. My test application complains that static linker is unable to find MyLibrary's symbol MyClass within MyFramework's ABCTracker.o symbol:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyClass", referenced from:
objc-class-ref in MyFramework(ABCTracker.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
How to correctly setup weak linking?
Full Details
Setup
The Xcode project builds a static Mach-O binary and bundles it into a static framework. The result is MyFramework.framework bundle.
Other project builds a static Mach-O binary and the result is a static lib file libMyLibrary.a with a header MyLib.h
libMyLibrary.a is removed from MyFramework.framework target's Build Phases > Link Binary With Libraries (as suggested here). Only MyLib.h is available to use library's API from the framework's classes
NO Bitcode is used neither in the framework, nor in the library
MyFramework.framework, libMyLibrary.a and custom application are all written in Objective-C
The MyLib.h defines just one Objective-C class MyClass
MyFramework.framework uses MyClass from its own class ABCTracker conditionally checking for symbol availability during runtime, e.g. NSClassFromString(#"MyClass") == NULL
From MyFramework target's Build Settings I have set Other Librarian Flags and Other Linker Flags to same value -weak_library MyLibrary:
OTHER_LDFLAGS = (
"-weak_library",
MyLibrary,
);
OTHER_LIBTOOLFLAGS = "-weak_library MyLibrary";
Result
MyFramework.framework builds OK
After the build I have checked the symbols in the resulting binary and the output was emty (no symbols from the static library were built into static framework binary):
$ otool -L MyFramework.framework/MyFramework | grep MyClass
Despite that, my test application which is not linked with MyLibrary whatsoever, builds with ld error:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyClass", referenced from:
objc-class-ref in MyFramework(ABCTracker.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
What am I doing wrong here?
Other Observations
In MyFramework target I set Other Librarian Flags and Other Linker Flags of to same value:
-lMyLibrary. Result: otool shows the library's symbols are built into the framework (expected).
-weak-lMyLibrary. Result is the same as for lMyLibrary (is it expected?)
In my application target I set Other Linker Flags to -force_load MyLibrary. Result: the linker error slightly changes:
ld: file not found: MyClass
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I have also not been successful at getting XCode to properly weak link a static library, although I have the opposite problem from yours - for me nm showed all the symbols from the static library, and not with "U" (undefined) symbol type as you see when you weak link a framework.
But a workaround you can use is the following:
Create a new Cocoa Touch Framework project called MyWrapper.framework and add libMyLibrary.a to it
Add -ObjC to the linker flags to make sure all the symbols get
loaded (and -all_load if you need non Obj-C symbols)
Add your library's headers to the framework's Public Headers section in Build Phases
Build this framework (you'll want to set up an aggregate target to build for all architectures but that is a whole separate topic)
Open your MyFramework.framework project and add MyWrapper.framework to it, weakly linked (i.e. use the toggle to set it to Optional or if you prefer remove it from the Link Binary with Libraries phase and add it via -weak_framework to Other Linker Flags)
Now build MyFramework.framework
In your testing app, remove any reference to libMyLibrary.a
You should be able to run your testing app with no crash and your code should not detect the presence of symbols from libMyLibrary.a
Add MyWrapper.framework to your testing app and then you should see the opposite result - symbols from libMyLibrary.a will be found and usable.

Related

resolving link errors with ios workspace with static library

I've done this before, several years ago with Xcode 5 or 6. Now using Xcode 8 or 9, I seem to be missing someting.
No matter what I've done, when I try to build and link my project, I get the Linker message:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyClass", referenced from:
objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
This is not a duplicate question. It is not an architecture issue.
None of the other results I've found on S-O or google resolve this issue.
I'm obviously missing some build settings, but cannot figure out which one(s).
Between build attempts I've cleaned the build folder, and deleted DerivedData. Quit and restarted Xcode. Created a new set of projects with a new workspace and walked through the steps outlined below.
I'm writing in objective-C for this project if that matters (I don't think it does)
My question is what did I forget?
What I did --
Create a project for my framework and static library
a) create the project for a cocoa-touch framework - let's call it mySDK which creates mySDK.framework
b) Add a target for a cocoa-touch static library - let's call it SDK which creates libSDK.a
c) optionally build both targets -- they build fine
d) close the project
Create a project for my application - myApp - then close the project
Create a workspace - myWorkspace -- and open the workspace
Drag both project files from #1 mySDK and #2 myApp into the workspace
Build the framework and static library (both build and create the targets successfully)
Add the static library to myApp
a) Select myApp and go to build phases
b) Open Link Binary with Libraries
c) Drag from the library build products libSDK.a into the link binaries pane, set to "Required"
The library now appears in the Frameworks group-area in the myApp
7) Select the myApp project and go to build-settings
Add to Header Search Paths = "$(SRCROOT)/../mySDK/mySDK"
This resolves compile errors in finding the headers
Now I ask, why do I need to do anything else, shouldn't Xcode figure the rest out?
Various solutions or tutorials I've reviewed suggest adding:
Other Linking Flags = -ObjC
Library Search Paths = $(BUILT_PRODUCTS_DIR)
Library Search Paths = "$(SRCROOT)/../mySDK"
Changing Skip Install from YES to NO
Installation Build Product Location = $(BUILT_PRODUCTS_DIR)
I've tried all of these in different combinations.
Once I added the library to myApp I see that the Frameworks/libSDK.a file changes from red to black when I build the library so something in the workspace/project knows I built the library and it sees it.
So why when I try build myApp, do I still see the liner error:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyClass", referenced from:
objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Nothing I have done seems to clear that error. I am pulling my hair out trying to find a solution.
I have also checked that it is building all the appropriate architectures, confirmed it using 'lipo -info'
Xcode obviously knows about the library, why isn't it linking?
My app also compiled with no problem but would hit an error while linking to the static library. My library was based on C++.
I had 2 problems to fix in my case:
The headers lacked proper extern "C" declarations for C functions in a C++ file.
One .cpp file did not #include its matching header so the extern "C" would be properly applied to the compiled version.
The linker had issues because the compiler used a mangled name for the function due to the mistakes. Later confirmed this by looking in the .a file with a text editor. I found my function with "_Z11" prefixed and "v" suffixed.
There was another clue: the error was reporting the missing function name with an underscore at the front.
Undefined symbols for architecture arm64:
"_myCFunction", referenced from:
SwiftModule.swiftFunction () -> () in MySwiftClass.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Can't build project with MobileVLCKit (XCode)

I'm trying to make a single view application for iOS and tvOS with MobileVLCKit.
I downloaded files from git.
I ran ./buildMobileVLCKit.sh with -f key and got a framework ("MobileVLCKit.framework" folder containing MobileVLCKit binaty and Headers subfolder).
I temporary put the framework into ~/Desktop/FrameworkFolder/
I created new project in XCode, chose "File->Add files" and located the framework.
Added Framework Search Path in Project Options (~/Desktop/FrameworkFolder/, recursive).
Added #import into ViewController.h file.
Added VLCMediaPlayer *vPlayer = [[VLCMediaPlayer alloc] init]; into ViewController.m -> viewDidLoad method.
This is my binary:
imac:~ vlad$ file ~/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit: Mach-O universal binary with 5 architectures
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit (for architecture armv7): current ar archive random library
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit (for architecture armv7s): current ar archive random library
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit (for architecture i386): current ar archive random library
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit (for architecture x86_64): current ar archive random library
/Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit (for architecture arm64): current ar archive random library
When I try to build and run the project I'm getting two types of errors:
If I'm working with AppleTV project:
ld: in /Users/vlad/Desktop/FrameworkFolder/MobileVLCKit.framework/MobileVLCKit(VLCMediaPlayer.o), building for tvOS, but linking in object file built for iOS, for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
If I'm working with iOS project:
Undefined symbols for architecture x86_64:
"_AVAudioSessionCategoryPlayback", referenced from:
_Start in MobileVLCKit(audiounit_ios.o)
_Pause in MobileVLCKit(audiounit_ios.o)
"_AVAudioSessionModeMoviePlayback", referenced from:
_Start in MobileVLCKit(audiounit_ios.o)
_Pause in MobileVLCKit(audiounit_ios.o)
"_AudioComponentFindNext", referenced from:
_Start in MobileVLCKit(audiounit_ios.o)
"_AudioComponentInstanceDispose", referenced from:
_Stop in MobileVLCKit(audiounit_ios.o)
— at the begining, and:
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Showing first 200 notices only
— at the end of output. And 155 critical errors between.
I have tried to use precompilled framework as well, same result.
The questions are:
What am I doing wrong?
How can I solve this issue and successfully
build and run the project(s)?
Thank you for any help!
The reason of ld and clang errors was that the Framework and the Library has been built wrong.
The reason of multiple errors during working with iOS project is that required system frameworks has not been included.
I built the static library using XCode and the issue has been solved!

How to use private framework's .h file in Xcode

I am trying to use SBSRemoteNotificationClient.h file of SpringBoardServices framework downloaded from GitHub. I directly drag and dropped downloaded SBSRemoteNotificationClient.h file into Xcode and tried to compile it. But I am facing below error during compiling.
Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_SBSRemoteNotificationClient", referenced from:
objc-class-ref in MyClass.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I added #import "SBSRemoteNotificationClient.h" to my MyClass.m file.I also added path of SBSRemoteNotificationClient.h in Build Settings -> Search paths -> User Header Search paths like this /Users/awsuser006/Desktop/iphone-private-frameworks-master/SpringBoardServices/
But I am facing above mentioned error. Is this the right way of using .h files of private frameworks?
This is a linker error. The header was correctly parsed, but the framework symbols were not found. Make sure you are linking the SpringBoardServices framework.
Use
find /Applications/Xcode.app/ -name 'SpringBoardServices.framework'
to find it, then add -framework SpringBoardServices and -F /the/path/returned/by/find/ (without SpringBoardServices.framework at the end of the path) to your compilation flags.
Adding the framework using Build Phases > Link Binary With Libraries > (+) in your Xcode project may also work.
Find the framework symbols
Drag & drop them into Link with binaries...

Undefined symbols when referencing PLCrashReporter 1.2 beta 2 in static library and build in client

I have created a static library and added an aggregated target to build a .framework static framework so I can release to the users.
I have to use PLCrashReporter to this static library so I downloaded the latest version 1.2 beta 2 since ARM64 support is added and added the .xcodeproj file in a group inside my static library. Added the User Header Search Paths in the build settings of the static library target, in build phases added in Target Dependencies the CrashReporter-iOS-Device (CrashReporter) static library and Link Binary With Libraries added the libCrashReporter-iphoneos.a static library.
My static library builds successfully all the targets with no problem, but when it comes to adding my .xcodeproj project as a dependency in a UI client test project or even adding directly the .framework that I generate, the build for the simulator breaks.
I can run it on a device and work properly but it is major to use it in a simulator too.
If I hit build I get the following errors.
Undefined symbols for architecture i386:
"std::terminate()", referenced from:
___clang_call_terminate in libReporter-iOS.a(PLCrashSignalHandler.o)
___clang_call_terminate in libReporter-iOS.a(PLCrashAsyncImageList.o)
"___cxa_begin_catch", referenced from:
___clang_call_terminate in libReporter-iOS.a(PLCrashSignalHandler.o)
___clang_call_terminate in libReporter-iOS.a(PLCrashAsyncImageList.o)
"___gxx_personality_v0", referenced from:
Dwarf Exception Unwind Info (__eh_frame) in libReporter-iOS.a(PLCrashSignalHandler.o)
Dwarf Exception Unwind Info (__eh_frame) in libReporter-iOS.a(PLCrashAsyncImageList.o)
Dwarf Exception Unwind Info (__eh_frame) in libReporter-iOS.a(PLCrashSignalHandler.o)
Dwarf Exception Unwind Info (__eh_frame) in libReporter-iOS.a(PLCrashAsyncImageList.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I miss something for sure here!
Thank you in advance.
It looks like the i386 architecture is missing from libCrashReporter-iphoneos.a (The name of that file also suggests that it's for device only). Try to run lipo -info libCrashReporter-iphoneos.a to see if all the required architectures are there, if the i386 (required for simulator) is not there, you have to find the lib for i386 (or build it if you are building it yourself) and use lipo -create lib-iphoneos.a lib-iphonesimulator.a -output lib-all.a to create a library with all required architectures.
P.S. I have just downloaded the latest build from https://www.plcrashreporter.org and it seems like the CrashReporter.framework in iOS Framework contains armv7, armv7s and i386, so you might try that if you don't require arm64 and x86_64.
EDIT: see this for arm64 support (it's a beta from September).
EDIT2: I didn't pay attention to the std::terminate() at first, so if all the required architectures are there you might have to add libstdc++ to the Linked Frameworks and Libraries.
By the way.. can be useful to others..
the same settings:
-lstdc++ in linker flags
may solve similar headache for using MySQL in C/C++ in Xcode in OSX.
in fact when you link against libmysqlclient.a or libmysqlclient.dylib, you get the same error.
It has been broken in respect to previous installation of mysql.
verify to have:
//:configuration = Debug
OTHER_LDFLAGS = -lstdc++
//:configuration = Distribution
OTHER_LDFLAGS = -lstdc++
//:completeSettings = some
OTHER_LDFLAGS
Hope this can help.

Static Library linking error. Undefined symbols for architecture armv7s

The error is..
Undefined symbols for architecture armv7s:
"ABCD_Initialize(ABCD_data_type*)", referenced from:
-[MyViewController doSomething] in MyViewController.o
ld: symbol(s) not found for architecture armv7s
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I would like to list what all I've done
ABCD_Initialize is a function in header file of the static library i added.
Checked almost every related question.
Added all the files to target properly.
Linked the FAT file (.a file) in the build phases
lipo on FAT file says it is valid for armv6 armv7 and armv7s
Set Build Active Architecture Only to YES.
Added .h file related to the FAT file
restarted Xcode, Mac etc :)
A few things about my app
Created a workspace
Added a few other dependent .xcodeproj files to the workspace.
Added FAT file (of C++) and linked in build phases
set -ObjC flag in Other Linker Flags (to Load all members of static archive libraries)
Environment specs
Mountain Lion + Xcode 4.6 + iOS SDK 6.1
Let me know if you need more information. Any help is appreciated.
Thanks
J0k3r
My initial answer:
I'd say step 5 is incorrect.
If you're building a library, you want to build for all architectures, not just the "active architecture".
Set that to "NO" and see how it goes.
My second answer:
Also, make certain you've added "extern "C" in your library function declarations:
#ifdef __cplusplus
extern "C" {
#endif
ABCD_Initialize(ABCD_data_type*);
#ifdef __cplusplus
}
#endif
which help with demangling the symbols when they are linked against your app. Here's a related question with a decent explanation of what's going on.

Resources