どこにでもありそうな内容だが、Apple Silicon版 Mac(M1)で開発する時によく使うコマンドをまとめた。
1. ビルド編
CMakeのビルド設定
CMAKE_OSX_ARCHITECTURESを設定しないとデフォルトでは M1 macのarm64環境でビルドしたらApple Silicon版(arm64)ができる。Intel MacならIntel Mac(Rosetta2)版(x86_64)ができる。CMake 3.19.4以降でUniversal Binaryに対応している。
cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
CMake v3.19.2からはCMAKE_APPLE_SILICON_PROCESSORでビルドする環境を指定することができる。
cmake -DCMAKE_APPLE_SILICON_PROCESSOR="arm64" -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
cmake --version
で3.19.4より古かったら更新したほうがよい( brew upgrade cmake
)。
CMakeLists.txt内での処理の切り替え
CMAKE_SYSTEM_PROCESSORはコンパイル対象のプロセッサー、CMAKE_HOST_SYSTEM_PROCESSORは実行しているシステムのプロセッサーを返す。
if(APPLE)
message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_OSX_ARCHITECTURES: ${CMAKE_OSX_ARCHITECTURES}")
message(STATUS "CMAKE_INSTALL_RPATH: ${CMAKE_INSTALL_RPATH}")
foreach(ARCH IN LISTS CMAKE_OSX_ARCHITECTURES)
if(${ARCH} MATCHES "arm64")
# arm64設定
message(STATUS "CMAKE_OSX_ARCHITECTURES: arm64")
elseif(${ARCH} MATCHES "x86_64")
# x86_64設定
message(STATUS "CMAKE_OSX_ARCHITECTURES: x86_64")
else()
# 未知のプロセッサ or 未設定
message(STATUS "CMAKE_OSX_ARCHITECTURES: ${CMAKE_OSX_ARCHITECTURES}")
endif()
endforeach()
endif()
node-gypのx86_64版ビルド設定
そのままM1 macでビルドするとarm64版ができる。x86_64版は--arch=x86_64を指定する。
この方法だとUniversal binaryは作れなそう(2021/10/14現在)。
"node-gyp clean configure build --verbose --arch=x86_64"
node-gypのUniversal binaryビルド
まだ試せていないのでメモのみ(2021/10/14現在)。node-gyp-buildのここで変更が入っているのでver.4.3.0 (Sep 12, 2021)以降を使うとできそう。オプションで--arch=arm64+x86_64を指定してビルドする?
2. コマンド編
M1 Macを使っている時によく使うコマンド。
uname -m: 使っているTerminalがx86_64かarm64かを確認する。
% uname -m
arm64
arch -x86_64: arm64 terminalでx86_64コマンドを呼び出す。
"uname"コマンドをx86_64で呼び出した例。
% arch -x86_64 uname -m
x86_64
x86_64版Terminalへの切り替え
使っているターミナルをx86_64版に切り替えてからビルドする時などに使う。
% arch -x86_64 /bin/zsh
lipo -archs: 実行ファイルの対応アーキテクチャを確認する。
% lipo -archs /System/Applications/Notes.app/Contents/MacOS/Notes
x86_64 arm64e
コマンドのパスを探してアーキテクチャを確認するにはwhich ***
で囲んで戻りを使う
% lipo -archs `which node`
arm64
otool -L: リンクしているライブラリをリスト表示
M1と関係ないけど。WindowsのDependenciesみたいなもの。リンクしているライブラリを調べるのに使う。
% otool -L /System/Applications/Notes.app/Contents/MacOS/Notes
/System/Applications/Notes.app/Contents/MacOS/Notes:
/System/Library/Frameworks/PencilKit.framework/Versions/A/PencilKit (compatibility version 1.0.0, current version 1.0.0)
/System/Library/PrivateFrameworks/NotesShared.framework/Versions/A/NotesShared (compatibility version 1.0.0, current version 1872.0.0)
/System/Library/PrivateFrameworks/NotesUI.framework/Versions/A/NotesUI (compatibility version 1.0.0, current version 1872.0.0)
...
install_name_tool : リンクしているdylibを変更
otool -L と一緒によく使うコマンドでinstall_name_toolがある。リンクしているdylibのパスを @rpath に後から変更したい時やdylibのパスを修正するときなどに利用する。"a.out"という実行ファイルのlibc++.1.dylibのリンクパスを /usr/lib/libc++.1.dylib
に変更する例。
% install_name_tool -change /usr/local/opt/llvm/lib/libc++.1.dylib /usr/lib/libc++.1.dylib a.out
@rpathを追加した場合、% otool -l b.out
してcmd LC_RPATH
という出力が出て来なかったら @rpathが設定されていないのでadd_rpathする。
% install_name_tool -add_rpath "@executable_path" b.out
おまけ(/usr/libにシステムのdylibがない件)
Apple Siliconと共に登場したBig Surから“dynamic linker cache”という仕組みが導入され、/usr/libにシステムのdylibが置かれなくなった。
New in macOS Big Sur 11.0.1, the system ships with a built-in dynamic linker cache of all system-provided libraries. As part of this change, copies of dynamic libraries are no longer present on the filesystem. Code that attempts to check for dynamic library presence by looking for a file at a path or enumerating a directory will fail. Instead, check for library presence by attempting to dlopen() the path, which will correctly check for the library in the cache. (62986286)
3. シェルスクリプト例
動作環境(x86_64/arm64)を見て処理を切り替える
Apple SiliconかIntel Macかを見分けるビルドスクリプトを作る時に利用したものから抜粋。
if uname -m | grep --quiet "arm64" 2>&1 > /dev/null ; then
echo 'is Apple Silicon'
else
echo 'is Intel/Rosetta2'
fi
M1 Macのターミナルから実行すると、
% zsh ./checkMacOS.sh
is Apple Silicon
M1 MacのRosette2上のVSCodeターミナルから実行すると、
% zsh ./checkMacOS.sh
is Intel/Rosetta2
となる。