Does bitcode support weak linking third party frameworks? - ios

Question stated simply in title. Here is my setup:
Building a dynamic framework that optionally links (weak link) to GoogleInteractiveMediaAds.framework. For apps that use my framework, GoogleInteractiveMediaAds is an optional dependency, and the framework will work fine without it. This is currently working.
However the problem arises when attempting to rebuild from bitcode, as typically happens when exporting an Ad Hoc build with "Rebuild from Bitcode" selected. The bitcode compile process fails with:
ipatool failed with an exception: #<CmdSpec::NonZeroExitException: $/Applications/Xcode.app/Contents/Developer/usr/bin/bitcode-build-tool ...
And looking deeper into the log file I find the error description:
Failed to resolve linkage dependency MyFramework arm64 -> #rpath/GoogleInteractiveMediaAds.framework/GoogleInteractiveMediaAds: Could not resolve #rpath in #rpath/GoogleInteractiveMediaAds.framework/GoogleInteractiveMediaAds from MyFramework
error: GoogleInteractiveMediaAds not found in dylib search path
Note: GoogleInteractiveMediaAds.framework does include bitcode.
Obviously this error is avoiding by not selecting "Rebuild from Bitcode". If I were to answer my own question, I'd say, no, it looks like when compiling from bitcode, you cannot use weakly linked frameworks. Simply from the fact that the bitcode compilation step is trying to link to a framework which isn't included in the app target. However I haven't been able to find any official documentation surround using weak linking with bitcode, or any relevant StackOverflow answers about it, so I'm not sure if I'm missing something or if there is some relevant compiler/linker settings that I am missing to get this to work.

In your case, you will need to wait for the fix in framework itself.
We've got similar issue while distributing our framework, which I described here and I just wan't to share results of our investigation, because seems that no-one has published their results.
No needs to distribute without bitcode. Long story short, there were LLVM instrumentation included, which prevents AppStore processing. I've written a whole blog about XCode 12 and BigSur issues with XCFramework.
To sum up, here is a few required steps to make sure while creating XCFramework for distribution:
Using archive builds is a MUST, release build isn't enough
BUILD_LIBRARY_FOR_DISTRIBUTION must be set to YES
SKIP_INSTALL must be set to NO
GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO to turn off GCC instrumentation and remove them from the binary
CLANG_ENABLE_CODE_COVERAGE = NO to turn off code coverage tools from the binary
Having all of the above helped to solve our preparing and distribution problem and hopefully save you some time if you happened to face same issues as we did.

Related

Xcode 8 : Disabling bitcode and Umbrella frameworks

I'm currently building an Umbrella framework (before anyone say so, I know this is discouraged by Apple, but I am in the case were I'm the owner of all the sub-frameworks, they are not distributed if they are not part of this or another Umbrella framework I may create, and we are in a closed source configuration) within Xcode 8.
I've followed this post to create the framework: https://stackoverflow.com/a/41815368/2572568
Everything is working fine except that I got the following error:
dyld: Library not loaded: #rpath/B.framework/B
Referenced from: /private/var/containers/Bundle/Application/E0113060-CA91-47F8-BEE3-BDF1F847DB3A/app.app/Frameworks/A.framework/A
Reason: no suitable image found. Did find:
/private/var/containers/Bundle/Application/E0113060-CA91-47F8-BEE3-BDF1F847DB3A/app.app/Frameworks/A.framework/Frameworks/B.framework/B: required code signature missing for '/private/var/containers/Bundle/Application/E0113060-CA91-47F8-BEE3-BDF1F847DB3A/app.app/Frameworks/A.framework/Frameworks/B.framework/B'
app is the Application using the Umbrella framework A which has a sub-framework B
I found that disabling bitcode from all the projects is solving this issue (and that's what I am doing now) from this thread : https://github.com/CocoaPods/CocoaPods/issues/3661
So here are my questions:
What does disabling bitcode is exactly doing ? I found that Apple can run optimization after you submitted your code. Are these speed optimization or disk space optimization, or any other optimization ?
Am I doing something wrong building my Umbrella framework ? Is it possible not to disable bitcode ?
First of all:
I came into the exact same problem today and I couldn't fix it. But removing Bitcode fixt it for me. Thanks for that
To your questions:
Bitcode is something kind of similar to Java's Bytecode. Your app gets compiled completely, but not in machine code (like assembler). Your app is compiled to Bitcode. This helps Apple to build different versions of your app on their server. One for 64bit and one for 32bit devices. Then they separate both apps, which saves disk space on the actual device.
And they probably have some further optimisations, which could speed up the app. Generally it's not needed today.
I tried almost everything I could imagine and at the moment I would say: No it's not possible to disable bitcode, if you have a big umbrella framework. Can you check if you have sub-frameworks in your umbrella framework which do not support Bitcode ? Like AWS SDK, Facebook SDK...
It may be possible to support Bitcode if all sub-frameworks support Bitcode. This answer seems promising me, but it's a bit old: https://stackoverflow.com/a/27638841/1203713
Regards,
Alex
Ok so after a few more researches on completely unrelated questions, I found this thread : https://github.com/Carthage/Carthage/issues/535
In substance, this solve question 2 and another one : Yes, you can enable bitcode for your Umbrella framework.
To do so, you must manually set a User-defined setting (inside Build settings, click on the plus in the top bar) named BITCODE_GENERATION_MODE to bitcode. This will force Xcode to build you project with real bitcode and not only a bitcode subset.
You have to set this flag for all the frameworks under your Umbrella framework.

Using pre compiled dylib in iOS8+ or building dynamic framework out of dylibs?

I'm trying to use a fat dylib I've made that contains the latest version of tbb with code for all architectures I may be targetting (armv7, arm64, i386 and x86_x64)
Since iOS8 using dylib(s) is meant to be possible, in fact one of the error messages I found googling was the following one:
ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later
Which seems to suggest that embedding dylibs is actually possible and we aren't only restricted to the new so called dynamic frameworks, yet, when I try to run my project I get the following:
dyld: Library not loaded: #rpath/libtbb.dylib
Referenced from: /Users/user/Library/Developer/CoreSimulator/Devices/B4DCFF3E-10B2-4C01-953F-BD26D14300E7/data/Containers/Bundle/Application/8C84A844-97FC-4993-A37E-A456C4E2240F/TestTBB.app/TestTBB
Reason: image not found
I thought it would be due to the dylib not being automagically copied into the app being built so I added it to the "Copy Bundle Resources" section in the projects "Build Phases" and I've since made sure that the libtbb.dylib is in fact being copied into the app and yet I keep getting the message saying that it can't be loaded.
I've tried using the "Embedded Binaries" section under "General" but it seems to be restricted to using only the new framework types.
Is there anything I might be missing?
As you may have noticed I'm trying to use TBB which comes with its own build makefiles that generates dylibs, I'm assuming that if it does it's because dylibs can be used, legally since the iOS8+ update.
I have seen ways of getting dylibs to load, but these aren't the ones that Apple would accept in their AppStore, I'm trying to do this for an app that is currently on the AppStore and I have no plans of getting it removed or not accepted after an update so I'd like to go with whatever the new "legal" way is to get dylibs loaded. My app is targetting iOS9.2+ since the latest update so this shouldn't be an issue.
All I can find are ways to get dynamic frameworks loaded but no info about actual dylibs even though the error message clearly states that they could be used.
Alternatively, is there a way to build a dynamic framework out of existing dylib files?
Thanks in advance.

Xcode unable to find strip-frameworks.sh directory

I recently update Xcode to Version 7.1, which included Swift 2.1. I installed Swift 2.1 with no troubles. After attempting to run my project, I realized that I needed to grab the latest version of Realm, since the previous version did not support Swift 2.1. I deleted the old frameworks and imported Realm 0.96.2. Whenever I run, I now get this error:
bash: /Users/userName/Library/Developer/Xcode/DerivedData/appName-ghiroqitgsbvfhdqxsscyokyoouz/Build/Products/Debug-iphoneos/appName.app/Frameworks/Realm.framework/strip-frameworks.sh: No such file or directory
I suspected the problem was with the script that is required if you wish to submit your app the the App Store, so I removed the Run Script Phase, added a new one, and copied the script from the Realm documentation site:
bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Realm.framework/strip-frameworks.sh"
I thought that that would fix it, but it did not. I then thought that the problem may be in the Realm.framework or RealmSwift.framework files, so I removed them and re-imported them (Just in case I messed something up). Nothing changed. Does anyone know if there is a fix to this error?
Thanks!
-CodeIt
From the error message, it seems like, you didn't added Realm.framework and RealmSwift.framework to the Embedded Binaries pane, which you find in the General tab of your project, as shown below:
For further validation, you can check the tab Build Phases. It should look like below:
Note: Make sure that the run script phase comes after the Embed Frameworks phase.
Why is this script needed?
The vendored frameworks are not just single executables, but actually FAT binaries which are archives of linked executables on different architectures. This includes architecture slices for arm64 and armv7, which are necessary for deployment on the phone as well as i386 and x86_64 which are necessary for running the app in the simulator.
The strip-frameworks.sh script main responsibility is to take care of removing unnecessary slices. This reduces the final package size and is necessary for AppStore deployment because iTunes Connect rejects apps with simulator architectures.
More Details
The script works on base of the build setting VALID_ARCHS. Because that is changing the signed executable of the framework, it also needs to take care of code signing. Since introduction of bitcode, it also got further post processing as responsibility. It extracts the included *.bcsymbolmap files from the framework bundle and places them into correct path in the *.xcarchive.
The FAQ topic on Bitcode of PSPDFKit has a good explanation on what BCSymbolMaps are:
A BCSymbolMap is a lot like a dSYM for bitcode. Xcode builds it as part of creating the app binary, and also for every dynamic framework. It's required for re-symbolicating function/method names to understand crashers.
In my case, change the process order in Build Phases to solve
not OK
OK

What do these Dsymutil Warnings mean in XCode 4.5?

I am linking a static framework for iOS, against an armv7 ios 6 application, I suspect that the original binaries are from XCode 3.x and were compiled with GCC, and that I'm now linking it using CLang compiler. I do not have the source code for the framework, only the binaries:
(null): warning: (armv7) /.../DerivedData/.../armv7/HardwareObjectFile.o unable to open object file
I get 69 warnings like the above, one for every .o file linked into the static framework.
Is this warning serious for any reason? I have simplified the giant path which appears to indicate that the binary files in the library have hardcoded a path in "/Users/somedeveloperthatisntme" that could hardly help but Not Exist since I'm using this library on a computer that doesn't even have a folder named "Users/somedeveloperthatisntme".
Dsymutil appears to be a tool to "manipulate archived DWARF debug symbol files", although I know precisely nothing about what it is and what it does, notwithstanding the thorough documentation from Apple, which tells me what, but never ever, why. What is it doing, and what will this warning mean for me? I suspect I need a new library/static-framework from the vendor to clear this up?
Update: I am unable to solve this and it appears the cause lays with very old binaries compiled by a very old XCODE version, shipped as part of a mobile framework from a third party vendor. The issue in this case would be resolved by having that vendor rebuild their library, something I asked them to do because the warnings drove me nuts, but which they seem unable to do. In the end I ditched their technology and replaced it with something else. (Grin)
These errors are to do with the architectures you are using and the resources you are referencing. I don't understand the reasons myself, but if you want them to go away, go to Build settings, then Build Options and then select Debug information format and select DWARF.
I am on the other side of this, building a library for others to use, and I was able to alter the library project by setting 'GCC_GENERATE_DEBUGGING_SYMBOLS = NO' in the Build Settings to make those warnings go away in an Application project that consumed the output framework.
This isn't a solution to your problem, but if you're in contact with this vendor, you could pass this along.
The other answers contain helpful information but I wish to put the real answer down succinctly:
You can not fix this, and the meaning of the errors is simple: The current linker sees these library files as containing elements that can not be opened.
To solve the warnings, contact the vendor and get a recompiled library that has been rebuilt with a later version of CLANG.
What I did was just delete the /Library/Developer/Xcode/DerivedData folder and it fixed everything for me.
Another reason these warnings could occur is because of incorrect symbol stripping settings for release builds in a project. Contact the author of the framework and tell them to make a new binary with the proper symbol stripping settings.

Ho can I use adMob library for iOS without using -all_load linker flag

I'm adding adMob provide by google to my iOS app and I'm stuck on this part of the installation:
Add -all_load under Other Linker Flags in the project build info
If I add that flag, then another third party library breaks giving me the error message:
ld: duplicate symbol _vw_chartype_table_p in /Users/josh/ Projects/app/libs/libvt_universal.a(vw_ctype-3279EF26D0C25F3A.o) and / Users/josh/Projects/app/libs/ libvt_universal.a(vw_ctype-34AB9EC0B46D954C.o) for architecture i386
Is there any way to use the adMob library without using -all_load? For example, I've tried -force_load $(SOURCE_ROOT)/adMob/libGoogleAdMobAds.a
but
ld: file not found: /Users/USERNAME/Desktop/latest/bbbb/APPNAME/adMob/libGoogleAdMobAds.a
The reason Google suggests using -all_load is that they are using categories in their code, and Objective-C libraries with categories are not properly loaded by the llvm linker (well that was the case in 4.3 xcode, not sure about 4.4 with the newer clang).
So, I guess if you are brave you can try to just remove the all_load flag. It should build fine. If the bug is NOT fixed, what will happen is when you run your code, it will crash, since none of the categories the library uses will have been loaded. This might be a good thing to do in any case, as your project should build, and if it does not you can fix those problems first.
What I do suggest you do is use -force_load, which has llvm load the categories in the adMob library (among other things). To use it you MUST have a fully qualified path (ie starts at '/') to the library. Obviously if you use Terminal and run:
ls -l /Users/USERNAME/Desktop/latest/bbbb/APPNAME/adMob/libGoogleAdMobAds.a
its going to fail. So enter the proper path - hard coded - for now to just see if you can get the project to first build, then run. If it does you can later figure out what is the appropriate $(VAR) to use to find it inside your project.

Resources