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 します。
$ 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 でインストールしています。
$ 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 ディレクトリ内で
$ ../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-checkout
も build-script
も、どのディレクトリから実行しても問題無い作りになっています。つまり、カレントディレクトリに依存しませんので、 swift-source
から swift/utils/update-checkout
でも上記のように呼び出しても一緒です。
Xcode プロジェクトの作成
コーディングは全部 vim でやるぜ、みたいな人には不要ですが、 Xcode プロジェクトがあると何かと便利です。ただし Xcode の IDE でビルドするのは時間がかかることもあり、やったことありません。Xcodeでコーディングして、コマンドラインの build-script -Rt
でビルド・テストするのがオススメ構成。
Xcodeプロジェクトは、 build-script
を通して CMake に作成してもらう形になります。
$ utils/build-script -x --skip-build
オプションの -x
は CMake を Xcode ジェネレータで実行するオプションです。 Xcode では実際にはビルドしないので --skip-build
オプションをつけて実行します(とはいっても llvm の一部だけビルドされます)。完了したら ../build/Xcode-DebugAssert
ディレクトリ内に Xcode プロジェクトが生成されているはずです。
$ open ../build/Xcode-DebugAssert/swift-macosx-x86_64/Swift.xcodeproj
この xcodeproj には Scheme が設定されていないので、開くとこのようなダイアログが表示されます。
Xcodeはエディタとして使用したいだけなので何でもいいのですが、オート実行すると膨大な数の Scheme が生成されてめんどくさいので、 「Manually Manage Schemes」 を選び、左下の 「+」ボタンを押してターゲットをデフォルトのまま ALL_BUILD で 「OK」を押下し、スキームの作成を完了させます。
で、生成された xcodeproj ですが、このグループツリー構造がよくわかりません。ターゲット毎か何かになっていて、ファイルシステムの構成と違うので、ファイル探すのに苦労します。取り急ぎコンパイラのヘッダ (include/swift/
) とソース (lib/
) は xcodeproj では Sources/Swift libraries
グループ下にあります。
インデックスに結構な時間がかかります。気長に待ちましょう。
ツールチェーンビルド
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
/Library/Developer/Toolchains
に swift-LOCAL-{yyyy}-{MM}-{dd}-a.toolchain
いうディレクトリが作成されているはずです。 Xcode の Preferences > Components > Toolchains から見えるようになっているはずなので、それを選択して試すことができます。
不要になったらこの画面で該当行をマウスオーバーすると出てくる アイコンをクリックして、メニューから、 "Move To Trash" を選択すればアンインストールできます。
注意: build-toolchain
は swift
のワーキングディレクトリ に成果物を作ってしまうため、あまり行儀がよくありません。終わったら git status
で状況見て、削除しておきましょう。
フォークの作成とリモート登録
今のうちに自分のフォークも作っちゃいましょう。
普段通り github でフォーク作り、それをローカルのリポジトリに 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/ |
Foundation や UIKit など Apple の各SDKのSwiftオーバーレイ |
stdlib/private/ |
標準ライブラリをテストするためのライブラリなど |
utils/ |
ビルドスクリプトやその他諸々、Swiftの開発者が使用している雑多なユーティリティが納められています |
いかがだったでしょうか?
Swift は新規コントリビュータ向けの文書や案内が充実しているとは言いがたいです。また、今現在既にコントリビュートしている人やアップルの中の人はそれなりに分かってしまっているので、何がひっかかるポイントなのかもわかってない、もしくは文書化する暇もない状態なのだと思います。
手を出してみたいけどココが分からない。というのがあったら是非コメントで教えてください!