Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

Apple M1プロセッサ搭載macbookでの開発環境構築

こんにちは、ForSchool事業部の冨山(@atomiyama1216)です。
好きなエディタはVimです。どんなにVSCodeが流行っても僕はVimを使い続けます。

2021年4月に業務用マシンを買い換えApple M1チップ搭載モデルに買い替えました。
その際環境構築でなかなかに躓いたのでそのことについて記録しておきます。 主にRails関連のgemをインストールするときとNode.jsをインストールするときに困ったのでそれらについて書きます。
今回の環境構築ではRosetta 2は使いません。

Disclaimer

以下の環境で構築したときの記事になります。

$ uname -a
Darwin PC21-010.local 20.3.0 Darwin Kernel Version 20.3.0: Thu Jan 21 00:06:51 PST 2021; root:xnu-7195.81.3~1/RELEASE_ARM64_T8101 arm64
$ system_profiler SPHardwareDataType
Hardware:

    Hardware Overview:

      Model Name: MacBook Pro
      Model Identifier: MacBookPro17,1
      Chip: Apple M1
      Total Number of Cores: 8 (4 performance and 4 efficiency)
      Memory: 16 GB
      System Firmware Version: 6723.81.1
      Serial Number (system): ...
      Hardware UUID: ...
      Provisioning UDID: ...
      Activation Lock Status: Disabled

TL;DR

  • 環境構築のためのbootstrapを書いたatomiyama/dotfiles
  • homebrewのインストール先はIntelプロセッサでは/usr/local、Apple Siliconでは/opt/homebrewになっている*1
  • ffiはv1.14.0移行がApple Silicon環境に対応している
  • Node.jsはv15.3.0以上をソースコードからコンパイルする*2

bootstrapを作成した

これまでもdotfilesをshellスクリプトで書いて複数環境で管理していたのですが今回Ansibleを用いる形に書き換えました。 一応これをローカルで実行して最低限の環境が揃ったので参考にしてください。
お星さままってます☆(ゝω・)v☆

github.com

mysql2のインストールでコケる

これは以前から頻出の問題でググるとたくさん記事が出てきます。
ただし進研ゼミでやったやつだ!と思ってこれまでのIntel環境同様の手順を脳死で踏むともれなくコケて下のようなエラーが出力されます。

$ bundle install
...
2 warnings generated.
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in
...

ld: library not found for -lxxxっていうのはGNUリンカのldコマンド実行時にxxxってライブラリが見つからんかったってエラーです。
なのでその場所を教えて上げればいいわけです。
これまではこのエラーが出たら脳死で以下のコマンドを実行すれば解決しました。

$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"

ただApple M1チップ環境では失敗します。 homebrewのドキュメント(こちら)に以下の記載があるようにインストール先が/opt/homebrewに変更されています。

This script installs Homebrew to its preferred prefix (/usr/local for macOS Intel, /opt/homebrew for Apple Silicon) so that you don’t need sudo when you brew install.

どのパスを指定すればよいかは下の方法で確認できます。

$ brew info openssl
...
For compilers to find openssl@1.1 you may need to set:
  export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include"
...

つまりここに書いてある通り/opt/homebrew/opt/openssl@1.1/libを指定してあげれば問題ないので

bundle config --local build.mysql2 "--with-ldflags=-L/opt/homebrew/opt/openssl@1.1/lib"

としてからbundle installなりgem install mysql2すれば成功するはずです。

rails cが起動しない

ここまでやって一通りbundle installは成功したのでbundle exec rails cしたら次は下のエラーがでました。

$ bundle exec rails c
Traceback (most recent call last):
...
/path/to/rails/project/vendor/bundle/ruby/2.7.0/gems/ffi-1.13.1/lib/ffi/types.rb:69:in `find_type': unable to resolve type 'size_t' (TypeError)

これはffiのFFI#find_typeで型定義が解決されないことに起因する問題でこちらのPRで解決され、v1.14.0でリリースされています。

github.com

Node.jsが動かない

つぎにNode.jsをいれようとしたら動かなくて困りました。(見かけ上はinstallできたが一部jestなどが動作しなかった) こちらのissueにて言及されているようにv15.3.0より前のリリースではdarwin-arm64環境はサポートされていません。*3
https://nodejs.org/dist/v15.14.0を見るとわかるのですがv15.x以前ではApple M1チップ環境darwin-arm64向けのビルド済みパッケージは配布されていません。
現在CURRENTリリースのv16.x以上であればdarwin-arm64向けのビルド済みパッケージが配布されています。 それ以前のバージョンを使用する場合はv15.3.0以降のバージョンを自身でコンパイルして使用するしかないと思います。
ただしこちらに関してもExperimentalサポートなので完全な動作を保障するものではないですが...

なので今回は以下のページを参考にnodebrewを使用してソースコードからコンパイルすることにしました。

tech.tabechoku.com

手順は以下の通りです

  1. nodebrewのインストールとセットアップ
$ brew install nodebrew
$ nodebrew setup_dirs
  1. nodebrewのスクリプトの編集 こちらでシステム環境を特定するサブルーチンsystem_infoを以下のように書き換えました。
$ vim $(which nodebrew)
sub system_info {
    my $arch;
    my ($sysname, $machine) = (POSIX::uname)[0, 4];

    if  ($machine =~ m/x86_64/) {
        $arch = 'x64';
    } elsif ($machine =~ m/arm64/) {
        $arch = 'arm64';
    } elsif ($machine =~ m/i\d86/) {
        $arch = 'x86';
    } elsif ($machine =~ m/armv6l/) {
        $arch = 'armv6l';
    } elsif ($machine =~ m/armv7l/) {
        $arch = 'armv7l';
    } elsif ($machine =~ m/aarch64/) {
        $arch = 'armv7l';
    } elsif ($sysname =~ m/sunos/i) {
        # SunOS $machine => 'i86pc'. but use 64bit kernel.
        # Solaris 11 not support 32bit kernel.
        # both 32bit and 64bit node-binary even work on 64bit kernel
        $arch = 'x64';
    } else {
        die "Error: $sysname $machine is not supported."
    }

    return (lc $sysname, $arch);
}
  1. nodeのコンパイル
$ nodebrew compile v15.14.0

この作業はだいぶ時間がかかりました。が、ここまでやれば一通り自分は環境が整いました。

まとめ

Apple M1チップ搭載マシンはまだ未対応のライブラリなどがあるため環境構築で躓くことは多くありましたが、バッテリーの持ちとか動作の速さは素晴らしいと思います。 前であればDockerを立ち上げた状態でZoom会議に参加するとマウスカーソルが遅延したりと使うに耐えない状態でした。 ただ業務マシンを買い替えてからはそういった問題が起きることなく快適に仕事ができてます。 ライブラリの問題などは積極的にフィードバックして一日でも早く人類がM1チップ環境に追いつく日がくるといいなと思ってます。