コレ何
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-opt
Schemeを追加する
では、そのSchemeを追加します。今回のワークショップではsil-opt
コマンドを使うので、それをビルドするSchemeを追加します。
プルダウンが出てくるので、New Scheme
を選択します。
ここで、どのtargetでSchemeを作るかが出てきます。まず、target
を選択します。
このような大量のリストが出てくるので、sil-opt
を探して選択してください。キーボードでなにかしら文字を入力をすると絞り込み検索ができます。図では、sil-opt
で絞り込みをした結果です。
※ 絞り込みをしてもだいぶスクロールして探さないと見つからないので注意してください。
sil-opt
Schemeを編集して、コマンドラインからデバッグできるようにする
次に、コマンドラインから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