2020-11-26

Apple Silicon MacでshellをIntelモードで簡単に起動するには arch -arch x86_64 zsh、Intelコードをコマンドで作成するには cc -arch x86_64、Universalバイナリ作成は lipo -create

新しいコンピュータでまずやってみるのがHelloWorldアプリ。
Xcodeでの例はたくさんあると思います。
でももっとシンプルにC言語でのHelloWorldももちろん作れます。
macOSは少し特殊なので、「はじめてのC」の方でも作成できるように、手順を少していねいに紹介してしてみたいと思います。

macOS上でのはじめてのプログラムの作り方(Xcodeに頼らずに)
こんな感じのソースコードをテキストエディット(textEdit.app)に入力します。

#include <stdio.h>
int main () {
    printf ( "hello world.\n");
}

この内容をソースコードとして保存するためには、少し面倒ですが、次のおまじないが必要です。

保存する前に [フォーマット] => [標準テキストにする] を指定します(※1)。
ファイルの保存は [ファイル] => [保存...] メニューなのですが、以降のCLIコマンドで扱えるように次の指定をします。
保存先シートの [場所:] がデフォルトでは [書類] が選ばれていると思いますが、この一覧から自分のユーザ名を選び(またはShift+Cmd+H)、
その右側の下矢印 [v] を選んでフォルダ一覧を出します。
さらに [新規フォルダ] ボタンを押して、[名称未設定フォルダ] のところを tmp に書き換えて [作成] ボタンを押します(※2)。
保存先シートの [名前:] に a.c と入力し、[保存] ボタンを押します。
※1 プログラムファイルはテキスト形式にするのが必須なので、このようにします。)
※2 書類フォルダに a.c を保存することもできるのですが、次に実行するターミナルでのアクセスがmacOSの保護機能で制限されるので、このようにします。)

次にterminal.app(アイコン名はターミナル、アプリケーション配下のユーティリティフォルダの中にあります、あるいはCmd+Spaceでterminalまたはターミナルで検索してもよいです)を起動します。

ターミナルアプリの中で shell が起動されます。
まずはプログラミング環境一式を整えるために make コマンドを呼び出します。

make

すると、右の図の1つ目のダイアログが表示されますので、指示の通り [インストール] ボタンを押します
(このように必要なものがオンデマンドでインストールを促されます、面白いですよね。
 事前に Xcode をインストールしてある場合はこのダイアログは表示されません)。
次のコマンドでコンパイルします。

cd tmp
cc a.c

これでエラーメッセージがでなければ a.out という名前で、アプリの実行ファイルが作成されます。
ファイルの確認は次のコマンドでできます。

ls -l

作成したアプリは次のようにして実行できます。hello worldと表示されれば成功です。

./a.out

動きましたか?

Intel版アプリの作成方法
この手順でアプリを作成するとApple Silicon専用のアプリが作成されます。
file コマンドで確認すると、a.out: Mach-O 64-bit executable arm64 と表示されると思います。

file a.out

Apple Silicon Mac上で、Intel用のアプリを作成することもできます。
コンパイルする際に次の指定を行います。

cc -arch x86_64 a.c

先ほど同じように file コマンドで確認すると a.out: Mach-O 64-bit executable x86_64 と表示されます。

file a.out

作成したIntel用のアプリも同じ様に実行できます。

./a.out

ただし、今度は右の図の2つ目のダイアログが表示されます。
これは、macOS Big Surの初期状態ではRosetta 2がインストールされていないためなので、ここでも [インストール] ボタンを押します。
Rosetta 2のインストールが終わるとIntel版の a.out アプリが実行できるようになります。

Universalアプリの作成方法
さてここで私は、macOSが提供しているコンパイラアプリ自体はApple Silicon用なのか、Intel用なのかの疑問が湧きました。
次のコマンドで見てみると、Apple SiliconとIntelのUniversalアプリになっていることがわかります。

file /usr/bin/cc

自分でUniverasalバイナリを作成するには次のようにします。

cc a.c
mv a.out a_arm64.out
cc -arch x86_64 a.c
mv a.out a_x86.out
lipo -create -output a.out a_x86.out a_arm64.out

このコマンドで a.out が作成されます。
file コマンドでUniversalになっていることを確認してください。

file a.out

もちろん実行も問題なくできると思います。

./a.out

Intelモードのshellを起動する最も簡単な方法
先ほどやってみたように、Apple Silicon版でもIntel版でもアプリは区別なく必要に応じて自動的にRosetta 2で翻訳されて実行されるので、通常の利用目的ではとても都合が良くできています。
ところが、アプリ開発やパフォーマンス検証等の目的で明示的にIntel版環境を使用したい場面もあります。
その場合は、最初からターミナルのshellをIntel版にしておくのが便利です。
他の方のブログ等では、ターミナルアプリ自体の属性を [Rosettaを使用して開く] に明示的に変更する方法が紹介されているケースが多いです。
しかしながらこの方法はmacOSの [アプリケーション] => [ユーティリティ] に保存されているターミナルアプリを直に書き換えることになるため、あまりスマートではないと感じていました。

次のコマンドを使用すれば、ターミナルアプリの設定を書き換えることなくIntel版環境のshellを起動できることがわかりました。

arch -arch x86_64 zsh

実行中のshellがApple Silicon版なのかIntel版なのかは、次のいずれかのコマンドでの確認できます。

arch
uname -m
echo $CPUTYPE
machine

Intel版のshellからApple Silicon版のshellに戻るには次のコマンドを使います。

exit

逆に、Intel版のshellからApple Silicon版のshellを呼び出すのは次のコマンドです(引数に注意)。

arch -arch arm64e zsh

なお、Intel版環境のshellでは、Universalアプリはx86_64のコードが優先的に実行されます。
少しややこしいのですがIntel版環境においてもApple Silicon専用のアプリを意識することなくそのまま実行できるようになっています(macOS自体がApple Siliconなので)。

archコマンドでCPUタイプを指定した起動を行えるのはshellだけではありません。
例えばSafariをIntel版で動かしたい場合は次のようにします。

arch -arch x86_64 /Applications/Safari.app/Contents/MacOS/Safari

一発で起動できて、これ捗ります。

[English version of this post]

No comments:

Post a Comment