外部ライブラリをimportして実行可能な*.swiftファイルをつくる

  • 5
    Like
  • 0
    Comment
More than 1 year has passed since last update.

モチベーション

(コミット数とforkでは)CocoaPods派のbanjunです。
今回はCocoaPodsにあるような外部ライブラリを含むSwiftスクリプトをつくります。

かつてはまさにそのあたりを支援するApousというツールがあったのですが,Swiftの進化に追いついていないので一旦忘れます。
https://github.com/owensd/apous

使ってみたい外部ライブラリは SourceKitten です。 SwiftLintのようなツールを作れるそうです。

導入

*.swiftswiftコマンドで実行可能なので,shebangで*.swiftファイルの頭に付けてやれば起動はできます。

#!/usr/bin/swift

ただし,ここに import SourceKittenFramework を追加するには,フレームワークサーチパスの指定が必要になります。

そこで*.swiftファイルの隣りに Cartfile を書いて, carthage bootstrap します。CocoaPodsしか持っていない人は brew install carthage しましょう。

Cartfile

github "jpsim/SourceKitten"

すると Carthage/Build/Mac にframeworkがビルドされるので, swift -Fに渡すことでフレームワークサーチパスを指定できます。
それをshebangで指定しますが,*.swift自体はどこか別のディレクトリから,または ~/bin/* からシンボリックリンクでも起動できるようにします。
そのために一旦swiftではなくシェルスクリプトで受けたいので,*.swiftの頭を次のようにします。

#!/bin/sh
":" //#; exec swift -sdk $(xcrun --sdk macosx --show-sdk-path) -F "$(dirname $(readlink $0 || echo $0))/Carthage/Build/Mac" -target x86_64-apple-macosx10.10 "$0" "$@"
import Foundation
import SourceKittenFramework
(続く...)

:はshでnopなので,exec より前を無視します。ただちにexec swiftするのでシェルスクリプトの解釈はこの行でおしまいです。
引数には,起動されたパスから,Carthageでビルドしたframeworkのフルパスを解決して swift -F に渡しておきます。

さてexec swiftされると今度は同じファイルがSwiftスクリプトとして実行されます。一行目の":"はただの文字列であり, // はコメントなのでその行はなにもしません。続く行が実際のSwiftコードです。

ここでは import SourceKittenFramework したので,このSwiftスクリプト内ではSourceKittenを使ってコードを書けます。スクリプトに引数がほしい場合はexec swiftで"$@"したところから取得可能なので,それを使います。

SourceKittenを使うSwiftスクリプトの例です。

https://github.com/banjun/bansan/blob/601232feac6d61b73aaa82f646e64d9363639709/bansan.swift

これは ./bansan.swift としても実行できますし,PATHを通した~/bin/bansanからシンボリックリンクを貼っておいて,どこからでもbansanで実行できます。

課題とworkaround

Carthageのバイナリインストール

Carthageにはバイナリインストールモードがあり,frameworkをビルドせずに,ビルド済みframeworkを置いてくれる仕組みがあるようです。
ただしSwiftが生成するバイナリはSwiftバージョンに対して互換性が悪いので(Swiftで静的ライブラリが作れなかったり,libDarwinとかをいつも付属させてたり,‥とかが関係する?),Xcodeのバージョンが変わるときにはハマります。

そんなときは carthage bootstrapcarthage checkout--no-use-binaries を付けて,ソースからビルドしましょう。

swift -targetのデフォルト値

-target の引数はXcodeのバージョンで変わるかもしれません。これはXcode 7.3のものです。動かないときはswift -vで実行してみて,swiftコマンドが生成するオプションを見てみるといいかもしれません。
例えば x86_64-apple-macosx10.9 だと 10.10をminimum deployment targetにしているframeworkはimportできません。

まとめ

  • 外部ライブラリを含む実行可能*.swiftを作りたいときはCarthageとexec swiftを使うことができる
  • Carthageはその場にframeworkを作ってくれるのでべんり
  • Carthageのバイナリインストールモードは,Swift自体がバイナリ互換性がないことを考えると筋が悪い