Bitcode in a static library requiremnts

Hello,

we are shipping a static library to other developpers. We want to build it with the bitcode so that the developers can enable bitcode in their apps. The question is, does such a library require XCode 7 to build the app? In other words, if I ship a library compiled with OTHER_CFLAGS='-fembed-bitcode', does it requiere XCode 7 to compile the app using it or will XCode 6 work as well.


I'm trying to compile an app with XCode 6 that links against a static library (built with fembed-bitcode in XCode 7) and I'm getting a lot of linker errors



duplicate symbol _llvm.cmdline in: ... libMyStaticLib-8.0.0
duplicate symbol _llvm.embedded.module in: ... libMyStaticLib-8.0.0


If I compile the app in Xcode 7, it works fine.


What is the problem ?


cheers

I don't think so. I have a static lib from a 3rd party and it is compiling in Xcode 6.4.2 just fine. When I take that lib and migrate it to the tvOS beta xcode, that project also has no problems; though I have to turn off bitcode for linking phase since I am not using it. I see no abnormal behaviors from either setup.


Do you have a dependency target that is also linking into your lib? Your error logs indicate duplicate symbols rather than bitcode settings

Hi,


this issue occurs if dependency was compiled with Xcode 7 beta, and the main target that includes that dependency is being compiled with Xcode 6.4.

Solution: recompile dependency with Xcode 6.4.


P.S. might be good to move the main target to Xcode 7 GM and the issue will go away.

Well that's not a solution. I do not control what version of XCode developers who include my library use. Yet, I want to compile my library with XCode 7 to support bitcode.

No, I reprduced this with a plain app that links only against my static library

EDIT:


There's no way Xcode 6 can support Bitcode.

In order to support Bitcode, one needs to compile with Xcode 7.

One binary that supports Bitcode cannot be used in a project that doesn't support Bitcode.


So, in any case: ship 1 binary without Bitcode for those who don't support it (a build with Xcode 6), and one binary built with Xcode 7 and Bitcode enabled.

I think the problem appears when I compile the simulator slice of the library with the

-fembed-bitcode
flag. In other words, I use now the bitcode flag only when compiling the library for the device and it works fine.


Here is a part of my build script



# simulator without bitcode
fail unless system "xcrun xcodebuild -workspace #{WORKSPACE} \
                                     -scheme #{SCHEME_SDK} \
                                     -configuration #{configuration} \
                                     -sdk iphonesimulator9.0 \
                                     -derivedDataPath #{derived_data_path} \
                                     clean build | xcpretty -c"


# device with bitcode
fail unless system "xcrun xcodebuild OTHER_CFLAGS='-fembed-bitcode' \
                                     -workspace #{WORKSPACE} \
                                     -scheme #{SCHEME_SDK} \
                                     -configuration #{configuration} \
                                     -sdk iphoneos9.0 \
                                     -derivedDataPath #{derived_data_path} \
                                     clean build | xcpretty -c"
# fat library
arm_file = "#{derived_data_path}/Build/Products/#{configuration}-iphoneos/lib#{target}a"
x86_file = "#{derived_data_path}/Build/Products/#{configuration}-iphonesimulator/lib#{target}.a"
final_file = "#{BUILDS_SDK_LIB_DIR}/lib#{target}-#{sdk_version}.a"


fail unless system "lipo -create #{arm_file} #{x86_file} -output #{final_file}"

Simulator linker is "hungry" and it links in a different way than ARM linker. This can give you a hint why there's a difference, even though this problem might be comming from the compiler and not linker.


The idea is that there's no way to enable Bitcode for a library and try to use that library from a target that doesn't enable Bitcode. This fundamental idea is a strict rule behind supporting Bitcode: Bitcode (iOS, watchOS)

So enabling bitcode only for the device arch (armv7, arm64) and disabling it for the simulator arch (i386, x86_64) is not the correct solution even if the app compiles / archives fine in XCode 6.4 ?


> One binary that supports Bitcode cannot be used in a project that doesn't support Bitcode.


I cannot find a Apple doc where this is clearly stated.


I could indeed ship two libraries (one with bitcode, the other without) but this makes things more complicated. I'd have to e.g. pubish a new CocoaPod spec, update my build script to create, upload. publish two different libraries, ...

>> One binary that supports Bitcode cannot be used in a project that doesn't support Bitcode.


> I cannot find a Apple doc where this is clearly stated.


I agree that statement regarding enabled support of Bitcode doesn't explicitly clarify a rule for "disabled support of Bitcode", I just did not manage to build targets with Xcode 6.4 with dependencies built with Xcode 7.


Would be great if someone from Apple could elaborate on this.. 🙂


> So enabling bitcode only for the device arch (armv7, arm64) and disabling it for the simulator arch (i386, x86_64) is not the correct solution even if the app compiles / archives fine in XCode 6.4 ?


I guess the correct answer is: if it works for you doesn't mean that it will work for everyone else.


Let's cosider what happens:

1. Compiled library with Xcode 7 includes simbols wrapped with _llvm... markers

2. ARM build doesn't include symbols twice if they were included before - Xcode 6.4 linking works "as expected"

3. Simulator build includes symbols as many times as they are linked - Xcode 6.4 linking fails due to duplicate symbols


I think this is the idea behind the behaviour your are seeing. In general it's better to support just 1 IDE, this is not an SDK but this is a tool, so I see it as "use as latest one as you can find" 🙂


> e.g. pubish a new CocoaPod spec, update my build script to create, upload. publish two different libraries, ...


I don't see a problem in having '0.0.1-XCODE6' version marker in your specs file - this is temporary anyway

I see. So the safest way would be to ship two versions of our SDK.

Hi JanC,


We're also providing static library and stumbled on the bitcode issue. For our library it seems to be OK to include bitcode using XCode7 and still be able to build apps with e.g. XCode6

1) build lib with XCode7 (GM version), enable bitcode.

2) build app using XCode6 (GM version) linking with our bitcode-enabled lib works OK. Runtime test OK only on iPad running iOS7.1.2, i.e. no simulator.


Best regards,

Håkan

Hi HakanBerg,

yes it looks like this actaully works. I had a look at how other 3rd party SDK handle this (Fabric, Crashlytics) and they do enable bitcode for the device arch slices. I wrote a small script that checks which slices include them. Here is the result for the latest Fabric


~/extract.sh Crashlytics.framework/Crashlytics
Extracting slice for armv7 to /tmp/lib_Crashlytics_armv7.a
Bitcode marker:   sectname __bitcode

Extracting slice for armv7s to /tmp/lib_Crashlytics_armv7s.a
Bitcode marker:   sectname __bitcode

Extracting slice for i386 to /tmp/lib_Crashlytics_i386.a
Bitcode marker: NO

Extracting slice for x86_64 to /tmp/lib_Crashlytics_x86_64.a
Bitcode marker: NO

Extracting slice for arm64 to /tmp/lib_Crashlytics_arm64.a
Bitcode marker:   sectname __bitcode
Bitcode in a static library requiremnts
 
 
Q