Swift コンパイラーのビルド環境を Linux に作ってみる

Swift プログラミング

サクッと簡単にではあるのですけど、Ubuntu Linux 上に Swift コンパイラーをビルドする環境を構築してみた様子を綴っておきます。


だいぶ前に構築したきり、あまり触れることのなかった Open Source 版の Swift ビルド環境でしたけど、また少し触ってみようかなって思って、振り返りも兼ねて最初から構築し直してみることにしました。今回利用する環境は Ubuntu Linux 16.04.2 LTS です。

今回、試す上で参考にさせて頂いた資料は、Apple Swift Open Source の swift/README.md と、@rintaroさんSwift コンパイラ開発環境構築 、そして @eduraaaさんInside Of Swift です。とっても素敵な資料たち、どうもありがとうございます!

ビルド環境構築

まずは、公式の swift/README.md に沿って Swift のビルド環境を整えてみます。

環境構築に必要なパッケージをインストールする

今回は Linux 環境へのビルド環境構築なので、まずは次のようにして、それに必要なパッケージをインストールします。

sudo apt-get install git cmake ninja-build clang python uuid-dev libicu-dev icu-devtools libbsd-dev libedit-dev libxml2-dev libsqlite3-dev swig libpython-dev libncurses5-dev pkg-config libblocksruntime-dev libcurl4-openssl-dev autoconf libtool systemtap-sdt-dev tzdata

ソースコードの保存場所を作る

そして Swift ソースコードを入れるためのディレクトリーをどこかに作成します。今回は /home/tomohiro に作成しようと思うので、次のようにして、そのディレクトリーに移動して swift-source を作成します。

cd /home/tomohiro
mkdir swift-source

そうしたら、先ほど作成したディレクトリーに移動しておきます。

cd swift-source/

ここに Swift コンパイラーをビルドするために必要なソースコードを取得していきます。

ソースコードセットを取得する

Swift コンパイラーは幾つかのリポジトリーにあるソースコードを使って構成されているので、それらをすべて取得する必要があります。それを自動で行えるスクリプトが apple/swift リポジトリー内に utils/update-checkout スクリプトとして用意されているので、その Swift リポジトリーをクローンしてそのスクリプトを実行します。

git clone git@github.com:apple/swift.git
./swift/utils/update-checkout --clone-with-ssh
ネットワークの調子で大きく変わると思うのですけど、とりあえず apple/swift リポジトリーのクローンにかかった時間は、自分の試した環境では 11 分ほどでした。そんな環境で update-checkout は 35 分ほどで終わりました。

時点のソースコードの合計容量は 1.8GB ほどでした。

取得されたソースコードたち

このようにして取得してみると、 現在、swift-source ディレクトリーには次のサブディレクトリーが作成されていました。それぞれの用途などを分かる範囲で調べてみると、次のようになっている様子です。

名称 用途 リポジトリー
clang C 言語系のコンパイラーでフロントエンドを担当するもの apple/swift-clang.git
compiler-rt 主に Clang や LLVM で使われる コンパイラーランタイムライブラリ ? apple/swift-compiler-rt.git
lldb Swift 言語と REPL をサポートした LLDB(デバッガー) apple/swift-lldb.git
ninja 速度重視のコンパクトなビルドシステム(make コマンドみたいなものの様子) ninja-build/ninja.git
swift-corelibs-foundation Swift コアライブラリーのひとつに位置付けられている Foundation フレームワーク(macOS や iOS の Cocoa/Cocoa Touch フレームワークでお馴染み) apple/swift-corelibs-foundation.git
swift-corelibs-xctest Swift コアライブラリーのひとつに位置付けられている XCTest フレームワーク(Xcode でお馴染みの単体テスト) apple/swift-corelibs-xctest.git
swiftpm Swift 用のパッケージマネージャー(CocoaPods や Carthage みたいなもの) apple/swift-package-manager.git
cmark CommonMark という Markdown ライクな軽量マークアップ言語 apple/swift-cmark.git
llbuild Xcode 9 や Swift Package Manager で使われる、低レベルのビルドシステムのライブラリーセット apple/swift-llbuild.git
llvm 最適化機能やバイナリ生成機能などを備えたコンパイラー基盤(ミドルエンドとバックエンドを担当) apple/swift-llvm.git
swift Swift 言語コンパイラー apple/swift.git
swift-corelibs-libdispatch Swift コアライブラリーのひとつに位置付けられている Dispatch フレームワーク(並列処理機能、GCD) apple/swift-corelibs-libdispatch.git
swift-integration-tests 生成された Swift スナップショットが正しく生成されたかどうかを検証するための自動テスト? apple/swift-integration-tests.git
swift-xcode-playground-support Swift ツールチェインが Xcode と通信するためのログ収集や通信手段を提供(Xcode Playground で使用) apple/swift-xcode-playground-support.git

どのリポジトリーがどんなフォルダー名で取得されるかは utils/update-checkout-config.json に記載されています。ここでは "branch-scheme" によって、どのブランチからソースコードを取得するかも記載されていて、スキームは update-checkout 実行時にも切り替えられるようになっています。

Swift コンパイラーをビルドする

ライブラリーセットを取得したら、Swift リポジトリーにある utils/build-script を使って、次のようにすることでビルドできます。

./utils/build-script --release-debuginfo

こうすることで Swift コンパイラーがビルドできます。Ubuntu Linux 環境では、ビルドされたコンパイラーは swift-source/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64 ディレクトリーの bin ディレクトリー内に生成されました。

時点のソースコードを --release-debuginfo でビルドすると、合計 55GB ほどの生成物が ./build ディレクトリーに生成される様子でした。ちなみに --release でビルドした場合は 3.2GB ほどになりました。

部分的なビルド

いったん全てのビルドを終えると、以降はターゲットを指定してビルドすることも可能になるそうです。たとえば Swift コンパイラーだけをビルドしたい場合は ビルドしたファイルが生成されたディレクトリー内で 次のようにします。

ninja swift

たとえば Linux 環境で -release-debuginfo を添えてビルドした場合は、ビルドの出力ディレクトリーが swift-source/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64 になっているので、そのディレクトリーに移動してから上記のコマンドを実行するか、以下のようにディレクトリーを指定して ninja を実行します。

ninja -C /home/tomohiro/swift-source/build/Ninja-RelWithDebInfoAssert/swift-linux-x86_64 swift

どんなターゲットが存在しているかは、ビルドディレクトリーの中に生成されている build.ninja ファイル内の # Target aliases. の行以下に build ターゲット名: phony ... という形で記されている様子でした。

ビルドの所要時間

ビルドにかかる時間は環境性能に大きく依存するようで、全てのターゲットをビルドしたときの環境と時間をまとめると、次のような感じでした。ちなみにメモリーは 32GB あれば大丈夫そうな印象です。

OS CPU メモリー ビルド時間
Linux Core i7 6950X 3.0GHz × 20 128GB 約 17 分
Linux Core i7 6800K 3.4GHz × 12 128GB 約 21 分
macOS Core i7 3.6GHz × 8 (iMac Retina 4K 21.5-inch 2017 ) 32GB 約 60 分
macOS Core i5 2.7GHz × 8 (iMac 21.5-inch Late 2013 ) 16GB 約 97 分

コンパイラーオプション

公式の README では、ビルドオプションとして --release-debuginfo が添えられていました。これについては自分がまだよくわかっていないのですけど、Swift とその構成部品を RelWithDebInfo 指定でビルドすることで、最適化等が図られた上でデバッグ情報が添えられるビルドモード…なのでしょうか。

公式 README.md には、上記の --release-debuginfo に加えて、--debug-swift--debug-swift-stdlib などを添えることで、部品ごとに Debug ビルドを行う指定もできる様子です。

なお --debug で、全てをデバッグビルドできるようになっていますけど、ビルドに多くの時間が必要になるとのことでした。まだ分からないですけれど、ひとまずは --release-debuginfo 指定でビルドしておく感じで良いのかもしれません。

Xcode 用のプロジェクトは作れない

これは Linux 環境の場合 に限られるはずなのですけど、Xcode 用のプロジェクトを生成するためのオプション --xcode を指定しての utils/build-script は実行できない様子でした。実行してみると、次のエラーメッセージが表示されます。

CMake Error: Could not create named generator Xcode

ひとまずここまで

これでひとまず Linux 環境で Open Source 版の Swift を入手してビルドする方法の初歩的なところを試すことができました。

この辺りについては、以前に Swift 愛好会 vol19第72回 Cocoa勉強会関西 で簡単ながら発表した資料もあるので添付しておきます。

Getting Started With Ore-Ore Swift Standard Library ++ ほんのり続報 from Tomohiro Kumagai

まとめ

最後に Swift ビルド環境についてまとめておきます。