dittoの--archオプションを使うと、Universalバイナリ(複数のアーキテクチャを含むMach-Oバイナリ)をコピーしながら、指定したアーキテクチャだけを残した「thin」なバイナリにできる。ディレクトリやアプリのバンドルをまとめて処理できる。

参考: 【ditto】コマンドでディレクトリをコピーする

Universalバイナリを用意する

検証用に、arm64とx86_64の両方を含むUniversalバイナリをビルドする。

$ printf '#include <stdio.h>\nint main(void){puts("hello");return 0;}\n' > hello.c
$ clang -arch arm64 -arch x86_64 -o hello hello.c
$ lipo -info hello
Architectures in the fat file: hello are: x86_64 arm64

--archでアーキテクチャを指定してコピーする

--archにアーキテクチャ名を指定すると、そのアーキテクチャだけを含むバイナリとしてコピーする。

$ ditto --arch arm64 hello hello-arm64
$ lipo -info hello-arm64
Non-fat file: hello-arm64 is architecture: arm64
$ ./hello-arm64
hello

ファイルサイズも小さくなる。

$ stat -f "%z %N" hello hello-arm64
49816 hello
33432 hello-arm64

--archを複数指定すると、指定したアーキテクチャをすべて含むバイナリになる。

$ ditto --arch arm64 --arch x86_64 hello hello-both
$ lipo -info hello-both
Architectures in the fat file: hello-both are: x86_64 arm64

アプリのバンドルをまとめてthin化する

ディレクトリを指定すると、配下のMach-Oバイナリをすべてthin化してコピーする。Mach-Oバイナリ以外のファイルはそのままコピーされる。

Universalバイナリで配布されているCotEditorのアプリを、arm64だけにしてコピーした結果は以下の通り。

$ lipo -info /Applications/CotEditor.app/Contents/MacOS/CotEditor
Architectures in the fat file: /Applications/CotEditor.app/Contents/MacOS/CotEditor are: x86_64 arm64
$ ditto --arch arm64 /Applications/CotEditor.app CotEditor-arm64.app
$ du -sh /Applications/CotEditor.app CotEditor-arm64.app
29M	/Applications/CotEditor.app
22M	CotEditor-arm64.app
$ lipo -info CotEditor-arm64.app/Contents/MacOS/CotEditor
Non-fat file: CotEditor-arm64.app/Contents/MacOS/CotEditor is architecture: arm64

thin化したアプリも、コード署名の検証に成功した。

$ codesign --verify --deep --strict --verbose=2 CotEditor-arm64.app
CotEditor-arm64.app: valid on disk
CotEditor-arm64.app: satisfies its Designated Requirement

指定したアーキテクチャを含まないバイナリはコピーされない

--archで指定したアーキテクチャを含まないMach-Oバイナリは、コピー対象から外れる。エラーは表示されない。

$ ditto --arch x86_64 hello-arm64 hello-x86
$ echo $?
0
$ ls hello-x86
ls: hello-x86: No such file or directory

ディレクトリをコピーした場合も、該当するバイナリだけが黙って抜け落ちる。ppcを指定すると、Mach-Oバイナリのbin/helloがコピーされず、テキストファイルのreadme.txtだけが残る。

$ find app
app
app/bin
app/bin/hello
app/readme.txt
$ ditto --arch ppc app app-ppc
$ find app-ppc
app-ppc
app-ppc/bin
app-ppc/readme.txt

終了コードも0になるため、--archを使う場合はコピー後にlipo -infoなどで結果を確認しておくとよい。

参考

DITTO Command: Copy directory hierarchies, create and extract archives in macOS