18

I've been experimenting with porting an Obj-C library to Swift, and I've run into a problem where the linker fails to build a static library when Swift code is in the project.

As a minimal reproducer, go into XCode6 and create a new iOS Static Library. It'll give you a project with a blank .h and .m file. This will compile fine. Then, add a new .swift file to the project (with or without creating a header bridge). This too should compile fine, but instead it fails during linking:

Libtool /Users/alexkarantza/Library/Developer/Xcode/DerivedData/Test-alenfoymgkewlghfjjvizjjuvign/Build/Products/Debug-iphonesimulator/libTest.a normal i386
    cd /Users/alexkarantza/Workspace/Test
    export IPHONEOS_DEPLOYMENT_TARGET=8.0
    export PATH="/Applications/Xcode6-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode6-Beta.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static -arch_only i386 -syslibroot /Applications/Xcode6-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.0.sdk -L/Users/alexkarantza/Library/Developer/Xcode/DerivedData/Test-alenfoymgkewlghfjjvizjjuvign/Build/Products/Debug-iphonesimulator -filelist /Users/alexkarantza/Library/Developer/Xcode/DerivedData/Test-alenfoymgkewlghfjjvizjjuvign/Build/Intermediates/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/i386/Test.LinkFileList -ObjC -L/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -Xlinker -rpath -Xlinker /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -Xlinker -force_load -Xlinker /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a -Xlinker -sectalign -Xlinker __SWIFT -Xlinker __ast -Xlinker 4 -Xlinker -sectcreate -Xlinker __SWIFT -Xlinker __ast -Xlinker /Users/alexkarantza/Library/Developer/Xcode/DerivedData/Test-alenfoymgkewlghfjjvizjjuvign/Build/Intermediates/Test.build/Debug-iphonesimulator/Test.build/Objects-normal/i386/Test.swiftmodule -o /Users/alexkarantza/Library/Developer/Xcode/DerivedData/Test-alenfoymgkewlghfjjvizjjuvign/Build/Products/Debug-iphonesimulator/libTest.a

error: /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: unknown option character `X' in: -Xlinker
Usage: /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static [-] file [...] [-filelist listfile[,dirname]] [-arch_only arch] [-sacLT] [-no_warning_for_no_symbols]
Usage: /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -dynamic [-] file [...] [-filelist listfile[,dirname]] [-arch_only arch] [-o output] [-install_name name] [-compatibility_version #] [-current_version #] [-seg1addr 0x#] [-segs_read_only_addr 0x#] [-segs_read_write_addr 0x#] [-seg_addr_table <filename>] [-seg_addr_table_filename <file_system_path>] [-all_load] [-noall_load]

This happens if I'm targeting the simulator or the device. It looks like perhaps having the Swift file in the project is causing it to use linker options normally reserved for executables, even though the target is a static library? I don't know enough about the build options to know if this is a bug in the beta, or some option I should be configuring. It seems questionable that the build would legitimately fail on such a trivial example. Any thoughts?

karantza
  • 459
  • 3
  • 11

5 Answers5

16

To answer my own question after some discussion in the comments, it is simply not possible to build static libraries that include Swift code yet. I'm writing this as of Beta 4, and the release notes still say, under "Known issues in Xcode 6 beta 4":

Xcode does not support building static libraries that include Swift code. (17181019)

karantza
  • 459
  • 3
  • 11
3

I have been looking at this issue too for a while, here is what I found:

First, in Xcode 6 Beta, there is no language selection when you create Cocoa Touch Static Library, the language is set to Objective-C by default, though you can add Swift file to the project, it gives error like in your question as a result. My interpretation is that it is Apple's intention to steer away from creating Swift static library.

So If you intent to build a library that leverages power of Swift, use Cocoa Touch Framework instead of Static Library. I have written steps on creating framework project and app project, you can find it here. Note in that example, I created an Objective-C framework project. Choose Language Swift if want pure Swift framework project.

enter image description here

Also note If you look to import Swift framework into Objective-C project, or mix the languages, there is a good reading here Swift and Objective-C in the Same Project.

Hope this will give you a good direction.

Community
  • 1
  • 1
vladof81
  • 24,145
  • 9
  • 35
  • 40
  • That could be a good workaround, however in my particular case I'm writing a library to be consumed by a Xamarin app on iOS, and a static library is the only option. – karantza Jul 22 '14 at 13:31
  • One thing to keep in mind. As far as I can tell, there is no way to use CocoaPod packages with Swift Framework projects. Otherwise it works! – Shane N Jul 23 '14 at 21:44
  • The only problem with Touch Frameworks is that you can't deploy final product for iOS7. There is a waring that dylibs are not supported pre to iOS8. And when you run the app it crashes ...saying unable to load dylib. – Matej Ukmar Jan 15 '15 at 09:30
2

Look at this threat XCode5 simulator: unknown option character `X' in: -Xlinker

In order to understand the error, you have to understand what the command is attempting to do.

In this case it's using Libtool, which is a slightly altered version of libtool. There are some options that are specified in the command line, but what we're looking for is the destination file, and this is passed in as the -o option, who's argument is /Users/jr/ios/app/iCozi/build/DevOnly-iphonesimulator/libCozi\ Common\ Code.a, and the type of library we're generating, and in this case it's -static. Both options together explicitly state that you're making a static library archive.

Because you're making a static library archive, the only thing you're actually doing is taking .o files and possibly .a files and turning them into another .a file. This can be roughly equated to the creating of a .zip file from a set of files (.o), and the contents of other .zip files (.a). There are very few things you can do while making this archive, for example you can't specify libraries that need to be implicitly linked while building a static archive, you can't specify that you're going to require entitlements.

libtool is complaining because it doesn't understand the options that are being used for a static library that are being passed in. In this case the options are:

-Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker /Users/jr/ios/app/iCozi/build/iCozi.build/DevOnly-iphonesimulator/Cozi\ Common\ Code.build/Cozi\ Common\ Code.xcent

These are options that are present when you're trying to link in an entitlements file, which means that some options is specifying the use of an entitlements file. In this case, you found the correct solution yourself, which was to remove the entitlements file specified in the project settings -> Code Signing -> Code Signing Entitlements -> DevOnly.

Community
  • 1
  • 1
Alberto Barrera
  • 329
  • 1
  • 4
  • Not working for me under project settings -> Code Signing -> Code Signing Entitlements i have nothing, even put DevOnly doesn't change the error :( – jaumard Jun 05 '14 at 18:14
  • I read that too before asking; none of the options set that I know of would cause it to add those Xlinker args. My guess is that it's some option hardcoded into xcode for building Swift files that they haven't yet exposed to the build settings dialog. – karantza Jun 05 '14 at 21:23
  • I just report this bug to apple please do it too https://bugreport.apple.com/ – jaumard Jun 06 '14 at 05:38
  • jaumard: I've just done so. Let's hope this is fixed in the next build of Xcode! – karantza Jun 06 '14 at 19:48
  • My ticket was closed as a duplicate, but of course I can't see the duplicate ticket itself. (I can see that it's marked as Open, though.) If this changes, I'll update this ticket! – karantza Jun 08 '14 at 22:42
  • 1
    Beta 2 is out but same error for me... Did you fix this on your project ? – jaumard Jun 18 '14 at 06:56
  • 1
    In the Xcode Beta 2 release notes, under known errors, it says "It is not possible to build static libraries which contain Swift code in this release. (17181019)". So at least they're aware of it, I guess. – karantza Jun 18 '14 at 20:43
  • Thanks for the feedback :) yes at least they're aware but so annoying bug... ^^ – jaumard Jun 19 '14 at 20:31
  • As of xcode 8 .. is it possible to create static library out of swift code ? – Durai Amuthan.H Mar 11 '17 at 15:55
1

Check out this blog (translation needed)

http://andelf.github.io/blog/2014/06/25/write-swift-module-with-swift-cont/

Aggressor
  • 12,511
  • 18
  • 88
  • 165
0

I came across same problem and I did found a solution for it. 'libtool' is failing because of -Xlinker attribute, which tries to specify Swift module - that seems not to be supported for static libraries. (I also think that is mistake/deficiency by Apple, but maybe that's a discussion for another thread)

What I did is I copy/pasted the whole libtool command to terminal, remove all '-XLinker ...' parameters and surprisingly build succeeded from command line.

My static library project included both Objective-C and Swift sources and they were both 'packed' into produced static library!

The only downside was that Swift module was not produced but in my case that didn't matter because Swift was used only internally - I had only Objective C external interfaces.

I think it would be possible also to expose Swift 'interfaces' by copying produced static lib bridging header along the produced static lib.

Matej Ukmar
  • 1,820
  • 19
  • 20