M1 MacでのコマンドラインからのUniversal Binary作成

# Universal Binary
macOSはARMやx86_64や32bit i386やpowerpc用のバイナリを一つのバイナリにまとめて複数のアーキテクチャに対応できるUniversal Binaryに対応しています。標準の開発ツールのXCodeのGUIでもUniversal Binaryのビルドが可能ですが、既存のオープンソースのコードを利用する場合などコマンドラインでUniversal Binaryをビルドする方が便利な場面もあります。M1 Macのコマンドラインでの手順をまとめました。

- [lipoで個々のバイナリを結合](#lipo)
- [直接Universal Binaryを生成](#clangで直接生成)
- [autotools](#autotoolsの場合)
    - [自前のプログラム](#自作のautotools対応プログラムの通常ビルド)
    - [libpngとライブラリの利用](#libpng)
- [CMake](#CMakeの場合)
- [i386とx86_64のUniversal Binary](#i386とx86_64の場合)(i386での動作は未確認)

## 作業環境
~/Downloads/で作業します。

```
$ cd ~/Downloads/
```

未インストールの場合はCommand line tools for Xcodeをインストールしてください。

```
$ xcode-select --install
```

## lipo
lipoコマンドで複数のバイナリを1つのバイナリにまとめることができます。ARMバイナリとx86_64バイナリをそれぞれ独立してビルドし、lipoコマンドでARMバイナリとx86_64バイナリを一つにまとめることでARMとx86_64両対応のUniversal Binaryが作成できます。

次の内容でtest.cを作成します。現在の実行環境を表示するarchコマンドを実行するプログラムです。

```
#include <stdlib.h>

int main()
{
  system("arch");
  return 0;
}
```

-archオプションを使用してARMバイナリのtest.armとx86_64バイナリのtest.x86_64をビルドします。fileコマンドでどちらのバイナリか確認して実行します。

```
$ clang -o test.arm -arch arm64 test.c
$ clang -o test.x86_64 -arch x86_64 test.c
$ file test.*
test.arm:    Mach-O 64-bit executable arm64
test.c:      c program text, ASCII text
test.x86_64: Mach-O 64-bit executable x86_64
$ ./test.arm 
arm64
$ ./test.x86_64 
i386
```

lipoコマンドで1つのバイナリであるtestにまとめます。

```
$ lipo -create test.arm test.x86_64 -output test
```

fileコマンドで確認しそのままarmで実行とarch -x86_64でx86_64として実行の両方を試します。

```
$ file test
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64):	Mach-O 64-bit executable x86_64
test (for architecture arm64):	Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -x86_64 ./test
i386
```

## clangで直接生成
次に、clangのオプションを利用して直接Universal Binaryを作成します。上記のtest.cをそのまま使います。

### 普通にビルドした場合
ARMバイナリが生成されるのでARMとしては実行できますがx86_64としては実行できません。

```
$ clang -o test test.c
$ file test                        
test: Mach-O 64-bit executable arm64
$ ./test
arm64

$ arch -arm64 ./test  
arm64

$ arch -x86_64 ./test
arch: posix_spawnp: ./test: Bad CPU type in executable
```

同様にx86_64としてビルドした場合x86_64として実行できますがARMとしては実行できません。

```
$ clang -arch x86_64 -o test test.c  
$ file test
test: Mach-O 64-bit executable x86_64
$ ./test
i386
$ arch -x86_64 ./test              
i386

$ arch -arm64 ./test
arch: posix_spawnp: ./test: Bad CPU type in executable
```

### Universal Binaryとしてビルドした場合
clangに-arch x86_64 -arch arm64をオプションを指定してUniversal Binaryとしてビルドします。armとしてもx86_64としても実行できるようになります。

```
$ clang -arch x86_64 -arch arm64 -o test test.c
$  file test
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64):	Mach-O 64-bit executable x86_64
test (for architecture arm64):	Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -arm64 ./test
arm64
$ arch -x86_64 ./test
i386
```

### Rosetta2環境でビルドした場合
Rosetta2環境でビルドすると標準ではx86_64バイナリが生成されます。archコマンドでx86_64環境のzshに移って確認します。

```
$ arch -x86_64 /bin/zsh
```

```
$ clang -o test test.c
$ file test
test: Mach-O 64-bit executable x86_64
$ ./test
i386
```

なおRosetta2環境下からARMバイナリを実行しARMバイナリがarchを呼ぶ場合はx86_64としてarchコマンドを実行するようです。

```
$ clang -arch arm64 -o test test.c
$ file test                       
test: Mach-O 64-bit executable arm64
$ ./test
i386
```

Rosetta2環境から抜けます。

```
$ exit
```

## autotoolsの場合
autotoolsはconfigureスクリプトを使って様々な環境に適合できるよう調整したりビルドオプションを指定してビルドできるようにするための開発ツールです。configureスクリプトを使ってmakeコマンド用のMakefileを作成します。GNUをはじめ多くのオープンソースプログラムで使われています。


準備としてbrewからautoconf, automake, libtoolをインストールします。

```
$ brew install autoconf automake libtool
```

brewが未インストールの場合は先にbrewをインストールして上のコマンドを実行してください。

```
$ arch -arm64e /bin/bash -c "$(curl -fsSL $ https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```

### 自作のautotools対応プログラムの通常ビルド
最小限のautotools対応プログラムを作ってUniversal Binaryとしてビルドします。特別な対応は不要でconfigureスクリプトにCFLAGSやLDFLAGSを指定するだけでUniversal Binaryとしてのビルドが可能です。


autotools-test以下にMakefile.am, src/test.c, src/Makefile.amを作成します。

```
$ mkdir autotools-test
$ cd autotools-test
$ mkdir src
```

Makefile.am

```
SUBDIRS=src
```

src/Makefile.am

```
bin_PROGRAMS=test
test_SOURCES=test.c
```

src/test.cは上記をコピーしてください。

```
$ cp ../test.c src/
```

autoscanを実行しconfigure.scanをconfigure.acに変更し、中の

```
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
```

を

```
AC_INIT([test], [1.0], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE
```
に書き換えます。

```
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([test], [1.0], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/test.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([stdlib.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT
```

あとは必要なコマンドを実行してconfigureスクリプトを作成します。

```
$ aclocal
$ autoheader
$ touch NEWS README AUTHORS ChangeLog
$ automake -a -c
$ autoconf
```

configureしてmakeすればARMバイナリが生成され問題なく実行でます。

```
./configure
make
```

```
$ file src/test
src/test: Mach-O 64-bit executable arm64
$ src/test
arm64
```

クリーンしておきます。

```
$ make clean
```


### 自作のautotools対応プログラムのUniversal Binaryビルド
CFLAGSとLDFLAGSにそれぞれ"-arch x86_64 -arch arm64"を指定することでARMとx86_64両対応でビルドされます。envコマンドで環境変数に値を与えるかexportで環境変数を設定してください。

```

$ env CFLAGS="-arch x86_64 -arch arm64" LDFLAGS="-arch x86_64 -arch arm64" ./configure
```
または

```
$ export CFLAGS="-arch x86_64 -arch arm64"
$ export LDFLAGS="-arch x86_64 -arch arm64"
$ ./configure
```

makeしてfileでUniversal Binaryになっているのを確認して実行します。

```
$ make
$ src/test
src/test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
src/test (for architecture x86_64):	Mach-O 64-bit executable x86_64
src/test (for architecture arm64):	Mach-O 64-bit executable arm64
$ src/test
arm64
$ arch -x86_64 src/test
i386
```

~/Downloads/に戻ります。

```
$ cd ..
```

### libpng
autotoolsを使用するオープンソースのライブラリの例としてlibpngをUniversal Binaryでビルドして、サンプルプログラムをリンクして利用してみます。

http://www.libpng.org/pub/png/libpng.html
よりlibpng-1.6.37.tar.xzをダウンロードして展開します。

```
$ tar xvfJ libpng-1.6.37.tar.xz
```

#### libpngのARMバイナリビルド

まず普通にビルドして/usr/local/opt/libpng-arm64以下にインストールします。

```
$ cd libpng-1.6.37
./configure --prefix=/usr/local/opt/libpng-arm64
make
make install
cd ..
```

ARMバイナリとしてビルドされます。

```
$ file /usr/local/opt/libpng-arm64/lib/libpng.dylib 
/usr/local/opt/libpng-arm64/lib/libpng.dylib: Mach-O 64-bit dynamically linked shared library arm64
```

http://zarb.org/~gc/html/libpng.html
にあるコードをpngtest.cとして作成しpngtestとしてビルドします。pngファイルの画素ごとに赤を0緑を青の値にしてpngファイルに書き込むプログラムです。入力画像は適当な画像を用意してtest1.pngとしてください。出力ファイルをtest2.pngとします。

ARMバイナリとしてビルドしARMライブラリのlibpngをリンクしています。

```
clang -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-arm64/include -L/usr/local/opt/libpng-arm64/lib
 file pngtest
pngtest: Mach-O 64-bit executable arm64
./pngtest test1.png test2.png
```

x86_64バイナリはうまくリンクできずエラーになります。libpngがARMバイナリだからです。

```
$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-arm64/include -L/usr/local/opt/libpng-arm64/lib
(略)
Undefined symbols for architecture x86_64:
  "_png_create_info_struct", referenced from:
(略)
```

#### libpngのx86_64バイナリビルド

次にlibpngをx86_64バイナリとしてビルドしましょう。/usr/local/opt/libpng-x86_64にインストールします。CFLAGSとLDFLAGSに-arch x86_64を指定することでx86_64バイナリとしてビルドできます。

```
$ cd libpng-1.6.37
$ make clean
$ env CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" ./configure --prefix=/usr/local/opt/libpng-x86_64
$ make
$ make install
$ cd ..
```

```
% file /usr/local/opt/libpng-x86_64/lib/libpng.dylib
/usr/local/opt/libpng-x86_64/lib/libpng.dylib: Mach-O 64-bit dynamically linked shared library x86_64
```

pngtest.cをx86_64バイナリとしてビルドしてx86_64バイナリのlibpngとリンクします。
正常に実行できます。

```
$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-x86_64/include -L/usr/local/opt/libpng-x86_64/lib

$ file pngtest
pngtest: Mach-O 64-bit executable x86_64
$./pngtest test1.png test2.png
```

#### libpngのUniversal Binaryビルド
libpngをUniversal Binaryとしてビルドします。CFLAGSとLDFLAGSに-arch x86_64 -arch arm64を指定してARMとx86_64両対応でビルドします。

```
$ cd libpng-1.6.37
$ make clean
$ env CFLAGS="-arch x86_64 -arch arm64" LDFLAGS="-arch x86_64 -arch arm64" ./configure --prefix=/usr/local/opt/libpng-universal
$ make 
$ make install
$ cd ..
```

ARMとx86_64対応Universal Binaryとしてビルドされています。

```
$ file /usr/local/opt/libpng-universal/lib/libpng.dylib
/usr/local/opt/libpng-universal/lib/libpng.dylib: 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]
/usr/local/opt/libpng-universal/lib/libpng.dylib (for architecture x86_64):	Mach-O 64-bit dynamically linked shared library x86_64
/usr/local/opt/libpng-universal/lib/libpng.dylib (for architecture arm64):	Mach-O 64-bit dynamically linked shared library arm64
```

まず普通にpngtest.cをビルドしてリンクしてみます。

```
$ clang -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib
```

ARMバイナリとしてリンクでき正常に実行できます。

```
$ file pngtest
pngtest: Mach-O 64-bit executable arm64
$ ./pngtest test1.png test2.png
```


clangに-arch x86_64を与えてx86_64としてpngtest.cをビルドしてリンクするとx86_64バイナリとしてリンクでき正常に実行できます。

```
$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib
```
```
$ file pngtest
pngtest: Mach-O 64-bit executable x86_64
$ ./pngtest test1.png test2.png
```

さらにclangに-arch x86_64 -arch arm64を与えればUniversal Binaryとしてpngtest.cをビルドしてリンクでき実行できます。

```
$ clang -arch x86_64 -arch arm64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib
```
```
$ file pngtest 
pngtest: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
pngtest (for architecture x86_64):	Mach-O 64-bit executable x86_64
pngtest (for architecture arm64):	Mach-O 64-bit executable arm64
$ ./pngtest test1.png test2.png
```

## CMakeの場合
CMakeは様々な環境でビルドできるようにするための開発ツールです。UnixのMakefile、macOSのXcode、WindowsのVisual Studioなどでビルドに必要なファイルを自動生成できます。


### 自作のCMake対応プログラムの通常ビルド
test.cをCMakeに対応させます。

cmaketest以下にtest.cとCMakeLists.txtを作成します。

```
$ mkdir cmaketest
$ cd cmaketest
```

test.cは上記をコピーしてください。

```
$ cp ../test.c .
```

CMakeLists.txtは

```
cmake_minimum_required(VERSION 2.8)
project(test_cmake C)
add_executable(test test.c)
```
とします。

build以下でcmakeでMakefileを作成してビルドします。

```
$ mkdir build
$ cd build
$ cmake ..
$ make
$ file test
test: Mach-O 64-bit executable arm64
$ ./test
arm64
$ cd ..
```

### 自作のCMake対応プログラムのx86_64ビルド
CMAKE_OSX_ARCHITECTURESにx86_64を指定するとclangに-arch x86_64を指定するのと同じ意味となりx86_64バイナリをビルドできます。build-x86_64以下でビルドします。

```
$ mkdir build-x86_64
$ cd build-x86_64 
$ env CMAKE_OSX_ARCHITECTURES=x86_64 cmake ..
$ make
$ file test 
test: Mach-O 64-bit executable x86_64
$ ./test
i386
$ cd ..
```

### 自作のCMake対応プログラムのUniversal Binaryビルド
CMAKE_OSX_ARCHITECTURESにx86_64;arm64を指定するとclangに-arch x86_64 -arch arm64と同じ意味になりUniversal Binaryとしてビルドできます。build-universal以下でビルドします。

```
$ mkdir build-universal
$ cd build-universal 
$ env CMAKE_OSX_ARCHITECTURES="x86_64;arm64" cmake ..
$ file test 
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64):	Mach-O 64-bit executable x86_64
test (for architecture arm64):	Mach-O 64-bit executable arm64
```

ARMとしてもx86_64としても実行できます。

```
$ ./test 
arm64
$ arch -x86_64 ./test 
i386
```

上に戻ります。

```
cd ..
```


## i386とx86_64の場合
32bit i386とのUniversal Binaryも同様に作れそうなのですがmacOS Catalina以降は32bitバイナリ非対応なのでそのままではビルドできません。

```
$ clang -arch i386 -o test test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd, missing required architecture i386 in file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd (3 slices)
Undefined symbols for architecture i386:
  "_system$UNIX2003", referenced from:
      _main in test-ea1c56.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

下記のサイトから32bit対応macOS用SDK(MacOSX10.13.sdk.tar.xz)をダウンロードして/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs以下にインストールしてください(10.14でも良さそうですがi386用SDKが入っていない?)。

https://github.com/phracker/MacOSX-SDKs/releases

```
$ tar xvfJ MacOSX10.13.sdk.tar.xz
$ sudo mv MacOSX10.13.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs 
```

### MacOSX10.13.sdkを利用したi386とx86_64のUniversal Binaryビルド
clangに-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdkを指定することでMacOSX10.13.sdkを使用してビルドできます。

```
$ clang -arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
$ file test
test: Mach-O executable i386
```

ただし、M1 Macは32bit i386バイナリの実行ができないのでエラーになります。

```
$ ./test 
zsh: bad CPU type in executable: ./test
```

32bit i386と64bit x86_64のUniversal Binaryのtest-i386_x86_64としてビルドすればx86_64バイナリとしてM1 Macでも実行できます。

```
$ clang -arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test-i386_x86_64 test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
$ file test-i386_x86_64 
test-i386_x86_64: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
test-i386_x86_64 (for architecture i386):	Mach-O executable i386
test-i386_x86_64 (for architecture x86_64):	Mach-O 64-bit executable x86_64
$ ./test-i386_x86_64 
i386
```

逆にMacOSX10.13.sdkはARM非対応なので-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdkを指定してARMバイナリを作ろうとするとエラーになります。

```
$ clang -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test test.c     
In file included from test.c:1:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:63:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/_types.h:27:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/_types.h:32:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/cdefs.h:761:2: error: 
      Unsupported architecture
#error Unsupported architecture
(略)
```

したがって、ARMとi386とx86_64のUniversal Binaryを作るためにはARMバイナリを別途ビドしてlipoで結合する必要があります。

```
$ clang -arch arm64 -o test-arm test.c
$ file test-arm 
test-arm: Mach-O 64-bit executable arm64
$ ./test-arm 
arm64
```

lipoでtest-i386_x86_64とtest-armを結合させてi386、x86_64、ARM対応Universal Binaryのtestを作成します。

```
$ lipo -create test-arm test-i386_x86_64 -output test
$ file test
test: Mach-O universal binary with 3 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture i386):	Mach-O executable i386
test (for architecture x86_64):	Mach-O 64-bit executable x86_64
test (for architecture arm64):	Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -x86_64 ./test  
i386
```

### autotoolsでのi386とx86_64のUniversal Binaryのビルド
CFLAGSとLDFLAGSに-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定すればOKです。autotools-testを再利用します。

```
$ cd autotools-test
$ make clean
$ export CFLAGS="-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export LDFLAGS="-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ ./configure
$ make 
$ file src/test
src/test: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
src/test (for architecture i386):	Mach-O executable i386
src/test (for architecture x86_64):	Mach-O 64-bit executable x86_64
$ src/test
i386
$ cd ..
```

### CMakeを利用したi386とx86_64のUniversal Binaryのビルド
https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-do-i-build-universal-binaries-on-mac-os-x
によるとCMAKE_OSX_SYSROOTに/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定するだけで良さそうですが、CFLAGSとLDFLAGSに-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定しないとダメのようです。CMAKE_OSX_ARCHITECTURESにi386;x86_64を指定してi386とx86_64のUniversal Binaryとしてビルドします。

```
$ cd cmaketest
$ export CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/
$ export CFLAGS="-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export LDFLAGS="-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export CMAKE_OSX_ARCHITECTURES="i386;x86_64"
$ mkdir build-i386_x86_64
$ cd build-i386_x86_64
$ cmake ..
$ make
$ file test
test: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
test (for architecture i386):	Mach-O executable i386
test (for architecture x86_64):	Mach-O 64-bit executable x86_64
$ ./test
i386
```

## まとめ
M1 MacでコマンドラインからUniversal Binaryとしてビルドする様々な手順を示せたと思うので、Universal Binaryのビルドが必要なときに参考にしてみてください。

## 参考サイト
https://news.mynavi.jp/article/osxhack-268/
https://developer.apple.com/library/archive/technotes/tn2005/tn2137.html
https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-do-i-build-universal-binaries-on-mac-os-x
https://www.itmedia.co.jp/enterprise/articles/0712/27/news012_2.html
https://www.webcyou.com/?p=9630

https://zenn.dev/ress/articles/069baf1c305523dfca3d
https://qiita.com/narupo/items/f63b8e768f17ce50f398
https://kamino.hatenablog.com/entry/cmake_tutorial1