Wrapping static library in Cocoa Touch Framework - ios

I have a fat static library with 2 architecture slices (armv7, arm64).
I'm trying to make it work with swift and wrap it into Cocoa Touch Framework.
What I do:
Create Cocoa Touch Framework project
Drag .a static library with headers
Set OTHER_LDFLAGS to -all_load
Set ONLY_ACTIVE_ARCH to NO
Set VALID_ARCHS and ARCHS to armv7 and arm64
Build with Release build configuration
Grab .framework file from DerivedData/../../Products/
When I put this .framework into my swift project, add to Embedded Binaries section in my targets general settings, import framework and use one of its classes, I'm getting undefined symbols for architecture arm64 or undefined symbols for architecture armv7.
EDIT:
Not sure if it helps but I've noticed that size of static library is about 34MB but size of generated .framework is about 12MB.
EDIT 2:
I ran nm -arch arm64 -g myLibraryName on both static library and generated dynamic library. The dynamic library doesn't contain all symbols that static library has. Seems like XCode build process strips lots of them.

I think you have also forgotten to add :
Project->Target->Build Phases->Link Binary With Libraries:
add + the: libz.dylib or libz.tbd
(Since Xcode 7 the *.dylib files are now *.tbd files)
Be sure to also clean the folder: /User/yourname/Library/Developer/XCode/DerivedData
P.S: If you want you should also be able to add the libz.tbd from "Other Linker Flags" in the Build Settings by adding the argument -lz.

Related

How can I get the Xcode linker to remove duplicate symbols it finds?

So I recently converted a universal/fat framework to an XCFramework and I need to replace the old framework with the new XCFramework in an app.
The app had the below linker flags:
OTHER_LDFLAGS = -ObjC -force_load path/to/FrameworkName.framework/Versions/A/FrameworkName -lstdc++
Migrating to XCFramework, in order to use the correct framework inside the XCFramework, I figured it would make sense to do the following:
OTHER_LDFLAGS[sdk=iphoneos*] = -ObjC -force_load path/to/FrameworkName.xcframework/ios-arm64/FrameworkName.framework/Versions/A/FrameworkName -lstdc++
OTHER_LDFLAGS[sdk=iphonesimulator*] = -ObjC -force_load path/to/FrameworkName.xcframework/ios-arm64_x86_64-simulator/FrameworkName.framework/Versions/A/FrameworkName -lstdc++
On building, Xcode could not find the XCFramework's headers, most likely because FRAMEWORK_SEARCH_PATHS (which we've historically used) does not work with XCFrameworks. So I also added the XCFramework to the "Link Binary With Libraries" build phase in order to get Xcode to find the headers.
Here comes the problem. Xcode now tells me that there are duplicate symbols, probably because I added the XCFramework to the "Link Binary With Libraries" build phase and also force-loaded the internal static library using linker flags. I have to do the latter so that the entire contents of the static library will be linked, but I also had to do the former because Xcode could not find the headers otherwise.
Is there a way (maybe another linker flag) to get the Xcode linker to remove duplicate symbols it finds? Or as an alternative, is there a way I can get Xcode to find XCFramework headers without having to add the XCFramework to the "Link Binary With Libraries" build phase?
I should also add that removing the -ObjC linker flag fixes the problem, but I don't want to risk breaking anything in the other frameworks being linked (since the flag links Objective-C code that static analysis cannot resolve as being called directly). I'm willing to provide more information if needed.
You shouldn't need to list the framework in OTHER_LDFLAGS at all. You should just add the xcframework to "Link Binary With Libraries" and remove it from OTHER_LDFLAGS. The whole point of xcframeworks is you don't need to provide the full internal path to the correct architecture.
This has nothing to do with the -ObjC flag. That still goes in your OTHER_LDFLAGS. Note that this is redundant with -force_load. -force_load was a workaround for a bug prior to Xcode 4. See QA1490 for details. The workaround recommendation was removed in 2014.

XCode Framework doesnt contain dylib symbols

I'm trying to integrate 2 dynamic libraries (written in C) together with its API header (one header) into a xcode framework, let's call it nanogen_c, so that I can call its functions inside a swift application.
For this I'm creating a framework in xcode, build it, and then I would expect the framework to contain the symbols of the dynamic libraries, so that ultimately I can create a xcframework containing both the arm64 and x86_64 frameworks, and when including it in a project it would be able to link.
But when checking the symbols of the framework, it's (almost) empty:
% nm -gU nanogen_c
0000000000007ff8 S _nanogen_cVersionNumber
0000000000007fc8 S _nanogen_cVersionString
And so when creating an xcframework out of these, I get linking issues because the function symbols are not found in the framework.
I'm pretty sure I'm missing some step in building the framework, but I can't figure out what...
The steps I do to make the framework (here for the arm64 architecture):
Create new Xcode project > Framework called nanogen_c
Drag libraries and headers into the project
At pop-up : Check ‘Copy items if needed’
In project settings > Build Settings
Set ‘Enable Bitcode’ to No
Set ‘Build Libraries for Distribution’ to Yes
Set ‘Skip Install’ to No
In project settings > General > Frameworks and Libraries
Change ‘Embed’ options for both dylibs to ‘Embed & Sign’
In project settings > Build Phases > Headers
Move the API header to public
In nanogen_c.h framework header, append this line at the end:
#import "nanogen_c/<name_of_api_header>.h"
Set build target to ‘Any IOS Device (arm64)’
Press ‘cmd + B’ to build
Framework is built into /Users//Library/Developer/Xcode/DerivedData/nanogen_c-/Build/Products/Debug-iphoneos/nanogen_c.framework
Check contents of nanogen_c.framework, it contains the dylibs and header, but nanogen_c file doesnt contain the symbols from the dynamic libraries.
I know that the dynamic library itself contains all the necessary symbols, because when manually adding linker flags to the xcode project it succesfully links/builds, however this is no permanent solution because afterwards when trying to install the application to the iphone, the dynamic libraries are not installed with it.
Does anyone know what I'm missing?

iOS import custom framework into project

I've developped a framework which I want to use in my projects. Everything went right until I tried to build my project. Here the error description :
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_ClassInFramework", referenced from:
objc-class-ref in ClassInMyProject.o
ld: symbol(s) not found for architecture arm64
My Architectures build settings are :
$(ARCHS_STANDARD)
and arm64 armv7 armv7s for valid arch
(same settings in my project and my framework, there are all default settings)
I can import myframework and build with no issue, but I get that error when I tried to use a class.
I'm on XCode 8.2.1, my Framework is a Cococa touch Framework, written in Objective-C, my project is written in Swift 3.0
I imported my framework by copying the output from Products and added it in Linked Frameworks and Libraries in my project
I've tried several different settings but none of them work.
You should remove the project folder from Xcode Drived Date and restart your Xcode then clean your project and run it.
I didn't solve my issue but I've managed to do something similar.
Instead of creating a Cocoa touch framework I created a Cocoa Touch static library and it worked.
I build my library,
I get the products (*.h and .a files), copy them in my project,
I add the lib.a in Linked Frameworks and libraries,
I create the Bridging Header and #import my "customlib.h",
Magic ! It works I can use my class.

Xcode - Created an iOS framework but can't use it in a project

I've created an iOS framework with this tutorial: http://www.raywenderlich.com/65964/create-a-framework-for-ios#comments
When I add it to a completely new project, I can import my public header and I can build it successfully. The problem comes when I try to create an instance of an object from the framework; when building it, fails with 40 errors:
All errors are displayed like this:
Apple Mach-O Linker Error "_OBJC_CLASS_$_AVPlayerItem < this is an example.
At the bottom it shows this message > Symbol(s) not found for architecture arm64
At first I thought the problem was that the framework I created wasn't supporting arm64. I executed the following line in Terminal to check which architectures were supported by my framework:
xcrun lipo -info MyFramework
The output is > Architectures in the fat file: MyFramework are: armv7 i385 x86_64 arm64
I'm using Xcode 6.4.
Thank you.
UPDATE: Here are some images of the error list:
Thanks!
I could be wrong but I think that in your MyFramework project you used several iOS frameworks like AVFoundation and also C++ standard library (libstdc++.6.dylib). In your fat library you don't have them. You need to add this dependencies manually to that project.
Another good tutorial about creating iOS Framework is iOS Framework Tutorial
Go to Build Phases in your Xcode settings. Select Target Dependencies. Add your framework Target (with Tests target). And Clean the project and delete your all derivedData and Run project. Very Easy.

How does iOS and Xcode link custom frameworks

I have a project with includes custom frameworks, but these custom frameworks also include custom frameworks.
Here's a sample structure, where the bullets are the included frameworks:
App
FrameworkA
FrameworkB
FrameworkC
FrameworkA
FrameworkC
FrameworkB
FrameworkC
Since FrameworkA and FrameworkB link FrameworkC, along with my App using Frameworks A, B, and C; are they all linked together or is the framework copied in multiple places?
Does this increase the size of the app?
In this example FrameworkC has assets, if it's copied multiple times wouldn't that unnecessarily duplicate data? Or this there a better way?
iOS frameworks are a collection of header files and a fat static archive library. iOS does not support frameworks containing shared libraries.
A fat static archive library is a collection of multi-architecture object files, the object files can be extracted as needed by the linker to create an executable artifact. iOS executables are self contained executables (except for system libraries which are shared objects).
Fat archives can be examined with lipo.
cd FrameworkA.framework
lipo -info FrameworkA
Architectures in the fat file: FrameworkA are: armv7 armv7s i386 arm64
When you create a Framework, the linker tool is not used because the frameworks (in your case FrameworkA and FrameworkB) are not executable artifacts. The dependent framework is included in the framework project because the compiler requires the header files to create the Framework A and B object files. Any references to symbols in frameworkC remain unresolved.
If you inspect the contents of FrameworkA or FrameworkB using the "lipo" and "ar" tools and extract an object file, then dump the object file symbols using "nm", you will notice any references to symbols in FrameworkC remain unresolved.
Note: You need to install the Xcode commandline tools to do this.
cd FrameworkA.framework
lipo FrameworkA -thin armv7 -output FrameworkA_armv7.a
ar -t FrameworkA_armv7.a
objectA1.o
objectA2.o
objectA3.o
ar -x FrameworkA_armv7.a objectA1.o
xcrun --sdk iphoneos nm -p objectA1.o
...
00000188 T FrameworkAFunction
U FrameworkCFunction
...
This is why when you create an App, you need all three Frameworks (A,B and C) included in the project. When the linker reads an unresolved symbol in one of the App object files it will search framework A and B. When the symbol is resolved, it reads in the whole object file from the archive that contains that symbol. The linker must then resolve any unresolved dependent symbols in that object. If one of those unresolved symbols is in FrameworkC, it will pull in the object containing the dependent symbol from FrameworkC
So to answer your questions:
Frameworks A,B and C are linked when the App is linked, only the objects required to resolve all symbols are copied from the Frameworks into the app executable.
Yes, copying in objects increases the size of executables, but there are no multiple copies of any of the objects.
The assets in FrameworkC are only copied once, when the final App bundle is assembled by xcode.

Resources