[日本語訳] Carthage issues, Xcode 12, XCFrameworks, Apple Silicon, etc.
訳者注:この記事は以下の記事の日本語訳です
Xcode 12がリリースされて以来、それは私たちiOS開発者コミュニティにいくつかのトラブルをもたらしました。少なくとも carthage
を1つ以上のプロジェクトで使用している人たちにとっては…
数ヶ月間 Xcode 12ベータを使用している場合、発生している問題とワークアラウンドの存在を既に知っているでしょう。今日(訳者注:2020年9月26日)でリリースから約2週間が経過しましたが、なぜすでに確定的な修正がないのか不思議に思うかもしれません。この記事では、この問題についての私の理解と、それが何に起因しているのかを共有します。
詳細に深く入る前に、 carthage が何をしているか、それがどのように動作するかを理解することは重要です。一部の人にとってはそれは自明であるかもしれませんが、他の人は手がかりを持っていないかもしれません。
1 — carthageがどのように動作するのか?
実は非常にシンプルです。iPhone Simulator上でアプリを実行するかiPhone実機でアプリを実行するかを切り替えるたびにコマンドラインを行き来したくないので、Carthage は各依存ライブラリの fat framework を構築します。これにより、両方のプラットフォームをシームレスに切り替えることができます。アプリはコンパイル済みのframeworkとリンクするだけです。
fat frameworkとは、複数のバイナリをマージしたバイナリをもつframeworkのことです。iOSプロジェクトで必要となる依存ライブラリでいうと、 iphonesimulator
と iphoneos
それぞれをビルドした結果である2つのバイナリを、マージすることになります。
基本的にcarthageは以下の2つのステップを踏んで依存ライブラリを構築します:
xcodebuild
を使って各プラットフォーム (iphonesimulator
とiphoneos
) 用にビルドlipo
を使って、それらをマージ
そして通常は、あなたのXcodeプロジェクトではCarthageが提供する copy-frameworks
スクリプトを実行する Build Script Phase を設定しています。これは、AppStore上で両方のプラットフォーム用のバイナリ配布を避けるためです。スクリプトは不要なバイナリを除去するために再び lipo
を使用し、ターゲットとするプラットフォーム用のバイナリだけを保持するようにします。これにより、アプリの embedded framework には fat でないframeworkを組み込むことができます。
2 — Xcode 12 でのCarthageの問題
さよなら VALID_ARCHS
、ようこそ EXCLUDED_ARCHS
、これがビルド設定におけるXcode12のアップデートです。
これは注目すべき変更である一方、 iphonesimulator
向けにビルドすると、 arm64
用のシンボルが生成されることに気付いたかもしれません。これは大きな変化で、問題を発生させている本当の要因です。
iPhone Simulator上でアプリを実行するということは、Mac上で実行するということであり、これまでの実際の意味はアーキテクチャ i386
や x86_64
上で実行することでした。
6月に開催されたWWDC 2020で明らかにされたApple Siliconは、Appleが製造する次世代の arm64
プロセッサです。これらのプロセッサはMac用に設計されており、これがあなたのXcode 12が今 iphonesimulator
向けに arm64
シンボルを生成する理由です。
私の理解では、 lipo
は同じアーキテクチャの複数のバージョンをマージすることができず、これがCarthageが iphonesimulator
と iphoneos
をマージしようとしたときに失敗する理由です(双方とも arm64
を含むようになりました)。
以下のスクリプトは、Carthage コミュニティで共有されたワークアラウンドスクリプトです。これは、 iphonesimulator
をターゲットにしたときにXcode 12が arm
アーキテクチャをビルドしないようにしてくれます。
'EXCLUDED_ARCHS[sdk=iphonesimulator*] = ... '
を使用している別のバージョンのスクリプトがあるかもしれません。
これは長期的な解決策ではないかもしれません
このスクリプトは今のところ正常に動作しますが、我々が次世代の Apple Silicon MacBookでcarthageを使用する時には壊れるかもしれません…
(訳者注:原文が書かれたのは2020年9月26日のため、「次世代の」という表現になっています。本翻訳は2021年1月に書いており、Apple Silicon Mac はすでに現実です。)
あなたのコードに( #if targetEnvironment(simulator)
を使用して)シミュレータ固有のコードが含まれている場合、 arm64
アーキテクチャを除外しても十分ではないでしょう。
これが XCFramework
が舞台に登場する理由です…
3 — XCFrameworkは fat framework より優れている
XCFrameworksはXcode 11で導入されたもので、バイナリを配布するためのソリューションとしては、fat frameworkよりも優れています。コンセプトはシンプルで、複数のバイナリを一つにまとめるのではなく、複数のバイナリを配布できる新しいファイル構造をXcodeに導入しようというものです。
XCFramework と fat framework の違いを確認してみましょう。
fat frameworkの例
fat frameworkの場合のファイル構造を以下に示します(Carthageでビルドしています)。
file
コマンドを実行して、 MyFramework
バイナリに何のアーキテクチャが含まれているかを確認してみましょう…
MyFramework: Mach-O universal binary with 2 architectures:
[x86_64:Mach-O 64-bit dynamically linked shared library x86_64]
[arm64:Mach-O 64-bit dynamically linked shared library arm64]MyFramework (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
MyFramework (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
XCFrameworkの例
XCFramework
のファイル構造は以下のようになっています。
fatバイナリを含む1つだけのframeworkを持つのではなく、特定の命名規則の下に構成された MyFramework.framework
の複数のバリエーションが存在しています。これらの各バリエーションは、それぞれのプラットフォームで有効なアーキテクチャを持つfatではないバイナリを含んでいます。
なぜそれが良いのか?
- マージ&除去が必要ない : XCFrameworkが優れている第一の理由は、高速であるということです。
lipo
を使用する場合、2つ(またはそれ以上)のプラットフォームのバイナリをマージし、最終的に1つのプラットフォームのバイナリにするために除去処理が行われます。これは必要ないことのように思えます。XCFramework
を使用する場合、Xcodeはリンクするバイナリがどこにあるかをシンプルに理解しています。 - プラットフォーム固有のアーキテクチャ : 先程の例では、選択された
ios-arm64_x86_64-simulator
という名前のフォルダには、iphonesimulator
用にビルドされたMyFramework.framework
のバリエーションが含まれています。この名前の付け方は、通常のx86_64(現在のMacBook用)だけでなく、arm64(将来のApple Siliconマシン用)の両方のアーキテクチャがバイナリに含まれることを暗示しています。これはまさにlipo
が現在失敗しているところです。XCFramework
は、異なるプラットフォームに同じアーキテクチャを配布することを可能にします。つまり、tvOS
,tvOS Simulator
,macOS
,iOS
,iOS Simulator
,watchOS
など、すべてのターゲットとなるプラットフォーム向けのバイナリを含む、単一の.xcframeworkパッケージを配布することができます。これはlipo
では決して可能ではありませんでした。
4 — To be continued
CarthageのXCFrameworkサポート
すべてのソースコードがオープンソースであるとは限らないので、バイナリを配布することは常にベンダーが要求することです。そして、プラットフォーム間での共有アーキテクチャの問題を解決するのは lipo
では不可能だと思われるので、Carthageはxcframeworksをサポートする必要があります。幸運なことに、これはCarthageコミュニティで現在進行中の作業です。
XCFrameworkとSPM
XCFrameworksはXcode 11から利用可能であり、Swift Package Managerも同様です。しかし、Xcode 12で導入された swift-tools 5.3
までは、バイナリパッケージは存在していませんでした。これは別の記事で取り上げます。
これはオープンな議論ですので、遠慮なくコメントしてください。
あなたのプロジェクトが Xcode 12 に移行するのに問題がまだありますか?
こちらにも投稿してください。