swiftenv で現在進行中の Swift 3.0-dev を扱う。

Swift プログラミング

swiftenv を使うと簡単に Swift ツールチェインを切り替えられるようになります。

それを使って Swift 3.0 候補の最新ビルドも切り替えられるようにしてみました。

ちょっと無理やり感はありますけれど。


先日に kylef/swiftenv を使って、Swift ツールチェインのバージョンを簡単に切り替えられるようにしてみました。それについては こちら で紹介しましたけれど、それを使って Swift 3.0 Developer Preview 1 も切り替えられるようにしたくなりました。

3.0-dev はビルドエラーに

そこで、結果的に失敗したので確かなことはわからないのですけど、次のようにすることで apple/swiftmaster ブランチを使ってツールチェインを作れるかもしれないことがわかりました。

swiftenv install 3.0-dev

ただ、実際にこれを実行すると の時点では、次のように Swift のビルドに失敗したことを知らせるメッセージが表示され、続行することができませんでした。

$ swiftenv install 3.0-dev

Found swift, skipping download

Found llvm, skipping download

Found clang, skipping download

Found lldb, skipping download

Found cmark, skipping download

Building Swift

This may take a very long time...

Building Swift failed

Check out the logfile for more information: /Users/tomohiro/.swiftenv/tmp/swiftenv-build-3.0-dev/swiftenv-build.20160519181517.16460.log

You can inspect or delete the working tree at: /Users/tomohiro/.swiftenv/tmp/swiftenv-build-3.0-dev

失敗の様子

エラーメッセージに記載されていたログファイルを見ると、どうやらそもそも メソッドが存在しない みたいな根本的なエラーであることが窺えます。

/Users/tomohiro/.swiftenv/tmp/swiftenv-build-3.0-dev/swift/lib/IRGen/GenClangDecl.cpp:81:24: error: no member named 'GetAddrOfGlobal' in 'clang::CodeGenerator'

return ClangCodeGen->GetAddrOfGlobal(global, (bool) forDefinition);

~~~~~~~~~~~~ ^

1 error generated.

ninja: build stopped: subcommand failed.

./utils/build-script: command terminated with a non-zero exit status 1, aborting

現時点でも、自分で直接 Swift ソースコードをダウンロードしてビルドする限りは正常にビルドできるようで不思議だったのですけど、目的のリポジトリがクローンされた作業ディレクトリを眺めてみると、どうやら clangllvm のブランチが、手動でビルドするときは stable なのが、swiftenv を使ってビルドした時には swift-3.0-branch なっていて、それが原因の様子でした。

この clangllvm は、Swift 3.0 のリリースプロセスの中で、ちょうどそれら以外のリポジトリとはブランチの切り方が違い、現時点ではそれ以外のリポジトリでは swift-3.0-branch が切られていないはずなので、その辺りの足並みの差が影響しているのかもしれません。

正常化の試みは失敗

とりあえずその作業ディレクトリ内にある clangllvm のブランチが stable になるように調整してみましたけれど、再び swiftenv install 3.0-dev を実行すると、ブランチが強制的に swift-3.0-branch になってしまうため、この方法ではうまく行きませんでした。

手作業でツールチェインを追加することに

せっかくブランチさえ stable にできればビルドは成功してくれるので、それなら swiftenv に手作業で Swift ツールチェインを追加してみたらどうかと思ってやってみたら、とりあえず、切り替えできるようになりました。

試行錯誤でやってみたので、正しく登録できているかは少し自信がないですけれど、とりあえずどんなことをやってみたのか、備忘録も兼ねて記しておくことにします。

Swift をビルドする

まずは swiftenv で使うための Swift を手作業でビルドします。今回は Swift のビルド環境が既に準備されているものとして、次のようにして最新ソースを取得してビルドします。

cd swift/
./utils/update-checkout --clone
./utils/build-script -R -c

そうすると ../build/Xcode-ReleaseAssert に Swift のビルドが出来上がります。

ちなみに上で指定した -Rデバッグ情報を伴わないリリースビルド を、-cクリーンにした上でビルドする という意味になるようです。今回みたいにソースコードを更新した場合、クリーンビルドをしないと思いがけないところでビルドエラーになったりするので注意です。

ビルドをツールチェインとしてまとめる

Swift をビルドできたら、それをツールチェインとして登録します。

見た感じ、ツールチェインは /Library/Developer/Toolchains ディレクトリーに *.xctoolchain というフォルダーでまとめられる様子です。中身を見ると Info.plist とかいろいろあるみたいですけど、とりあえず swiftenv/swiftenv-build あたりを眺める限りでは、フォルダーを作ってバイナリをコピーすれば良さそうな様子もうかがえて、このコードだけでは足りなそうな気はするものの、とりあえずそんな調子で実施してみることにしました。

sudo mkdir -p /Library/Developer/Toolchains/swift-master.xctoolchain/usr/bin

sudo cp -r "../build/Ninja-ReleaseAssert/"swift-*/bin "/Library/Developer/Toolchains/swift-master.xctoolchain/usr"
sudo cp -r "../build/Ninja-ReleaseAssert/"swift-*/lib "/Library/Developer/Toolchains/swift-master.xctoolchain/usr"

こんな風にすることで swift-master という名前の Swift ツールチェインをシステムに組み込むことが(たぶん)できました。

swiftenv で切り替える

ここまでできると、swiftenvswift-master というバージョンを選択できるようになるので、いつもと同じコマンドで切り替えてあげれば完成です。

swiftenv local swift-master

そうして試しに Swift のバージョンを確認してみると、今の時点で最新の Swift に切り替えられた様子です。

$ swift --version

Swift version 3.0-dev (LLVM a12db8b2fe, Clang 9df84c4959, Swift f045e5960d)

Target: x86_64-apple-macosx10.9

とりあえず、シンプルなコードを試す限りでは、コンパイラとしてちゃんと動いてくれる様子でした。

Swift 3.0 のリリースプロセスでは master ブランチで最新の Swift 3.0 コミットが入れられていくらしいので、もちろんコミットされるたびに、それを使って再ビルドの上、ツールチェインフォルダーにコピーする作業が必要になりますけれど、これで比較的気軽に最新の Swift 3.0 リリース候補を試していけるのではないかなって期待してます。