Swift がオープンソースになってしばらく経ちます。
コンパイラや標準ライブラリの開発に手を出してみたいけど、リポジトリを落とした後どうしていいかわからない!という方のために、まずは開発環境の構築方法をご紹介します。基本的にはREADME に書いてある内容ですが、あまり実践的ではないので、僕はこうしています的な。

必要な環境

メモリ容量: ちゃんと調べてないですが、リリースビルドで 2GB ほど消費するそうです。
ディスク容量: 10GB程度あれば大丈夫かと思います。
リポジトリも大きく、ビルドも含めると結構ディスク消費します。

macOS

Xcode: 9.0 beta最新版
OS: macOS 10.12 最新版以降

macOS で開発する場合は、 Xcode のコマンドラインツールは Xcode 9.0 の最新版の物にしておく必要があります。そうしないと、Apple の最新の SDK に対応した Swiftオーバーレイがビルド出来ないためです。Swiftコンパイラのビルドを行う際には xcode-select などで最新版の Xcode が選択されていることを確認してください。

Linux

Clang: 3.5 以降
CMake: 3.4.3 以降

CMake 3.4.3 以降が必要なので、公式パッケージで 3.5 がインストールできる Ubuntu 16.04 以降がオススメです。Ubuntu 以外のディストリビューションは試していないです。

READMEの通り依存パッケージをインストールしておいてください。

依存パッケージインストール
$ 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

リポジトリの clone

まずは README に書かれている通り apple/swift からリポジトリを clone していきます。適当なディレクトリ(~/Documentなど)に移動して、作業ディレクトリを作るところから始まります。

作業ディレクトリ作成
$ cd ~/Document
$ mkdir swift-source
$ cd swift-source

Swift.org のプロジェクトは、一つのリポジトリで完結しているわけではなくて、 apple/swift-llvm など複数のリポジトリに依存しています。最初に apple/swift を clone して、その中にあるスクリプトを使用してその他のリポジトリを clone します。

リポジトリのclone
$ git clone https://github.com/apple/swift.git
Cloning into 'swift'...

...ひたすら待つ

$ ./swift/utils/update-checkout --clone
Skipping clone of 'swift', directory already exists
Running ``obtain_additional_swift_sources`` with up to 8 processes.

...ひたすら待つ

ファイル数もコミット数も非常に多いリポジトリなので、時間帯によってはかなり時間がかかりますが、最初だけなので我慢。完了したらこんな感じのディレクトリ構成になっているはずです。

swift-source
 ├── clang
 ├── cmark
 ├── compiler-rt
 ├── llbuild
 ├── lldb
 ├── llvm
 ├── ninja
 ├── swift
 ├── swift-corelibs-foundation
 ├── swift-corelibs-libdispatch
 ├── swift-corelibs-xctest
 ├── swift-integration-test
 ├── swift-xcode-playground-support
 └── swiftpm

ちなみにファイル容量は、

$ du -s -h .
1.6G    .

CMake と Ninja

Swiftコンパイラの標準のビルドシステムは CMake および Ninja を利用します。CMakeがコンフィギュレーションをして、Ninjaが実際のビルドをします。

Linux の方は上でインストールしているのでOKとして、macOSの場合。CMake は公式からバイナリパッケージ落としてきてもいいのですが、僕は homebrew でインストールしています。

CMakeインストール(macOSのみ)
$ brew install cmake

あとNinjaですが、 README にはリポジトリ clone するとか homebrew でインストールするとか書いてありますが、実は utils/update-checkout コマンドが既に clone してくれていますので、必要ありません。既に homebrew などでインストールされている場合は自動的にそれが使用されますし、未インストールの場合には、clone されたリポジトリから自動的にビルドされ、それが使用されます。

とりあえずビルドしてみる

ビルド環境が整ったので、早速ビルドしてみましょう。utils/build-script というスクリプトでビルドします。

初回ビルド
$ cd swift
$ utils/build-script -Rt
... 30分程度から数時間

ここで使用しているオプションは -R が Release ビルド、これをつけないとデバッグ版のビルドになってしまい、コンパイルが非常に遅くなるので必ずつけます。 -t はテストも実行という意味で、省略して -Rt です。他にもいろいろあるのですが、僕は普段はほとんどこれだけで作業します(考えるのがめんどくさいので。)

ビルドはソースツリーの外で行われるようなっていて、成果物はすべて swift-source ディレクトリ内の build/Ninja-ReleaseAssert にあります。このディレクトリ名は build-script に与えたオプションによって変化します。明示的に指定することも出来ますが、とりあえず必要ないでしょう。

ちなみにこのビルドに必要なディスク容量は 3GB 程度です。

ビルドとテストが完了したら、早速ビルドされた Swift コンパイラを実行してみましょう。

ビルド済みswift実行
$ # swift ディレクトリ内で
$ ../build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift -version
Swift version 4.0-dev (LLVM 2b37177ffc, Clang cc5d6deb6e, Swift 2fe2328436)
Target: x86_64-apple-macosx10.9

$ echo 'print("Hello Swift!")' | ../build/Ninja-ReleaseAssert/swift-macosx-x86_64/bin/swift
Hello Swift!

とりあえず正常にビルド出来ていることが確認できました。
なお、この状態では、 swift-lldb や swiftpm など、その他 swift のビルドに依存するものがビルドされていないので、通常の REPL などは使えません。あくまでコンパイラ本体と macOS用の stdlib がビルドできたという状態です。また、iOS向けの stdlib などもコンパイルされていませんので、このビルドはXcodeのツールチェーンとしてインストールすることは出来ません。とはいえ、それら全てをビルド・テストするには非常に時間がかかるので、通常はこの状態でコンパイラの開発を行っていきます。

最新版へのアップデート

一度環境構築した後に、最新版を追っていく方法です。utils/update-checkout コマンドをオプション無しで使用します。

ソースアップデート
$ cd ~/Document/swift-source/swift
$ utils/update-checkout

utils/update-checkout には他にも Swift4 のリリースブランチ群をチェックアウトするなど、いろいろな機能があるのですが、僕は使ったことありません。興味ある方は --help オプションでヘルプを見てみてください。

ソースを最新にしたら、ビルドも更新します。

最新版ビルド
$ utils/build-script -Rt

もうすでに一度ビルドしているので、差分ビルドになります。これがデフォルトです。ただ、 swift-llvm などの swift が依存しているリポジトリに更新が入ると、ほぼ全てビルドし直しなのでそれなりに時間かかります。しょうがないですね。

また、クリーンビルドしたい時は、--clean オプションを同時に指定します。

クリーンビルド
$ utils/build-script -Rt --clean

とはいえ、--clean がやっていることはビルドディレクトリを削除してからビルドしているだけなので、 rm -rf ../build/Ninja-ReleaseAssert で事前に削除しておくだけで十分ではあります。ごくまれに、差分ビルドで対応できない変更が入ってビルド出来なくなることがあるので、何かおかしくなったらクリーンビルドしてみるのが良いかもしれません。

あと一応、 update-checkoutbuild-script も、どのディレクトリから実行しても問題無い作りになっています。つまり、カレントディレクトリに依存しませんので、 swift-source から swift/utils/update-checkout でも上記のように呼び出しても一緒です。

Xcode プロジェクトの作成

コーディングは全部 vim でやるぜ、みたいな人には不要ですが、 Xcode プロジェクトがあると何かと便利です。ただし Xcode の IDE でビルドするのは時間がかかることもあり、やったことありません。Xcodeでコーディングして、コマンドラインの build-script -Rt でビルド・テストするのがオススメ構成。

Xcodeプロジェクトは、 build-script を通して CMake に作成してもらう形になります。

Xcodeプロジェクト作成
$ utils/build-script -x --skip-build

オプションの -x は CMake を Xcode ジェネレータで実行するオプションです。 Xcode では実際にはビルドしないので --skip-build オプションをつけて実行します(とはいっても llvm の一部だけビルドされます)。完了したら ../build/Xcode-DebugAssert ディレクトリ内に Xcode プロジェクトが生成されているはずです。

Xcodeプロジェクトオープン
$ open ../build/Xcode-DebugAssert/swift-macosx-x86_64/Swift.xcodeproj

この xcodeproj には Scheme が設定されていないので、開くとこのようなダイアログが表示されます。

Screen Shot 2017-06-30 at 1.45.16.png

Xcodeはエディタとして使用したいだけなので何でもいいのですが、オート実行すると膨大な数の Scheme が生成されてめんどくさいので、 「Manually Manage Schemes」 を選び、左下の 「+」ボタンを押してターゲットをデフォルトのまま ALL_BUILD で 「OK」を押下し、スキームの作成を完了させます。

Screen Shot 2017-06-30 at 1.45.39.png

で、生成された xcodeproj ですが、このグループツリー構造がよくわかりません。ターゲット毎か何かになっていて、ファイルシステムの構成と違うので、ファイル探すのに苦労します。取り急ぎコンパイラのヘッダ (include/swift/) とソース (lib/) は xcodeproj では Sources/Swift libraries グループ下にあります。

Screen Shot 2017-06-30 at 2.00.23.png

インデックスに結構な時間がかかります。気長に待ちましょう。

ツールチェーンビルド

build-script -R だと、前述したとおり Xcode にインストールできるパッケージにはなりません。 Xcode にインストールするには、ツールチェーンというものをビルドしなければならないのですが、一番簡単な方法は、 utils/build-toolchain スクリプトを使用する事です。

注意: 非常に時間がかかるので覚悟してください。ディスク容量も 40GB くらい消費するので特別な理由が無い限りオススメしません。最新版追うだけなら Swift.org のダウンロードページからスナップショット落としてきた方が全然早いです。自前でビルドするのは、ローカルでの修正を Xcode での動きを含めてチェックをしたい場合に限られると思います。僕自身は必要性を感じたことはありません。

ツールチェーンビルド
$ cd ~/Document/swift-source/swift
$ utils/build-toolchain local.swift

数時間...

local.swift はパッケージの Bundle Identifier (のprefix)になります。単なる名前なので、他と被らなければ何でもいいです。

これが完了すると、 swift ディレクトリに下記のファイルが出来ているはずです。(ファイル名に日付が入っているのでその日によって当然違います。)

$ ls -l
...
-rw-r--r-- ... swift-LOCAL-2017-07-05-a-osx-symbols.tar.gz
-rw-r--r-- ... swift-LOCAL-2017-07-05-a-osx.tar.gz
drwxr-xr-x ... swift-nightly-install
drwxr-xr-x ... swift-nightly-symroot
...

これをインストールして、Xcodeから使ってみましょう。アーカイブの内容は / からの相対パスで作られているので、ルートから sudo でインストールします。

$ cd /
$ sudo tar zxvf ~/Document/swift-source/swift/swift-LOCAL-2017-07-05-a-osx.tar.gz

/Developer/Library/Developer/Toolchainsswift-LOCAL-{yyyy}-{MM}-{dd}-a.toolchain いうディレクトリが作成されているはずです。 Xcode の Preferences > Components > Toolchains から見えるようになっているはずなので、それを選択して試すことができます。

Screen Shot 2017-07-05 at 18.30.01.png

不要になったらこの画面で該当行をマウスオーバーすると出てくる :gear: アイコンをクリックして、メニューから、 "Move To Trash" を選択すればアンインストールできます。

注意: build-toolchainswift のワーキングディレクトリ に成果物を作ってしまうため、あまり行儀がよくありません。終わったら git status で状況見て、削除しておきましょう。

フォークの作成とリモート登録

今のうちに自分のフォークも作っちゃいましょう。
普段通り github でフォーク作り、それをローカルのリポジトリに remote として追加します。

remoteリポジトリ追加
$ cd ~/Document/swift-source/swift
$ git remote add private git@github.com:{フォーク名}/swift.git

remote 名は何でもいいですが、 private にしておきました。
僕は直接 push する可能性のあるリポジトリは ssh で、それ以外は https で clone するポリシーで運用しているので、こっちは ssh です。間違ってアップストリームに直接 push する心配が無くて良いです。

また、フォークしたものを clone する、つまり origin を 自分のフォークにするのもやったことないです。 utils/update-checkout がそれを想定しているかどうかもわからないので、 origin は apple/swift にしておいた方が安全と思います。

swiftリポジトリのディレクトリ構成

apple/swift のリポジトリがどういうディレクトリ構成になっているのかざっくりと。

ディレクトリ
docs/ ドキュメントです。Swift は公式の設計ドキュメントのようなものが少なくて、ドキュメントというよりはメモ書きレベルの物もいっぱい。別記事でまとめたい。
cmake/ CMake の設定ファイルである CMakeLists.txt から読み込まれる CMake 関連のモジュール群
include/swift/ コンパイラのヘッダファイル群
lib/ コンパイラのソース。実際にはこの中のディレクトリごとに .a としてコンパイルされ、 tools/ ディレクトリの各実行ファイルとリンクされます。
tools/driver/ swift コマンド本体
tools/SourceKit/ SourceKit のソース
tools/その他 その他テストツールなどの実行ファイルとしてコンパイルされるツール群
test/ テスト。テストについては別記事で解説します。
validation-test/ バリデーションテスト。普段は実行する必要ないけど、たまには実行したほうが良いテスト群。CIでは必ず実行されます。
unittest/ lib/ の各ライブラリの API レベルでのユニットテスト群。所詮パブリックなAPIではないので、あまり更新されません。
stdlib/public/runtime/ Swiftのランタイムライブラリ
stdlib/public/core/ 標準ライブラリ
stdlib/public/Platform/ Darwin もしくは Glibc ライブラリ
stdlib/public/SDK/ FoundationUIKit など Apple の各SDKのSwiftオーバーレイ
stdlib/private/ 標準ライブラリをテストするためのライブラリなど
utils/ ビルドスクリプトやその他諸々、Swiftの開発者が使用している雑多なユーティリティが納められています

いかがだったでしょうか?

Swift は新規コントリビュータ向けの文書や案内が充実しているとは言いがたいです。また、今現在既にコントリビュートしている人やアップルの中の人はそれなりに分かってしまっているので、何がひっかかるポイントなのかもわかってない、もしくは文書化する暇もない状態なのだと思います。

手を出してみたいけどココが分からない。というのがあったら是非コメントで教えてください!