コレ何
https://iosdiscord.connpass.com/event/151576/ の資料です
はじめに
このドキュメントは、わいわいswiftc ワークショップ Vol.3 福岡の事前準備のドキュメントです。
Swiftコンパイラというマンモスプロジェクトをビルドするので、これをやらないと当日ワークショップに参加しても作業できないのでご注意ください。
コンパイラのビルドにかかなり時間を要するので、寝てる間にビルドを進めるのがおすすめです。
5/16: Publicにしました。が課題レポジトリは消えてるので注意。
1/14: 必要なものを更新しました。Python2系じゃないとcloneスクリプトとビルドスクリプトは動きません。
1/20: 手順を更新しました。cmakeのバージョン3.15.1をビルドしないといけないです
必要なもの
- Xcode 11.x (動作確認をしているので11.3が望ましい)
- ninja (最新版に上げていると良い, Homebrewなどでインストール可能です)
- cmake 3.15.1 (**3.16 以降だと動かないです。**cmakeを個別でビルドする方法を下記に掲載してあるので、そちらを参照してください)
- 55GB程度の空きStorage
- Python 2系
- ※ 現在入ってるPythonが3系の場合、pyenv等のPythonバージョン管理ツールでpython2を入れることをおすすめします。
準備手順
レポジトリをCloneする
Terminalを開いて、ホームディレクトリでも好きなところでwaiwai-workshop-3rdというディレクトリを作ってください。
※ waiwai-workshop-3rdじゃなくてもいいです。
$ cd ~ # 例ではホームディレクトリですが、どこでも良いです
$ mkdir waiwai-workshop-3rd
次に、Swiftコンパイラをgithubから 削除しました。waiwai-workshop-3rdにクローンします。(https://github.com/freddi-kit/waiwai-swiftc-silopt-workshop~)
今回は、ワークショップ向けにカスタマイズしたSwiftコンパイラを利用します。
必ずクローンしたものはswiftというディレクトリにリネームしてください。
$ cd waiwai-workshop-3rd
$ git clone git@github.com:freddi-kit/waiwai-swiftc-silopt-workshop.git swift
$ cd swift
以下、swiftディレクトリにいる想定で書きます。
依存してるプロジェクトをクローンする
次に、Swiftコンパイラに依存しているプロジェクトをクローンします。swiftディレクトリにスクリプトがあるので、以下のコマンドを叩いてください。
# swift ディレクトリにて
$ utils/update-checkout --clone
※ 設定では各プロジェクトのクローンするブランチを意図的に変えています。
※ 前のセクションでswiftにリネームする作業を怠っていると、ここらへんからつまづきます。
一応ブランチを確認して、waiwai-questionになっているかを確認してください。
# swift ディレクトリにて
$ git branch
* waiwai-question
cmake version 3.15.1をビルドする
cmakeが必要なのですが、cmakeのバージョンが 3.15.1でないとビルドスクリプトが正常に動かないです。
なので、cmakeを個別にビルドしてそれをビルドスクリプトに利用します。
先程の依存してるプロジェクトをクローンするにて、cmakeはclone済みなので、そちらに移動します。
# swift ディレクトリにて
$ cd ../cmake
そして下記のコマンドを叩いてください。
# cmake ディレクトリにて
$ ./bootstrap && make
暫く待つと、./bin/以下にcmakeがビルドされています。
途中でjava関係のポップアップが出る可能性がありますが、無視してOKを押してください。
※ わかる人向け: make install しないでください。
ビルドが終わったら、swiftディレクトリに戻りましょう。
# cmake ディレクトリにて
$ cd ../swift # もといたswiftディレクトリに戻る
コンパイラをビルドする
最後に、ビルドスクリプトを使ってビルドをします。
--cmake オプションで先程ビルドしたcmakeを指定します。
# swift ディレクトリにて
$ utils/build-script --debug --xcode --skip-build-benchmarks --cmake ../cmake/bin/cmake
ワークショップではこれで生成されたXcode Projectを使って、Swiftコンパイラのコードを書きかえていきます。
かなり時間がかかるので注意してください。おすすめは寝る前にやって朝起きたらもう準備できている状態。
※ Ctrl+C とかでビルドを中断すると、最悪ビルドしたコンパイラがちゃんと動かなくなる可能性があるので時間があってかつマシンパワーに余力があるときに行いましょう
もしコンパイラのビルド失敗したら?
もしビルド等に失敗したら、
- 最新のレポジトリの状態をcloneして最初からやり直してみる
- 使っている環境とは別のpython 2系の別環境をpyenvで導入してやってみてください。
- それでもだめであれば、エラーログを書いて質問してください
ただし、下記のdocs_htmlでの失敗は、ドキュメントの生成が失敗してるだけでXcode Projectが正常に生成されてある可能性が高いので無視して次のステップに行ってみてください。
=== BUILD AGGREGATE TARGET docs_html OF PROJECT Swift WITH CONFIGURATION Debug ===
Check dependencies
# ~~~~~~~~~中略~~~~~~~~~
** BUILD FAILED **
The following build commands failed:
PhaseScriptExecution CMake\ Rules /パス/waiwai-workshop-3rd/build/Xcode-DebugAssert/swift-macosx-x86_64/docs/Swift.build/Debug/docs_html.build/Script-225217FDFF4641299E9F0141.sh
(1 failure)
utils/build-script: fatal error: command terminated with a non-zero exit status 65, aborting
Xcode Projectを開く
では、Xcode Projectを開いていきます。Xcodeはswiftディレクトリから見て次の場所にあるのでopenコマンドなどを使って開きましょう。
# swift ディレクトリにて
$ open ../build/Xcode-DebugAssert/swift-macosx-x86_64/Swift.xcodeproj/
最初Xcode Projectを開くと、「targetが多すぎるのでschemeどうするか」という旨のポップアップが出ますが、targetは以降の作業で指定するので「Manual」っぽいことを書いてある選択肢を選んでください。
このポップアップはCloseで大丈夫です。
Xcode Projectにsil-optSchemeを追加する
では、そのSchemeを追加します。今回のワークショップではsil-optコマンドを使うので、それをビルドするSchemeを追加します。
プルダウンが出てくるので、New Schemeを選択します。

ここで、どのtargetでSchemeを作るかが出てきます。まず、targetを選択します。

このような大量のリストが出てくるので、sil-optを探して選択してください。キーボードでなにかしら文字を入力をすると絞り込み検索ができます。図では、sil-optで絞り込みをした結果です。
※ 絞り込みをしてもだいぶスクロールして探さないと見つからないので注意してください。
sil-optSchemeを編集して、コマンドラインからデバッグできるようにする
次に、コマンドラインからsil-optコマンドを叩いても、Xcodeで設定したBreak Pointなどが働くようにします。
さっきのスキームをクリックして、Edit Schemeを選択します。

設定ポップアップが出るので、左のRunという項目を選択して、InfoタブのLaunchという項目にある、Wait for executable to be launchedにチェックしてください。

Closeして、設定はおわりです。ここまでお疲れさまでした。🍵
設定がうまく行っているかテストする
では、実際にsil-optがうまく準備してあるかをテストしましょう。
では実際にSILOptimizerのコードを書き換えます。
Command + Shift + oでプロジェクト内検索を開き、WaiWaiOptimizerと入力します。すると、WaiWaiOptimizer.cppが見つかるので、それを開きます。

以下のようなコードが出てくると思います。
# include "swift/SILOptimizer/PassManager/Passes.h"
# include "swift/SIL/SILFunction.h"
# include "swift/SIL/SILInstruction.h"
# include "swift/SIL/SILModule.h"
# include "swift/SILOptimizer/Utils/Local.h"
# include "swift/SILOptimizer/PassManager/Transforms.h"
# include "llvm/Support/CommandLine.h"
# include <iostream>
using namespace swift;
using namespace std;
namespace {
class WaiWaiOptimizer : public swift::SILFunctionTransform {
/// The entry point to the transformation.
void run() override {
}
};
}
SILTransform *swift::createWaiWaiOptimizer() {
return new WaiWaiOptimizer();
}
これはC++のコードです。今回のワークショップはこのコードを使った課題があるので、実際に事前に触ってみましょう。
run()関数の中身を以下のように変更してみます。coutはSwiftでのprintにあたるものと思ってください。
endlというのが文末にありますが、これがないと改行されません。
...
void run() override {
cout << "Hello, Optimizer!" << endl;
}
...
変更後はこんなコードになりますね。
# include "swift/SILOptimizer/PassManager/Passes.h"
# include "swift/SIL/SILFunction.h"
# include "swift/SIL/SILInstruction.h"
# include "swift/SIL/SILModule.h"
# include "swift/SILOptimizer/Utils/Local.h"
# include "swift/SILOptimizer/PassManager/Transforms.h"
# include "llvm/Support/CommandLine.h"
# include <iostream>
using namespace swift;
using namespace std;
namespace {
class WaiWaiOptimizer : public swift::SILFunctionTransform {
/// The entry point to the transformation.
void run() override {
cout << "Hello, Optimizer!" << endl;
}
};
}
SILTransform *swift::createWaiWaiOptimizer() {
return new WaiWaiOptimizer();
}
このコードを必要な部分だけ少しだけ解説します。
Swiftを書いたことがあるならチョット読めると思いますが、WaiWaiOptimizerというクラスはSILFunctionTransformを継承しています。
class WaiWaiOptimizer : public swift::SILFunctionTransform {
これは、「WaiWaiOptimizerというOptimizerのPassがあって、これは関数を最適化(Optimize)するPassである」という意味になります。Passとはなにかについては詳しくはワークショップで話しますが、SILをOptimizeするモジュールと考えてください。
SwiftコンパイラはSILOptimizerというフェーズでコードを最適化しますが、Passと呼ばれるモジュールがそれぞれ目的の最適化を行います。
また、Passの最適化のアルゴリズムはrun関数に書いていきます。今回は、Hello, Optimizer!と画面に表示するだけで何も最適化しないPassを作りました。
では、試しにこのPassを読んだら本当にHello, Optimizer!と出るかを確かめてみます。
その前に、さっき追加したcoutのところにBreak Pointをつけたら動くかも確かめてみましょう。

ここまで来たら、Command + Rを押して、ビルドと実行をします。時間はそこまでかからないです。
Runをする準備ができたら、Wainting to attach to sil-opt : sil-optと出るので、コマンドライン上からsil-opt起動してみます。

その前に、sil-optで最適化するためのSILコードを用意します。適当にそこまで複雑じゃないコードのSILコードを以下のコマンドを叩いて用意してください。
$ swiftc example.swift -emit-silgen -o example.sil
先程のswiftディレクトリの目線に戻ります。
ビルドされたsil-optコマンドは、../build/Xcode-DebugAssert/swift-macosx-x86_64/Debug/bin/ にあるので、そこにあるsil-optコマンドを以下のように叩きます。
sil-optに-wai-wai-optimizerオプションを付けると、先程のWaiWaiOptimizerが呼ばれます。
# swift ディレクトリにて
$ ../build/Xcode-DebugAssert/swift-macosx-x86_64/Debug/bin/sil-opt -wai-wai-optimizer さっき生成したSILのあるディレクトリ/example.sil -o optimized-example.sil
下記のようにHello, Optimizer!がいくつか出力されて、かつBreak Pointが働いたら成功です。
# swift ディレクトリにて
$ ../build/Xcode-DebugAssert/swift-macosx-x86_64/Debug/bin/sil-opt -wai-wai-optimizer さっき生成したSILのあるディレクトリ/example.sil -o optimized-example.sil
Hello, Optimizer!
Hello, Optimizer!
Hello, Optimizer!
... # SILのコードによってHello, Optimizer!の数が違うので注意
成果物は、optimized-example.silとして出力されます。しかし、WaiWaiOptimizerのrun関数には最適化するものを何も書いてないので、元のexample.silと比較しても特に目立った変更ははありません。
おわり
ここまで来たら、準備は完了です。ワークショップ当日に問題をPushしますので、それをPullして解いていくことになります。
お疲れさまでした、当日は頑張ってください!皆様のご来場お待ちしております〜!
追記事項
ワークショップ本体のリンク載せておきます。
https://qiita.com/freddi_/items/43130e5f2a6e9d33b0ca
https://qiita.com/freddi_/items/9690f53e267855ffe4b7
https://qiita.com/freddi_/items/38df6bd64904b5ccaa73






