初書:2021/11/2
mac : 11.6
node: v16.6.1
electron : v15.1.2
前置き
electron-builderを使ってmac向けにパッケージ化をした時に起こったメモ。
パッケージングする
electronで作成したプロジェクトをパッケージングするとき、大抵はelectron-builderを使用すると思う。
今回も調べたらelectron-builderが出てきたので、これを参考にパッケージングしてみる。
% npx electron-builder --mac --x64
実際にはpackage.json
か専用ファイルを作って設定が必要だが、本趣旨とは外れるので省略。
これで無事にパッケージングでき、DMGファイルを公開することで他のmacユーザーも使用できる。
起きた問題
こちらintelのCPU使い。パッケージングしたファイルを使っても特に問題はなかった。
問題は配布先。相手はM1のCPUを使用していた。
M1のmacでも特に問題なく動くのだが、1つだけ動かないものがあった。
今回、GUI版のEmacsを開く動作が必要だったため、child_processを使用してEmacsを起動していた。
これが、M1のmacだと動かず、Emacsがクラッシュしてしまった。
クラッシュレポートを見せてもらうとだいたいこんな感じ。
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
Thread 1:: com.apple.rosetta.exceptionserver
Thread 2:
Thread 3:
Thread 4:
Thread 5:
Thread 6:
Thread 7:: com.apple.NSEventThread
Thread 0 crashed with X86 Thread State (64-bit):
なんかrosettaが悪さしているような気がしている。
ということで試行錯誤した記録を書いていく。
現在の呼び出し方法
最初書いていたコード。
exec
はzshとかbashとかではなくsh
1を使っているので、パスが通っているか分からないので絶対パス指定。
exec(`/Applications/Emacs.app/Contents/MacOS/Emacs "${ExecPathEscape(dirPath)}"`, callback);
intelでは正常にEmacsが開く。
M1ではここが呼び出されると、一瞬だけ開いたのち、落ち、callbackでerror
が返される。
原因特定をする
ここは試行錯誤のメモ。結論はその下。
とりあえず呼び出し方を変えてどうにかならないか考えてみる。
-
exec
ではどうにもならないかもしれないと思い、大元であるspawn
を叩いてみる。
const exe = spawn('/Applications/Emacs.app/Contents/MacOS/Emacs', [ExecPathEscape(dirPath)], {
shell: true,
});
exe.stdout.on('data', stdoutCallback);
exe.stderr.on('data', stderrCallback);
変化なし。
- この時は、自分のアプリケーションがM1で適切に動いていて、Emacsが何故かX86_64で動いていると思っていた。
ので、シェルコマンドをX86_64で動かせば動くのでは?と思い以下のコードに変更
exec('arch -arch x86_64 /bin/bash -c "/Applications/Emacs.app/Contents/MacOS/Emacs ' + ExecPathEscape(`"${ExecPathEscape(dirPath)}"`) + '"', callback);
-c
以降が文字列になるため、ファイルパスを2重エスケープするという複雑な構造に。
もちろん変化はなかった。
-
electronのshellを叩いてみる。
もしかしてshell.openExternal
で開けるのでは?と思い書いてみたが動くはずもなく。 -
Emacsをrosettaで起動にチェックをつける
Emacsを右クリックし、情報を開く
から、rosettaを使用して開く
にチェックを入れて起動してみた。
まあこれでもないですよね。
他にも2,3個ためしたがどれも上手くいかなかった。とある事情でログを消してしまい何試したか覚えていないが。
解決方法の発見
M1ユーザーの方にも色々と試してもらっていて、それぞれ1つずつ解決策が見つかった。
1つは、叩いていた/Applications/Emacs.app/Contents/MacOS/Emacs
ファイルは、中はただのRubyなので、
読んでみると、どうやら実行環境に応じて開くファイルを変えているらしい。
これで、何故かX86_64が選択されてしまっているので、直接Arm64のEmacsを起動させるという方法。
コマンドだと/Applications/Emacs.app/Contents/MacOS/Emacs-arm64-11_2
とかになるだろうか。
これで正常起動が出来た。
もう一つがタイトルにもあるように、自分のアプリケーションがintel専用で配布していることに気がつき、
universalに変更してパッケージングするというもの。
この場合は/Applications/Emacs.app/Contents/MacOS/Emacs
を叩いても正常に起動できた。
ということで、上記二つから考えると、
- M1のMacでEmacsの
Emacs-x86_64-10_14
が何故か起動できない。 - M1のMacでintelのアプリケーションを起動すると、シェルはX86_64で呼び出される。
- これにより、EmacsがチップをX86_64だと判断し、Emacs-x86_64-10_14を起動しようと試みた。
という原因で開けないという事態が起きた。
結論
M1のMacに対応できるなら対応したものを配布した方がこんなことにならないですよね。
ということで最低でもuniversal
、容量とか気にするならM1とintelそれぞれに対応したパッケージを作成しよう。
という忘備録でした。
% npx electron-builder --mac --universal
-
これシェルと読むのだろうか、意外に詳しくないこの辺り。 ↩