简体   繁体   中英

The right way to link RxSwift into a Command Line Tool

I'm trying to build RxSwift for a Command Line Tool but it seams to be far more difficult then with an iOS App.

I created a new Command Line project and installed RxSwift with pod

$ cat Podfile
# Podfile
use_frameworks!

target 'HelloRx' do
    pod 'RxSwift',    '~> 4.0'
end

$ pod --version
1.5.3

XCode 10.1

After opening the workspace (.xcworkspace) and without adding any code the project builds fine but crash on run:

dyld: Library not loaded: @rpath/RxAtomic.framework/Versions/A/RxAtomic
  Referenced from: /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/HelloRx
  Reason: image not found

Dynamic dependencies are not visible to the binary.

$ otool -l HelloRx | grep -A 2 RPATH | grep path
         path @executable_path/../Frameworks (offset 12)
         path @loader_path/Frameworks (offset 12)
         path @executable_path/../Frameworks (offset 12)
         path @loader_path/Frameworks (offset 12)

XCode assumed that the binary can find frameworks in Frameworks directory relative to the binary. Unfortunatelly if I look into the build directory there is no Frameworks dir, hence the error.

$ ls
HelloRx         Pods_HelloRx.framework  RxCocoa
HelloRx.swiftmodule RxAtomic        RxSwift

$ ls ..
Debug

To make it more confusing all frameworks were copied into own Rx* dir rather then one global Frameworks dir.

I can fix that by adding more paths into "Build Settings" >> "Runpath Search Paths".

'@executable_path/RxAtomic'
'@executable_path/RxSwift'

I does the trick but binary still crashes.

dyld: Library not loaded: @rpath/libswiftAppKit.dylib
  Referenced from: /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/RxSwift/RxSwift.framework/Versions/A/RxSwift
  Reason: image not found

Now it's the RxSwift which is missing libswiftAppKit.dylib .

This can be "fixed" by adding another Runpath path.

'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx'

This finally stop crashes but my application throws lots of warnings:

objc[64025]: Class _TtCE6AppKitVSo17NSAnimationEffectP33_9E6F1C1DB126EBCC5B18B8BAC8A387CC26_CompletionHandlerDelegate is implemented in both /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/libswiftAppKit.dylib (0x101360b98) and /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/HelloRx (0x10059a250). One of the two will be used. Which one is undefined.
objc[64025]: Class _TtC8Dispatch16DispatchWorkItem is implemented in both /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/libswiftDispatch.dylib (0x101a7c6d0) and /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/HelloRx (0x10059bd28). One of the two will be used. Which one is undefined.
objc[64025]: Class _TtC10FoundationP33_45BFD3D387700B862E3A7353B97EF7ED20_CharacterSetStorage is implemented in both /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/libswiftFoundation.dylib (0x101c34f00) and /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/HelloRx (0x10059d5e8). One of the two will be used. Which one is undefined.
objc[64025]: Class _TtC10Foundation12_DataStorage is implemented in both /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx/libswiftFoundation.dylib (0x101c34fa8) and /Users/luke/Library/Developer/Xcode/DerivedData/HelloRx-ftbkqquhoytidfesyxazbaovndbu/Build/Products/Debug/HelloRx (0x10059d690). One of the two will be used. Which one is undefined.
...

I can live with warnings but it's clearly not the right solution. That makes me think, what's the right way to solve this problem?

(I'm new to XCode and Swift so perhaps I'm doing something crazy)

One quick way could be to have all the pods frameworks as static libs.

  1. Select Pods project on the Project Navigator
  2. Select the main Pods project above all the pods target
  3. Go to Build Settings and change Mach-O Type to Static Library . This will change all the pods to have Mach-O Type as Static Library . (Each time you run pod install this will be changed back so you might have to do it again)
  4. Clean

The advantage of this method is that your output will be a single executable.

If you want to use dynamic frameworks follow this tutorial: https://medium.com/livefront/how-to-add-a-dynamic-swift-framework-to-a-command-line-tool-bab6426d6c31 . By using this second method your output will not be just a single executable, but you will have to provide all the dynamic frameworks as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM