XcodeでのSwiftプロジェクトのアセンブリをオーバークロックします

画像

SwiftプロジェクトのXcodeのインクリメンタルコンパイルを修正し、CocoapodsとCarthageのビルドフェーズを何も壊さずに高速化する方法に関する記事。







小さなスポイラー:3つの異なるプロジェクトで、インクリメンタルアセンブリの時間が9倍に短縮されました!







このチュートリアルは、最小限の水で完全に実用的です。 現在のiOS開発者には必読です。









問題



当社のSwiftにはいくつかの並行プロジェクトがあり、実際、どこでもシリアルアセンブリに問題がありました。 「実行」を繰り返すたびに30〜50秒かかりました。 コードは1分間書かれ、プロジェクトが組み立てられるまで30分間待ちます。 あなたはなんとかお茶、煙、税金を計算し、時々仮眠を取ります。







間違いなく何かを変えなければなりませんでした。 コンパイラーの実際の問題とその解決方法を説明した以前の記事では、特定の成功を収めることができました。 ただし、これはインクリメンタルコンパイルの難しさを解消しませんでした。インクリメンタルコンパイルは、ほとんどの時間を消費し、常に低速でワークフローをノックアウトしました。 誰もが定期的にこれに直面し、作業プロセスの一部としてそれを取っていると確信しています。







しかし、私たちはこれに我慢せず、ケースのすべての状況を調査することを決定し、その結果、良い結果を得ました。 私が話したいと思うこと。







PSヘッダーの図は、Xcodeを「渦巻かせた」という意味ではありません。 これはおそらく非常に高速です。







インクリメンタルコンパイル



誰かがこの用語に慣れていない場合、これは、プロジェクト全体を完全に再コンパイルせずに、変更されたコードプレースのみをビルドする方法です。 そして、それがXcodeではうまく機能しません。







以前の投稿で、同志Gxostは問題をしばらく解決するアイデア提案しました 。 チーム全員でシャンパンを開き、ポートレートを掛け始めました 天皇 壁の配達人、しかし、残念なことに、この時点で問題が再開しました。







どうやら、私たちだけではありません。 再発は、回答の下のStackOverflow 、およびAppleフォーラムの元のトピックにも記載されています。







これは決して庭の棒ではありません。 それどころか-感謝、これすべては私が掘り続けることを促した。 一時的ではあるが、問題が解決した場合、真実はどこかにあります。







Appleの推奨にフラグを設定したこのヘッダーマップとは何ですか?

アップルのドキュメントに関するウェブ考古学のビット:







ヘッダーマップ(「ヘッダーマップ」とも呼ばれる)は、ターゲットで使用されるヘッダーの場所をコンパイルするためにXcodeが使用するファイルです。

ヘッダーマップとは、プロジェクトヘッダーの場所を含むXcodeインデックスファイルです。 使用するすべてのヘッダーに関するファイル。







理論に深く入り込まないことを約束したので、このテーマに関する優れた記事を以下に示します。 読みやすい、強くお勧めします。







主なことは 、これらのヘッダーマップ内の何か (またはそれらを使用するもの)がインクリメンタルコンパイルの不公平な作業を引き起こすことです。 このような技術的な腫瘍が見つかった場合は、半分の対策を講じずにそれを行い、それらをオフにします。







ビルド設定に移動し、 不要な詳細を削除する 既存のフラグUSE_HEADER_MAPSNOに設定します。







画像







次に、失われた機能を補正し、すべてのプロジェクトヘッダーの場所を手動で追加する必要があります。







設定をどこにも残さず、「ユーザーヘッダー検索パス」フィールドにヘッダーがあるフォルダーへのパスを手作業で指定します。







画像







Swiftプロジェクトにはそれらの数はなく、カスタムObj-Cのものだけが必要です。







繰り返しますが、完全なクリーンアップを行い、プロジェクトを開始しようとします。 次のエラーが発生した場合







画像







つまり、1つ以上のヘッダーファイルへのパスを言及するのを忘れただけです。 修正後、すべてを複雑にすることなく組み立てる必要があります。これを除いて、変更を加えていないためです。







おまけとして、 前回説明した全モジュール最適化(WMO)がオフになったときにインクリメンタルコンパイルが最適に機能することに注意してください。 これは、モジュール全体の最適化のためにソリューションが機能しないことを意味するものではなく、ソリューションがなければ、すべてが数秒速くなります。 ゼロから構築し、長続きするようにします。

ここで、誰もが自分にとってより便利で、より速く、より良いものを自分で決めます。 WMOを放棄することにした場合は、プロジェクト設定からSWIFT_WHOLE_MODULE_OPTIMIZATIONフラグを削除するだけで、間違いなく問題はありません。







結果 :インクリメンタルコンパイルが正常に修復されました。 これからは、コードサイン、リンク、およびさまざまなビルドスクリプトをカウントせずに、Swiftアセンブリ自体の事実に数秒しか費やすべきではありません(以下で説明します)。 社内では、この方法を3つの異なるプロジェクト、OSXのいくつかのバージョン、および一般的に多くの構成でテストしました。これはXcodeにも適用されます。 そして長い間、再発は観察されていません。







ココアポッドとカルタゴのオーバークロック



おそらく多くの人々は、コンパイル自体に加えて、さまざまな「シェルスクリプト」のために多くの時間がかかることに気付きました:







画像







ココアポッドおよび/またはカルタゴを使用する場合、いくつかもあります。 ディスク、プロセッサ、空の星の位置に応じて、毎回3〜10秒かかります。 Cocoapodsはそこで自動的に登録しますが、Carthageの場合は手動で登録する必要があります。

コンテンツを少し調べたところ、これらのスクリプトは、プロジェクトのアセンブリディレクトリにリソースをコピーする以外の何物にも関与していないことがわかりました。 ただし、これらのファイルがすでにコピーされているかどうかは気にしません。 ただし、必要なリソースを再度コピーする前に、必要なリソースの可用性を確認する方がはるかに論理的です。







私たちはそれをします。







カルタゴから始めましょう。



この決定のインスピレーションは、 StackOverflowに対する過小評価された応答でした。 ちなみに、承認されたソリューションを突然使用することに決めた場合、完全にクリーンアップすると、ランタイムでワイルドでホットなミスをキャッチします。







これは行いませんので、正しい道を進み、Copy Carthage Frameworksのビルドフェーズを変更します。







FILE="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Carthage-Installation-Flag" if [ -f "$FILE" ]; then exit 0 fi touch "$FILE" /usr/local/bin/carthage copy-frameworks
      
      





このスクリプトはさらに、リソースとともに別の空のファイルをコピーします。これは、操作が成功したことを示すビーコンとして機能します。 スペースをとらず、副作用もありません そして3歳からの子供に許可 。 次回スクリプトを起動すると、最初にこのファイルの可用性が確認され、ファイルがある場合、操作は不要なジェスチャーなしで自動的に終了します。







確かに、取得する結果のスクリーンショット:







画像







重要! Carthageに依存関係を追加または削除する場合、プロジェクトをビルドする前に、完全なクリーンアップを実行する必要があります。 それ以外の場合、スクリプトは既にインストールされていると想定します。 そして、あなたは何が起こっているかの説明を見つけようとしてあなたの顔に汗をかくでしょう。







ところで、メニューの製品→クリーンのクリーン機能を見つけることができます。







画像







まだオプション(alt)を保持している場合、 特別なクリーンを作成できます。 プロジェクトから悪魔を追い出す 頻繁にクラッシュするさまざまなローカル設定、キャッシュ、その他のがらくたを削除します。







今ココアポッド


Beanの場合、原則は同じですが、スクリプトは自動的に生成されるため、Podfileに魔法を追加する必要があります。 これを行うには、ファイルの最後に次の行をドロップします。







 post_install do |installer| Dir.glob(installer.sandbox.target_support_files_root + "Pods-*/*.sh").each do |script| flag_name = File.basename(script, ".sh") + "-Installation-Flag" folder = "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" file = File.join(folder, flag_name) content = File.read(script) content.gsub!(/set -e/, "set -e\nKG_FILE=\"#{file}\"\nif [ -f \"$KG_FILE\" ]; then exit 0; fi\nmkdir -p \"#{folder}\"\ntouch \"$KG_FILE\"") File.write(script, content) end end
      
      





このスクリプトの動作原理は同じです。リソースをコピーするためのスクリプトのファイルフラグにチェックを追加します。 同時に、Carthageとは異なり、ビルドフェーズは変更されませんが、cocoapodsスクリプト自体はすぐに変更されます。







ところで、既にpost_installブロックが含まれている場合は、別のブロックを作成する必要はなく、既存のブロック内にスクリプトを配置するだけです。 Cocoapods(1.1.1)の最新バージョンでは、エラーが発生すると警告が表示されますが、以前のバージョンではエラーを静かに飲み込むだけで、楽しいデバッグが可能です。







これで、「 ポッドインストール 」を実行して、変更を有効にすることができます。 Carthageと同様に、Podfileを編集するときは、開始する前に完全にクリーンなプロジェクトも必要です。







画像

PS Rubyは私の母国語ではありません。スリッパを握ってください。







おわりに



したがって、プロジェクトのビルド時間を45秒から5秒に短縮することができました。







証拠をほとんど忘れていました。 ビルド時間:







画像







スクリーンショットは、前回の記事のビデオから取られたものです。







ビルド後の時間:







画像







私の意見では、非常に重要な結果です。 コスト削減のアプローチは、すべての会社と開発者の兵器庫になければなりません。







Xcodeの最適化の経験があり、自分の考えを補完し共有できる人がいることは間違いないでしょう。 とにかく、コメントで質問を見たいので、次の記事では、あなた、あなたの経験、同僚の経験を取り上げ、 私にとっては、趣味、人生、仕事です。







最後に、メソッドのコンパイル時間を測定するために使用したユーティリティを共有します: https : //github.com/RobertGummesson/BuildTimeAnalyzer-for-Xcode

各関数とそのアセンブリに費やされた合計時間を個別に表示します。








All Articles