I have a fat (armv7 + i386) library I use for development now. Works fine but now I am concerned if Xcode will strip other architectures (i386) and other configurations (Debug for example) when building for release?
I don't plan to debug this library since it is very old and stable. I just want to use it so I guess I don't need all debug symbols (?), furthermore when building for release I won't even need the i386 since that is for the simulator.
Do I need to set up something in Xcode so it gets stripped or I should better be using a non-fat library? If so how can I control this? :)
This library is about 500KB so I prefer not to put more info than I need.
The library stores separate object files for different architectures (i386, armv7, armv7s etc.). When you build the final app, it will only retrieve the required architectures and only the required object files from the library. The final version for the App Store will certainly not contain any i386.
Regarding release and debug configuration, it's different. This concept is not known by the library tool. So it cannot store separate debug and release versions. And when building the app, it will take whatever it finds. So to minimize your final app, you'll need to build both the library and the app with release settings.
Related
I have a project, in the Framework, there have *.framework, *.dylib, *.a libs.
I want to know what's them? and the difference between them.
Dynamic and static libraries
First of all, a library is a collection of resources and the code itself, compiled for one or more architectures.
Static libraries (*.a):
In the case of static libraries (*.a), the code that the app uses is
copied to the generated executable file by a static linker during
compilation time.
Dynamic libraries (*.dylib):
Dynamic libraries (*.dylib) are different from static libraries in the
sense that they are linked with the app’s executable at runtime, but
not copied into it. As a result, the executable is smaller and,
because the code is loaded only when it is needed, the startup time is
typically faster.
Dynamic and static frameworks:
For frameworks, we first need to understand the bundle concept (as a
framework is a specific kind of a bundle). A bundle is a file
directory with subdirectories inside. On iOS, bundles serve to
conveniently ship related files together in one package – for
instance, images, nibs, or compiled code. The system treats it as one
file and you can access bundle resources without knowing its internal
structure.
The library may also have additional resources: headers, localization
files, images, documentation, and examples of usage. We can bundle all
of this together in one bundle – and the name of this is the framework.
Static frameworks contain a static library packaged with its
resources. Dynamic frameworks contain the dynamic library with its
resources. In addition to that, dynamic frameworks may conveniently
include different versions of the same dynamic library in the same
framework!
Other useful references:
Hackernoon
Runtastic
Static library
Software framework
Update:
Thanks for accepting my answer!
Compiled for one or more architectures?
Every architecture requires a different binary, and when you build an
app Xcode will build the correct architecture for whatever you’re
currently working with. For instance, if you’ve asked it to run in the
simulator, then it’ll only build the i386 version (or x86_64 for
64-bit).
This means that builds are as fast as they can be. When you archive an
app or build in release mode, then Xcode will build for all three ARM
architectures, thus allowing the app to run on most devices. What
about the other builds though?
Naturally, when you build your framework, you’ll want developers to be
able to use it for all possible architectures, right? Of course you do
since that’ll mean you can earn the respect and admiration of your
peers.
Therefore you need to make Xcode build for all five architectures.
This process creates a so-called fat binary, which contains a slice
for each of the architectures.
arm7: Used in the oldest iOS 7-supporting devices
arm7s: As used in iPhone 5 and 5C
arm64: For the 64-bit ARM processor in iPhone 5S
i386: For the 32-bit simulator
x86_64: Used in 64-bit simulator
Raywenderlich: Multi-Architecture
I have my framework and I am supporting different architectures. For supporting simulator I am using x86_64 in valid architectures.
But when I use my framework in the app, I get the error while running the app on simulator :
'MyClass(In framework)' is unavailable: cannot find Swift declaration
for this class
Note : It works fine on device.
If memory serves me right, since 6-th version Xcode doesn't support so-called "universal" frameworks (frameworks that contains architectures for arm-family and x86_64/i386). So now when you build a framework Xcode will make two separate bundles for iphoneos and iphonesimulator (you can find them under corresponding folders in your derived data folder). The architectures these frameworks will contain depends on ARCHS variable. By default it's set to $ARCHS_STANDARD, that varies between platforms. You can play around with this setting, mixing architectures you really need, but Xcode will fail at build time if these architectures are incompatible (presumably x86_64 and arm-family architectures are considered incompatible).
To get round this limitation you actually have to do a little bit of "hard-work" yourself and "merge" framework bundles for simulators and devices manually.
1. Build your framework for iOS device and simulator
Here is nothing fancy, just go to your target build settings and ensure that "Build Active Architecture Only" (ONLY_ACTIVE_ARCH) is set to NO and add all required architectures for "Valid Architectures"(VALID_ARCHS, you have already done that):
Now build your framework, find the bundle file under the Product group in Xcode, and open it in Finder:
You should find two folders, one for each set of architectures:
2. Merge two frameworks into one
Now go into Debug-iphoneos folder, copy framework from there and paste it somewhere else, for example in the parent folder:
It will contain our universal framework in a short while. In order to do that we need first create universal dynamic library with the lipo tool. Open terminal, navigate to the folder where you are now (with the copied framework file) and type as follow:
$ lipo -create -output 'MyFramework' 'Debug-iphoneos/MyFramework.framework/MyFramework' 'Debug-iphonesimulators/MyFramework.framework/MyFramework'
If you are not in the derived data folder your paths for the framework libraries will differ of course. This command will produce new universal library containing both sets of architectures. Now just drag and drop it into your framework bundle and replace the existing one.
It's likely that your framework has architecture slices under a folder like MyFramework.framework/Modules/MyFramework.swiftmodule. Our universal framework should have slices for all supported architectures. You should already have arm slices inside, since we copied our framework from the Debug-iphoneos folder, so just find the same folder for the Debug-iphonesimulator and copy files from the folder to the destination framework's folder. You now should have this folder look something like that:
That's it! Now you have a universal framework that should work properly on both an iOS simulator and an iOS device.
3. Slice your framework when submitting to the Appstore
If you try to submit an application alongside a universal framework, it will be automatically rejected. So before submitting you will need to extract only devices' architectures one by one and then merge them into one framework using lipo:
$lipo -extract 'arm' 'MyFramework.framework/MyFramework' -output 'MyFramework-arm'
$lipo -extract 'arm64' 'MyFramework.framework/MyFramework' -output 'MyFramework-arm64'
$lipo -create -output 'MyFramework' 'MyFramework-arm' 'MyFramework-arm64'
Then copy it into your framework and remove redundant slices.
P.S.
Hopefully it helps, however this is kind of well known issue and there is already a lot of solutions in the internet. I suggest you googling terms like 'Create fat/universal framework iOS', and I believe you will find a lot of working scripts that will do all this stuff for you. Here is one I find the most helpful.
I see two possible options:
Your device and your simulator use different iOS versions, and your framework is using something from the latest iOS versions (also, I see that you have the option "Build Active Architecture only" switched to 'No'. Try to switch it back to 'Yes' and make a clean build. Probably, the compiler will find an issue, but it depends on how you link your framework to the app).;
Your framework built for a specific device. Try to switch to the 'framework' target, switch destination for build to 'Generic iOS device' and make clean builds for the 'framework' and the app.
Also, it will help if you update the question with the brief description of how you link your framework (via Workspace / via binary / via CocoaPods / etc.).
Usually, such issues caused by some stupid things, and you should check all theories, even dump or misleading at first sight :)
I've built a Framework for distribution (not open source),everything is working despite Xcode not having a nice support for developing Frameworks.
The problem is that when archiving for AppStore you get the error:
The executable <EXECUTABLE_NAME_AND_PATH>.framework contains unsupported architectures[x86_64,i386]
The solution to the error above is to strip out the architectures mentioned, as already discussed in this question and in other sources as well.
The problem is that to use the binary on Xcode it is necessary to have all architectures, but to archive I cannot have all of them. How to build the framework in a way that it contains all the architectures (or in a way that simulators accept it) and still be able to archive and upload to AppStore without using the custom scripts to strip the exceeding architectures?
It looks like you need to build two fat libraries, one for development and another one for deployment.
This way you can create two targets into your project (you can duplicate the existing target). One target will be used for development and be linked with the full framework. The other target will be used for archiving and will be linked to the reduced framework.
Hoping this helps...
xcodebuild can build a project with sdk set to either iphoneos or iphonesimulator but not both, so in order to generate a framework containing armv7 arm64 and i386 x86_64 architectures, I have to run xcodebuild twice and then use lipo to combine all the architectures into 1 universal binary. I see commercial framework that does this but it result in an incorrect info.plist file because it has a field, CFBundleSupportedPlatforms and all signs point to it only containing 1 value, e.g., CFBundleSupportedPlatforms = ( "iPhoneSimulator" ).
Seems like lipo shouldn't be used in this manner because it isn't officially supported by xcodebuld. Is there a better way to build a framework to contain all architectures?
I follow the question, but I suppose I am a bit puzzled why you want to unnecessarily bloat a single .framework with simulator-only i386 and x84_64 slices that are really only relevant to your development builds. Would you by chance be wanting to distribute a framework to other developers and want to make it work on simulator as well as device?
If so, you are on the right track with using lipo to join the thin binaries for device together or to join the thin binaries for simulator together, but shouldn't be trying to spawn one single device and simulator framework. Apple's own use of SDKs and Frameworks serves as the guide here. Within Xcode, there are two different platform SDKs -- iPhoneOS.platform and iPhoneSimulator.platform that contain the SDKs with only the slices for the relevant target architectures:
You can drill into each of these folders and find the UIKit frameworks do indeed follow the per-platform idea and are conditionally linked based on the SDK that is in use:
I'd further guess that you wanted to have one universal, all-architectures framework so that consuming developers didn't have to remember to swap out one .framework file for another depending on how they were compiling the app. The great news is that you can use conditional linking flags to be able to affect this without needing to do file-system swaps!
As folks adopt your library, part of the setup should be to use conditional linking -- Within the OTHER_LINKER_FLAGS option you can have per-configuration (Debug, Release, Ad-Hoc, etc.) build settings and can also have per-Architecture or per-SDK specific settings too:
To get access to these SDK-specific settings you'll need to click the + next to each of your build configurations where you want to custom tailor framework linking. You can then select the appropriate SDKs from the dropdown list and add your linker flags for each of the two target frameworks.
As many of you noticed; zxing does not work in latest xcode (4.5/ios 6)
Here is use case:
checkout latest version from trunk (as some fixes were already added)
create single view application in xcode 4.5 with ios 6.0
use README to add dependencies, paths etc (just follow step by step)
add zxingcontroller call to class (renamed to mm)
Compilation fails both for simulator and device
It shows 31 error like this one:
Undefined symbols for architecture i386:
"std::string::c_str() const", referenced from
all 31 errors are similar, difference is in symbols name
May be somebody knows how to solve it with this use case?
p.s. if you have app from previous Xcode, it works. Problem is only if you create new app in Xcode 4.5
The issue you have encountered seems to be C++ standard library related.
Actually, whenever you see linker failures in relationship with standard library objects (e.g. std::string), you should check the project settings on all linked libraries and the app-project itself. They usually need to match!
The original ScanTest (which builds ZXingWidget as a subproject) uses the following settings and those need to match your App build-settings if you use the library as is.
For making sure, I created a brand-new project using Xcode 4.5. That project uses ZXingWidget as a prebuilt library but not as a subproject - I dont like subprojects for stuff that is not my own - though this specialty wont influence the results.
The important setting is C++ Standard Library - make sure that is set towards Compiler Default
Little clarification
Actually, you do not need to use C++ Standard Library, you may as well use LLVM C++ standard library with C++11 support. But you will have to use that exact same library in all projects, sub-projects and libraries that link with your project. So if you insist on using the more recent version of that library (C++11 support), then you will have to build the ZXing library with those settings as well.
Last but not least, make sure your Architectures and Valid Architecture settings are matching over all projects and sub projects (fixing the common armv7s linker issue).
First, make sure your Architectures setting is set towards armv7 armv7s within all projects. Then also edit the project settings of all projects towards Valid Architecture armv7s armv7.
You might also want to switch the "Other Warning Flag" -Werror off. Seems to be necessary in Xcode versions > 4.5 (LLVM compiler > 4.1).
It works for me, have you enabled -lstdc++ in your list of Other Linker Flags in the Build Settings tab of the project target? It sounds like it is not recognizing the c++ symbols needed for zXing to build. If this is the case, the above advice should help.