Universal Binaryの調査

2013/06/22

Mac OS Xの必要システム条件

10.7 Lion 2011/7/20 Intel Core 2 Duo、Core i3、Core i5、Core i7、またはXeonプロセッサを搭載したMac
10.6 Snow Leopard 2009/8/28 Intelプロセッサを搭載したMac
10.5 Leopard 2007/10/26 Intelプロセッサを搭載したMac、PowerPC G5、PowerPC G4(867MHz以上)
10.4 Tiger 2005/4/29 PowerPC G3/G4/G5 プロセッサ

OS Xが出てから10.4まではサポートCPUは変わっていなかった (I/O関係でサポート対象が変わっていたようだが)と思うがIntel Macが登場 した10.4以降はバージョンアップのたびに変化してきた。 次の変化は32ビットしかサポートしていない、または完全な64ビットが サポートできないIntelプロセッサがサポート外になるのだろうが、当分先の事で あろう。 予想とおり第一世代のIntel Mac(Core Duo)は10.7でサポートから外れた。 想像していたよりもかなり早いテンポであるが、Appleの技術力の衰退が そうさせているのではないかと思ってしまう。

10.5でも64Bitのアプリの構築および実行が出来たようだが、システム付属の アプリはすべて32Bitだったのではないだろうか。10.5ではシステム側の64Bit の準備をおこなって、10.6ではアプリをすべて64Bitにするという順序立ては さすがAppleと思う。おばかなシステム屋はすべて一緒にやって失敗する。

後から気がついたのだが、10.6の/usr/binのバイナリはppcでもビルドされている。 10.6のプロジェクト開始時は10.6でもG4のサポート対象にしていて、なんらかの 事情により、ppcのサポートが出来なくなってしまったのではないだろうか。

10.4のIntelへ移行時に入っていたppcのバイナリをIntelで実行するための Rosettaは10.6でオプションになり10.7でサポートされなくなった。

CarbonのUniversal Binaryで、プリンタに付属だった「CDダイレクトプリント」は 「※OS X 10.7(Lion)は動作保証外です」としていて、サウンドIFに付属だった 「sound It! 3.0」は「Mac OS X Lion(10.7)には対応していません」としている。 10.7でApple側からはCarbon/i386の終了の案内は出ていなかったと思うのだが。。。

Xcode 3.2.5のgcc 4.2でビルドしたバイナリーのfileコマンドで確認した内容。 この場合このアプリの動作環境は10.410.5以降のG4以降の機種になるの ではないかと思われる。後日追記:gcc 4.2で10.4のSDKを使うと "error: stdarg.h: No such file or directory"とエラーが出るため 10.5以降と思われる。10.4のSDKを使う為にはgcc 4.0でないとダメです。

Zebra: Mach-O universal binary with 3 architectures
Zebra (for architecture x86_64):        Mach-O 64-bit executable x86_64
Zebra (for architecture i386):  Mach-O executable i386
Zebra (for architecture ppc7400):       Mach-O executable ppc

このバイナリのアプリケーションを10.4 G3のマシンで起動すると クラッシュする。 CrashReporterのログには"incompatible cpu-subtype"と出ている。 10.4をリリースしていた時にはG4以上のバイナリーは想定外で、gcc 4.2を 提供するときにはその事を忘れていたかgcc4.0を同梱しているので対応する 必要はないと考えたのだと思われる。 同じ環境でi386だけのバイナリを実行すると以下のダイアログが出る。

i386only

Xcode 3.2.5のgcc 4.0でビルドしたバイナリーの中身。この場合は64bitのサポートが なくなるが10.4のG3のサポートが出来る。

ppctest: Mach-O universal binary with 2 architectures
ppctest (for architecture i386):     Mach-O executable i386
ppctest (for architecture ppc):      Mach-O executable ppc

lipoコマンドを使って、gcc 4.0でビルドした内容を抜き出して、gcc 4.2でビルド したIntel系のバイナリと引っ付けると10.4のG3以降の環境で動作できるアプリに なる。以下が簡単に実行するためのスクリプトです。

#!/bin/sh

APP="Zebra"
CONT="Contents/MacOS"

lipo -create ${APP}.app/${CONT}/${APP} ${APP}32.app/${CONT}/${APP}32 -output ${APP}

mv ${APP} ${APP}.app/${CONT}/${APP}

configureベースのオープンソースをUnivaral BinaryにするにはCFLAGSを設定する。 下はlibusbをconfigureする方法。

./configure CFLAGS="-arch i386 -arch x86_64 -arch ppc" --disable-dependency-tracking

Xcode 3.2.5のインストール時に10.4 SDKを選択してもSDKはインストールされない。 ただし10.4 SDKをチェックせずにインストールするとgcc 4.0を選択しても以下の エラーが出て10.4のビルドができなくなる。おそらくPre/Postインストールで何ら かの処理だけは実行しているのではないかと想像される。

スクリーンショット(2012-06-14 6.49.10)
error: stdarg.h: No such file or directory

SDKは3.1.2などのPackagesに含まれるMacOSX10.4.Universal.pkgでインストール できる。インストールするときは「インストール先の選択」で「フォルダーの選択」 を選んで/Developerを選んでおく。

スクリーンショット(2012-06-14 6.49.42) スクリーンショット(2012-06-16 11.13.34)

ppc64を指定してもgcc 4.2/4.0とも64BitのPowerPCのコードは生成されない。 これはppc64なコードをRossetaがエミュレートできないためかもしれない。 おそらくppcの生成もそれほど遠くないうちに出来なくなるのではないかと思われる。 最近のAppleは何の予告もなくサポートを打ち切る事があるので、十分に注意が 必要だと思われる。(iOS 3.xのSDKが3.2.5で突然なくなって困りました)

NSApplicationDelegateを使った場合には10.6以降の環境でしか動かなくなると 思われる。

Xcode 3.2.5のSDKのサポートは10.4からだが作り方によっては10.3(もしくはそれ以前) でも動きそうな感じがあるが全く試していない。

元祖Airはメモリが2Gのため10.6のカーネルは32bitで動いていて、ユーザランド (アプリ)は64ビットで動いているようだ。これはシステムプロファイラの ソフトウエアの項目で「64ビットカーネルと機能拡張」で確認できる。 この環境で64ビットのバイナリを含むユニバーサルバイナリの 32ビットコードを実行するにはアプリの「情報をみる」で「32ビットモードで開く」 にチェックを入れて実行する。

PPCコードを実行するRossetaは10.6からシステムインストール時にはインストールされず OS起動後にPPCなバイナリを実行したときに、オプションでのインストールになっている。

システムに含まれるkextをfileコマンドで確認すると以下のような感じになっている。 64ビットのカーネルであがっている場合は64ビットのバイナリを含まないkextは利用 できないのではないかと思われるが確認環境がないため未確認。

msdosfs: Mach-O universal binary with 2 architectures
msdosfs (for architecture x86_64):      Mach-O 64-bit kext bundle x86_64
msdosfs (for architecture i386):        Mach-O object i386

iPhoneのアプリをビルドしたところは以下のような感じ。

Pigeon: Mach-O universal binary with 2 architectures
Pigeon (for architecture armv6):        Mach-O executable arm
Pigeon (for architecture armv7):        Mach-O executable arm

必要以上には複雑にはなっていないようにも思うが、十分複雑だ。。。

新しい環境でビルドしたバイナリが、10.6でIllegal instructionとなり起動できない ケースがあります。ESP32のgccやstlinkのコマンドなどがそうでした。 Mach-O 64-bit executable x86_64なのになぜなんでしょうか? ほんとAppleの技術の衰退には目をおおいたくなります。(2018/3/1)

以下のページが大変参考になりました。

Universal Binary【前編】
Universal Binary【後編】
やっぱりスゴい! Snow Leopardの「64bit対応」