Intel/Appleシリコン対応Universalバイナリーを作ってみた


Universalバイナリーとは

Apple社がWWDC20で新しいmacOSのバージョンmacOS 11 Big Surの発表と共に自社設計のArmベースのチップ(Appleシリコン)をMacに搭載することも発表した。
今までのIntelのチップからAppleシリコンの移行をよりスムーズなものにするために、AppleはPowerPCからIntelへの移行の時と同様、二つのツールを発表した。一つはIntel用のバイナリーをARM用に動的に変換するプログラムRosetta2。そして、もう一つがIntel、ARM両方で実行できるUniversalバイナリー。
今回はXcode12でUniversalバイナリーをビルドする方法とバイナリーがどのアーキテクチャーに対応しているか確認する方法を紹介する。

Universalバイナリーのビルド方法

AppleデベロッパーアカウントからXcode12をダウンロードして、既存のXCodeプロジェクトを開く。
プロジェクトの設定画面から、ビルドしたいアプリケーションのビルド設定を表示する。
“Architectures”という項目のオプションから”Standard Architectures (64-Bit Intel and ARM)”を選択する。

ビルドターゲットを”Any Mac(Apple Silicon, Intel)”を選択してUniversalバイナリーをビルドする。

今回ビルドするのはプレプロセッサマクロでIntelMac、AppleSiliconMacで別の文字列が出力される簡単な分岐処理が実装されているコマンドラインツールだ。

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
#if defined(__x86_64__)
    printf("Arch is x86_64\n");
#elif defined(__aarch64__)
    printf("Arch is Arm64\n");
#else
    printf("Unknown architecture\n");
#endif
    return 0;
}

ビルドターゲットを"My Mac"にしてビルドしたIntel用バイナリーと比べてみるとUniversalバイナリーの方が2倍ほど大きかった。

Intel用の実行コードとAppleSilicon用の実行コードがファイルに格納されているのでUniversalバイナリーは2倍のサイズになっている。

バイナリーの対応アーキテクチャー確認方法

バイナリーがx86_64とARM両方で実行できるUniversalバイナリーかを確認するためにコマンドラインツールのlipoを使用する。
対応アーキテクチャーを調べるにはオプションの「-archs」を足して実行する。

lipo -archs バイナリーへのパス

コマンドは「lipo -archs バイナリーへのパス」。以下のような返事が表示される。

Universalビルドしたバイナリーはx86とARMの両アーキテクチャに対応していることが分かる。

最後にツールがIntel、AppleSilicon環境で違う文字列を出力することを確認した。

Intel環境

AppleSilicon環境

環境に依存するコードはプレプロセッサマクロで分けることができるのは便利なので覚えておこう!