Help us understand the problem. What is going on with this article?

SwiftUI 導入で LLVM のドキュメント読む羽目になった話

はじめに

この記事は CyberAgent Developers Advent Calendar 2019 9日目の記事になります。
今回は、コンパイラ周りの話も入ってくるので、日頃そこら辺に触れない方でも読んでいただけるようにスライドを多用した記事にしてみました。最後まで読んでいただけると嬉しいです!

SwiftUI 導入してます!

xcode-previews-and-llvm.005.png
弊社が運用する恋活サービス「タップル誕生」iOS 版では SwiftUI を一部で導入しています。
ただ、導入は簡単ではありませんでした。タイトルの通り、 LLVM のドキュメントを読む羽目になった経緯と問題の解決方法を紹介したいと思います。手っ取り早く 解決方法のみを知りたい! という方は、ページの一番下までスクロールしてみてください!

SwiftUI 導入方法

xcode-previews-and-llvm.007.png
SwiftUI と UIKit には互換性があるため、共存させることが可能です。なので、 UIKit で設計されたものを SwiftUI のようにプレビューさせることも可能になります。ここらへんに関しては、以前記事を書いてますので参考にしてみてください。

iOS12 以下をサポートするプロダクトで SwiftUI の恩恵を得る方法
参考:AkkeyLab/AutoPreviewable
参考:AkkeyLab/XcodePreviewsTemplate

地獄の始まり

xcode-previews-and-llvm.010.png
サンプルプロジェクトを作って SwiftUI を試していた私は完全に油断していました。実際のプロダクトで Xcode Preview が動かないんです(※)。しかも、1行の長々とした不親切なエラーを出力するだけ(内容的には、「〜が読み込めませんでした」という感じでした)。

※ SwiftUI を用いた設計・実行等は可能です

xcode-previews-and-llvm.019.png
先程のエラーの一部で検索を試みますが、 Flutter や Xamarin の記事ばかりで肝心の SwiftUI に関連するのもにはたどり着けませんでした。
この情報不足感は Swift 発表当初を思い出しますね。だからといって、諦めるわけにはいかないのですが、日頃の業務の空き時間等にちょこちょこ SwiftUI への対応を進めていたので、一旦ここで調査を中断しました。

xcode-previews-and-llvm.023.png
そして、休日に個人で開発を行っている動画視聴アプリ「AkkeyTV」の SwiftUI 対応を試みました。なんとなくわかっていましたが、同じく Xcode Preview に失敗しました。(スクショは、リポジトリの issue に貼り付けたエラーコード)
ただ、このエラーコードが問題解決に大きく貢献することになります。

xcode-previews-and-llvm.028.png
先程のエラーをもとに調査を進めたところ、 SwiftUI で同様の問題に直面している記事にたどり着きました。そこに書かれていたことをざっくりとまとめると「カバレッジを有効にした状態でプレビューできない」というものでした。
実際にカバレッジを無効にしてみると tapple でも AkkeyTV でも Xcode Preview が正常に動作するようになりました!しかし、テストを書きながら開発を進めているため、この解決方法はボツにしました。

引用元:Undefined symbols ___llvm_profile_runtime

xcode-previews-and-llvm.032.png
更に調査を進めたところ、 SwiftUI 以外でも同様のエラーが出ることがあり、それは static framework に関係しているということがわかりました。そして、 Linker flags に -fprofile-instr-generate を追加するとうまく動作するという解決策にたどり着いたのです!
実際にフラグを追加してみると tapple でも AkkeyTV でも Xcode Preview が正常に動作するようになりました!

引用元:ReactiveCocoa/ReactiveSwift > issue > Optimization Level configuration #552

状況整理

xcode-previews-and-llvm.044.png
ここで一旦、状況を整理します。
問題の解決はできたものの、「 -fprofile-instr-generate というフラグが一体何者なのか」という新たな疑問が生まれてきました。このフラグが原因でアプリが正常に動作しなくなったり、開発効率が低下するようなことがあってはいけないため、このフラグに対する調査も引き続き行っていきます。

問題解決の裏側

xcode-previews-and-llvm.047.png
まず、「このフラグが何者なのか」この疑問に対する答えがこれです。 clang を使ってソースコードのカバレッジも出力したいときに付加させるフラグだということがわかります。

xcode-previews-and-llvm.051.png
さて、先程の説明文に出てきた見慣れない用語についても触れておきましょう。
これで、 -fprofile-instr-generate というフラグに関してはある程度わかったと思います。

xcode-previews-and-llvm.055.png
ここで、少し前のスライドにフラグに関することも追加してみます。この解釈だと、矛盾が生じているように見えます。
そこで、もう少し視野を広げて、 Xcode のビルド方法について見ていくことにします。

xcode-previews-and-llvm.058.png
iOS は Objective-C と Swift を1つのプロジェクトで利用できることからもわかるように C 系のコンパイラである clang と Swift コンパイラである swiftc によってビルドが行われています。
ここで、 Linker については こちら を参考にしてください。

内部的に Xcode は各コンパイラに対して引数を渡してコマンドを叩いているだけなので、そのコマンド引数に渡されるオプションについて調べてみることにします。

xcode-previews-and-llvm.060.png
プロジェクトの設定ファイルなどに記載された各種設定項目から、コマンド引数に渡すオプションに変換するルールブックのようなものが Xcode の奥深くに置かれています。
これは clang の場合になりますが、 xcspec という拡張子のファイルに記述されており、カバレッジが有効であるときに2つのフラグをコマンド引数に設定するように記述されていることが確認できます。つまり、カバレッジを有効にした時点で -fprofile-instr-generate というフラグはコマンド引数に渡されていたということです。

では、 Linker flags に -fprofile-instr-generate を追加することと、カバレッジを有効にすることにはどのような違いがあるのでしょうか。→【Xcode Build System】

xcode-previews-and-llvm.064.png
swiftc に対する xcspec も同様の処理が記述されています。

xcode-previews-and-llvm.065.png
同様のファイルは Linker に対しても存在していますが、カバレッジに関する処理はありませんでした。

xcode-previews-and-llvm.068.png
ここで、もう少し深く見てみようと思います。
我々が記述するソースコードが機械語に変換されてアプリとして起動するまでを図にまとめてみました。

xcode-previews-and-llvm.071.png
各種コンパイラと Linker の存在を図に挿入し、渡されるフラグに関しても追記してみました。
ここでわかってくるのは、カバレッジを有効にすることでフラグが渡される対象と、 Linker flags のフラグが渡される対象が異なっているということです。

考察

xcode-previews-and-llvm.075.png
今後、引き続き調査と勉強を継続していきます。
そのため、この記事には解釈の間違い等が含まれている可能性があります。間違いにお気づきの際は、コメント等いただけると嬉しいです。

さいごに

タイトルに「読む羽目になった」と書きましたが、実際に原因を探り、コンパイラ等の技術について学ぶ時間はとても有意義な時間でした。(記事を読んで伝わったのではないかとは思いますが)嫌々ドキュメントを読んでいたわけではないのでご安心ください!

最後までご覧いただき、ありがとうございました!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away