Changing symbol names and embedding bitcode - ios

tl;dr: I get this error message:
ld: -alias_list and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES)
cannot be used together
How do I fix it?
I am trying to create my own version of a third-party library. I want to make sure that none of my calls are going to the system version of this library, so I use --alias-list to put a prefix on all the symbols, and generate a header file which renames all the symbols from foo to MJB_foo. My build system then includes this header file with the --include option whenever I want to use this library.
This works great on Android and Linux (and I'm pretty sure it will eventually work on Windows too). However I get the above error when I try to link the shared library. How do I achieve the same effect?

In Build Settings of project you need to set Enable Bitcode to No. For iOS Apps bitcode is default but optional so you can send the app to AppStore without bitcode.
Bitcode re-optimize your app binary in the future without the need to submit a new version of your app to the App Store.
From Apple Doc:
For iOS apps, bitcode is the default, but optional. For watchOS and tvOS apps, bitcode is required. If you provide bitcode, all apps and frameworks in the app bundle (all targets in the project) need to include bitcode.
https://help.apple.com/xcode/mac/current/#/devbbdc5ce4f

What I have ended up doing is forcing the inclusion of the header full of #defines when building the library, as well as when using it. This allows me to drop --alias-list from the linker command line, so it is happy.
Sadly, this is not the complete solution. The library (it is OpenSSL) has a number of assembler modules, so those have to be patched with sed by the build script first.
It also has some macros which turn
FOO(SHA1)
into
void SHA1_Init(struct SHA1_CTX *ctx)
the problem is that SHA1 is one of the functions I am renaming, so it becomes instead:
void MJB_SHA1_Init(struct MJB_SHA1_CTX *ctx)
renaming the function is harmless (because it turns out it gets renamed uniformly), but I am not renaming the structs. The solution is to create another small file which renames MJB_SHA1_CTX et al back to SHA1_CTX.

*When bitcode is enabled for a target, all the objects, static libraries and user frameworks used when linking that target must contain bitcode.
Otherwise, an error or a warning will be issued by the linker. (Note: missing bitcode is currently a warning for iOS, but it will become an error in an upcoming release of Xcode .)
ENABLE_BITCODE should be consistently turned on for all the targets. If you use a library or framework provided by a third party, please contact the vendor for an updated version which contains bitcode."

Related

Error: Invalid Swift Support when uploading a build to iTunes Connect

I'm submitting my first build for TestFlight distribution and am getting the following error. Bitcode is turned off. Other answers seem decently old so figured I'd re-ask for 2018.
Invalid Swift Support - The files libswiftDarwin.dylib, libswiftMetal.dylib, libswiftCoreAudio.dylib, libswiftsimd.dylib, libswiftQuartzCore.dylib, libswiftos.dylib, libswiftObjectiveC.dylib, libswiftDispatch.dylib, libswiftCoreGraphics.dylib, libswiftCoreFoundation.dylib, libswiftUIKit.dylib, libswiftCoreMedia.dylib, libswiftAVFoundation.dylib, libswiftCore.dylib, libswiftFoundation.dylib, libswiftCoreImage.dylib aren’t at the expected location /Payload/MyApp.app/Frameworks. Move the file to the expected location, rebuild your app using the current public (GM) version of Xcode, and resubmit it.
I have a .dylib file that I compile for my project that lives at ./MyProj/Core/lib.dylib. I saw this browsing around as well
It's likely you have a plain dylib outside of a framework somewhere, which is only supported on macOS. Please review the Troubleshooting section of Tech Note 2435 for more context.
If having a bare dylib is indeed the cause of the problem, please file a bug for an error message that clearly explains this.
Have you seen this?
https://developer.apple.com/library/content/technotes/tn2435/_index.html#//apple_ref/doc/uid/DTS40017543-CH1-TROUBLESHOOTING
Search for "Embedded .dylib Files"
I would try to follow that steps, It should work.
Make sure you have the 'Always Embed Swift Standard Libraries' at its default setting in your main target and possible other targets (extensions).
Also make sure you don't archive Release version with a Debug setting (Scheme).
The solution here was to add a new target to my project, the first Framework option that Apple gives and to move the .dylib file and the interface.h file into it. Link the interface.h file into my framework.h file, import the framework into my main target
Happy to give more info (it's a longer answer) if anyone needs it. Just leave a comment.
1.In XCode 10.1, Apple has introduced new architecture for Arm64e used in A12 chipset.
2.The App Store and TestFlight don't accept submissions containing arm64e.
To remove Arm64e from swiftlib run below script, Please note that change path inside script file.
https://github.com/ndpiparava/Swift_StripArm64e

How to debug "Invalid Bundle" error which happens only after submitting to app store

I have a lot of frameworks in my app. App works fine in adhoc/enterprise release. Only if I submit to the app store for testflight testing I get this error email from apple:
Dear developer,
We have discovered one or more issues with your recent delivery for "My app's name here". To process your delivery, the following
issues must be corrected:
Invalid Bundle - One or more dynamic libraries that are referenced by your app are not present in the dylib search path.
Once these issues have been corrected, you can then redeliver the corrected binary.
Regards,
The App Store team
there is no specific information here. How can I debug it?
Got an answer from Apple Developer Technical Support which says it is a bug on Apple's side. this is the suggested workaround below which did not work for me:
To diagnose this issue, you should export the IPA you are sending to
the App Store from Xcode. Since IPAs are zip files, you can
decompress it by right clicking and saying Open With > Archive
Utility. You should find your main executable inside the unzipped
folder structure and run otool at the command line to see the library
list: otool -L
The list of paths you get should match what you find inside of your
IPA. All of your libraries should start with #rpath. A simple
comparison of everything in this list with the unzipped IPA folders
should reveal what is missing.
Once you know what is missing, go to your Xcode build phases setup.
There should be a build phase for either Copy Files or Embed
Frameworks that includes the missing library — you should just add the
library to the list. If you don’t see either of these build phases,
you can recreate it by adding a new Copy Files build phase, setting
the Destination to Frameworks, and adding the library to the list,
ensuring that Code Sign On Copy is checked.
If you don’t find anything missing in your main binary, make sure to
do the same search on any other binaries you may have, like for a
watchOS app or an iOS app extension.
If you find that all of the frameworks are in this build phase, please
take a look at the Embedded Binaries section of your app target’s
General page, and let me know if you see multiple levels of ../ next
to the binary that you found is missing.
Please let me know if it works for you!
I have encountered the same issue when uploading an app with watch support to the app store.
I was able to solve it with the hint from the first answer, using otool -L to analyze the binary from the ipa or xcarchive.
However, the problem was not with my frameworks (at #rpath) but with a swift lib. I noticed that libswiftWatchKit.dylib was missing in the frameworks folder.
The solution that worked for me was as simple as to set EMBEDDED_CONTENT_CONTAINS_SWIFT=YES in the build settings of the watch app (or the watch app extension, but not both). After that, all necessary swift libraries were correctly copied to the watch app path in the archive and upload to app store was working correctly.
Apparently, the watch app works and upload passes if you provide the necessary swift libraries only in the main app's folder.
After adding the custom Swift framework to my project I got this email after uploading the app to iTunes connect.
I got this email from iTunes store,
Invalid Bundle - One or more dynamic libraries that are referenced by your app are not present in the dylib search path.
The fix is simple for this issue,
Step 1: Make sure your Custom framework is added to Embedded Binaries in General tab of your target.
Step 2: Under build settings,
Set Always Embed Swift Standard Libraries = Yes for your main project target.
And Set Always Embed Swift Standard Libraries = No for your custom framework target.
This solved my problem and I was able to upload binary to iTunes connect.
Ref
Tried all the above solutions and did not work for me.
I was experiencing this issue in Xcode 10.1 recently and all my frameworks were referenced correctly (did otool -L and everything lined up).
Seems there were some changes in the apple validation process, may be a bug, may not be on Apple's end, but all my prior builds uploaded and validated fine -- and I did not add any new frameworks since.
Upon uploading the binary to iTunesConnect, I'd see the following error:
Invalid Bundle - One or more dynamic libraries that are referenced by
your app are not present in the dylib search path.
Invalid Bundle - The app uses Swift, but one of the binaries could not
link to it because it wasn't found. Check that the app bundles
correctly embed Swift standard libraries using the "Always Embed Swift
Standard Libraries" build setting, and that each binary which uses
Swift has correct search paths to the embedded Swift standard
libraries using the "Runpath Search Paths" build setting.
MY SOLUTION:
After days of debugging, what worked for me was to disable 'Include bitcode for iOS content' upon uploading the archive from Xcode organizer. Seems that this option modifies the binary which caused the validator to fail.
Or you can disable bitcode in your Build Settings
My Problem:
I had the same error with embedded frameworks.
The App project has Custom Framework project
Inside the Custom Framework project is another Custom Framework project
The app built to the simulator and to devices with no problem but failed the Apple test, returning "Invalid Bundle".
I inspected the package just like Taha had been told to by Tech Support and everything was present and correct!
My Solution:
I restructured the project so that the two custom frameworks sit side by side and one is no longer embedded within the other.
This looks to be an Apple validation problem since everything works fine on devices and the simulator but the work around was straight forward.
In my case, in the build settings, this was fixed when I added the following to the build settings for the library:
DYLIB_INSTALL_NAME_BASE = #rpath
The clue was a linker warning: 'YourLibrary has an install name beginning with “/”, but it is not from the specified SDK'
Had same issue. This happened to me because one of my Framework target was added to main target in "Link Binary With Libraries" but was not added to "Target Dependencies" and "Embedded Binaries"
I also received a similar mail from Apple:
Dear Developer,
We identified one or more issues with a recent delivery for your app,
"********. Please correct the following issues, then
upload again.
ITMS-90562: Invalid Bundle - One or more dynamic libraries that are
referenced by your app are not present in the dylib search path.
Best regards,
The App Store Team
I used my own framework for my watch app. I solved this issue by changing the framework option to "Embed Without Signing" in the Extension Target. The default option was "Do Not Embed".
I had the same problem, it was due to one framework not being present in the Frameworks subfolder in the app bundle.
I fixed it by adding a Copy Fields build phase, and adding the missing .framework file there.
This error message is also addressed in Apple Technical Note TN2435
Embedding Frameworks In An App: https://developer.apple.com/library/archive/technotes/tn2435/_index.html
You can find the error message under the heading "Missing Framework Bundle" with troubleshooting steps.
We had the same problem, and even after going through all the steps (see "Missing Framework Bundle"), the only thing that worked was disabling Bitcode.
So I struggled on this for two days. What it turned out to be was I had UITests checked in Archive for the Build for the Scheme I was archiving.
After unchecking it from Archive, re-archiving it, validating it (although validating it before always passed), and "Upload to AppStore" I did not get the e-mail from Apple informing me of Invalid Swift Support. Instead I got the e-mail that it'd been processed and is good to go!
In my case, I've had to add a framework from Notification App Extension to the main target (embed & sign in the main target, do not embed in the extension) - even though there was no mention about it in otool -L output.
Funny thing that Iterable official doc says that the framework should be embedded & signed in the extension - which would lead to another upload problem because of nested bundles.

Linking to iOS simulator binaries on OSX

I was curious what would happen if I linked to an iOS simulator framework in a Mac app. So I copied UIKit to it's own folder (so the Framework search path wouldn't include all the iOS simulator framework, as like CoreFoundation is both on Mac and iOS but has different headers), and dragged it into the link section in Xcode. The error Xcode gave me was:
building for MacOSX, but linking against dylib built for iOS Simulator
file '/Users/jonathan/Desktop/macuikit/UIKit.framework/UIKit' for
architecture x86_64
Both architectures are x86_64, so how can it tell the framework is specifically for the iOS simulator, I removed all references to iOS in things like Info.plist, even tried deleted everything but the UIKit binary, but the same error came up. Is there something in the binary it self that tells the linker which platform it can run on, rather than just the architecture? I looked at the Mach-O header but there is only fields for CPU type and subtype, and neither has a value for the simulator as expected.
After a little bit of digging, it turns out that the platform on which the library can run on is indeed specified in the binary. In fact, you can edit the binary in your favorite Hex editor and make the linker skip this check entirely.
This information is not specified in the Mach-O header (as you have already realized). Instead, it is specified as a load command type. You can see the available types by digging through the LLVM sources. Specifically, the enum values LC_VERSION_MIN_MACOSX and LC_VERSION_MIN_IPHONEOS look interesting.
Now, find the offset for this in our binary. Open the same in MachOView (or any other editor/viewer or your choice) and note the offset:
Once the offset is noted, jump to the same in a Hex editor and update it. I modified LC_VERSION_MIN_IPHONEOS (25) to LC_VERSION_MIN_MACOSX (24)
Save the updates and try linking again. The error should go away. Of course, you will hit other issues when you try to actually run your example. Have fun with LLDB then :)

Apple iTunes Connect App submission error

Apple iTunes Submission Error : Unable to process application at this time due to following error: bundle 'xyz.app' is missing a bundle executable.
Certificates and Profile : Checked
This is likely happening due to the use of a "fake framework" (either the one from https://github.com/kstenerud/iOS-Universal-Framework or variations of this design). Some libraries and packages had their resources bundled together as a "framework" to make the inclusion of headers, nibs, images and localizable strings easier for host projects. However, those frameworks were actually a mutant bundle and don't meet the definition/structure that Apple is enforcing now that they've added Cocoa Touch Frameworks.
Some solutions:
Split the "fake framework" into a separate .a binary, resource bundle and set of headers. I'd recommend using Cocoapods to package them up so that anyone trying to incorporate the library/bundle/headers doesn't have to deal with manual inclusion at multiple steps. You can still lipo together multiple .a files that are targeting the architectures for devices/simulators to create a universal binary and all will work fine.
Switch to using a Cocoa Touch Framework (though, these appear to only work for deployment target 8.0) and embed the binary into the app. If you go this route, you'll need to also make a separate bundle for your resources because your framework now contains a binary (and thus, adding it as a "resource" package is going to cause you to have multiple binaries in your app when you package it and it'll get rejected from the app store). See here for some info on creating an iOS resource bundle: http://jaym2503.blogspot.ro/2014/03/how-to-create-resource-bundle-in-ios.html . There are some other nuances and gotchas with this approach (such as if you lipo together the simulator/device binaries in the framework and then embed the framework, you'll get rejected from the app store for having a binary embedded that includes architectures for the simulator). Unfortunately, as of now there isn't much documentation from Apple on how to use these frameworks, so it's a lonely road.
I'd personally recommend the Cocoapod route.
Check that you are building for arm64 armv7 armv7s

iOS Xcode: Warn about methods not in minimum target SDK

Is there a way to have Xcode tell me when I'm calling a method that isn't available in the SDK of the minimum supported target?
For example, the method [NSURLConnection sendAsynchronousRequest:queue:completionHandler:]. This method is available on iOS5 and up. But my application's minimum target is iOS4.
If I use that method (sendAsync), I'd like Xcode to tell me that that method isn't available for the minimum target I'm trying to support.
I've tried putting __IPHONE_OS_VERSION_MAX_ALLOWED=40000 in the preprocessor settings, but that just triggers a bunch of Apple SDK errors that aren't helpful. (Probably because my active SDK is iOS5.1)
Is the only solution to get ahold of old SDKs and install them in Xcode?
Are there any easier solutions?
There is unfortunately no standard way of doing this. By setting the target OS to a lower number than the base SDK, Xcode will weakly link the libraries and frameworks. When doing that Xcode will not warn you for using methods that may not be available on the target OS.
You could temporarily set the base SDK lower, but that might not always work. Since you want to ignore most of the errors and warnings produced (because they are only called conditionally in your code path), and many warnings and errors are dependant on other error that you may need to resolve before the compiler will give any meaningful output.
I do not think there exist any static analysis tools for this, neither from Apple nor third party.
After doing some research, reading the Apple Doc about it, and trying a number of things. The solution is downloading an old Xcode DMG from Apple, grab the .pkg file for the same SDK as your deployment target and install it in your version of Xcode. Here's how:
Download older Xcode.dmg from Apple
Open the DMG
In Terminal, go into packages: "cd /Volumes/[DMG]/Packages; open ."
Find the SDK you want, something like iPhoneSDK_4.0.pkg
Install that package, but change the install directory to /Applications/Xcode/Contents/Developer
Restart Xcode if it was open.
Now that you have the same SDK as your deployment target, set your BaseSDK to the same. When you build you'll get warnings about missing methods. Your project may or may not successfully build with an older BaseSDK in a new version of Xcode, but that doesn't matter - you've just found the method calls you need to wrap in a feature check with respondsToSelector:.
As of Xcode 7.3, the compiler can now generate these warnings for you. All you need to do is set the -Wpartial-availability warning flag in the Build Settings, as described in this answer.

Resources