🍎

M1 Mac (Big Sur 11.2) でNode.js, Python3 開発環境を用意する

2021/02/02に公開

これはなに

やっとApple SiliconなMacBookが届いたんですが、環境構築の為にいろんな記事を繋ぎ合わせて解釈する必要があったので、備忘録としてまとめます。

https://mykii.blog/m1-mac-setup/

環境

  • MacBook Air Late 2020
  • Apple M1 (8core GPU)
  • RAM 16GB
  • macOS Big Sur 11.2 (20D64)

揃えたいもの

今やってる案件がVue.jsとLambda/Pythonなので、取り急ぎ最低限欲しいのはこんな感じ。AWS関連は別途。

  • VSCode
  • XCode
  • Homebrew
    • anyenv
      • nodenv
      • pyenv

1. VSCodeを入れる

ARM64版は記事作成時点でまだInsider扱いのため、以下からダウンロードします。
https://code.visualstudio.com/insiders/
アイコンが緑色なのが目印。

Node.jsやPythonの為のExtensionsは適宜インストール。

2. XCodeを入れる

大抵の説明では一行で済まされていますが、怒られました。

$ xcode-select --install
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

実はすでに入ってたんですね。
ただEULAに同意していないので、同意しておきます。

$ xcode-select -license

3. Homebrewを入れる

以下参考に。
https://docs.brew.sh/Installation

macOS ARMでは/opt以下に入れることが推奨されています。

$ cd /opt
$ sudo mkdir homebrew
$ sudo chown $USER:admin homebrew
$ curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

んで、/opt以下なので自分でPATHを通す必要があります。
macOS Big Surは、デフォルトのシェルがzshの為、以下のようにします。

$ echo 'export PATH=/opt/homebrew/bin:$PATH' >> ~/.zshrc
$ exec $SHELL -l

PATHが通ったら以下でHomebrewの動作を確認。

$ brew doctor
Your system is ready to brew.

なにかエラーがあったら追いかけて直します。

4. anyenvを入れる

Homebrewから入れてみます。

$ brew install anyenv
$ echo 'eval "$(anyenv init -)"' >> ~/.zshrc
$ exec $SHELL -l

初期化処理。

$ anyenv install --init
Manifest directory doesn't exist: /Users/[your_account]/.config/anyenv/anyenv-install
Do you want to checkout ? [y/N]: y
Cloning https://github.com/anyenv/anyenv-install.git master to /Users/[your_account]/.config/anyenv/anyenv-install...
Cloning into '/Users/[your_account]/.config/anyenv/anyenv-install'...
remote: Enumerating objects: 44, done.
remote: Counting objects: 100% (44/44), done.
remote: Compressing objects: 100% (39/39), done.
remote: Total 44 (delta 1), reused 43 (delta 1), pack-reused 0
Unpacking objects: 100% (44/44), done.

どんな*envが扱えるのかの確認。

$ anyenv install -l
  Renv
  crenv
  denv
  erlenv
  exenv
  goenv
  hsenv
  jenv
  jlenv
  luaenv
  nodenv
  phpenv
  plenv
  pyenv
  rbenv
  sbtenv
  scalaenv
  swiftenv
  tfenv

アップデートプラグインを入れる。

$ mkdir -p $(anyenv root)/plugins
$ git clone https://github.com/znz/anyenv-update.git $(anyenv root)/plugins/anyenv-update
Cloning into '/Users/[your_acount]/.anyenv/plugins/anyenv-update'...
remote: Enumerating objects: 87, done.
remote: Total 87 (delta 0), reused 0 (delta 0), pack-reused 87
Unpacking objects: 100% (87/87), done.

5. nodenv / Node.js

anyenvからnodenvを入れます。

$ anyenv install nodenv

.
.
.
Cloning https://github.com/nodenv/nodenv.git master to nodenv...
Cloning into 'nodenv'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 4021 (delta 5), reused 4 (delta 1), pack-reused 4003
Receiving objects: 100% (4021/4021), 732.75 KiB | 979.00 KiB/s, done.
Resolving deltas: 100% (2636/2636), done.
~/.anyenv/plugins
~/.anyenv/envs/nodenv/plugins ~/.anyenv/plugins
Cloning https://github.com/nodenv/node-build.git master to node-build...
Cloning into 'node-build'...
remote: Enumerating objects: 231, done.
remote: Counting objects: 100% (231/231), done.
remote: Compressing objects: 100% (132/132), done.
remote: Total 20170 (delta 84), reused 172 (delta 79), pack-reused 19939
Receiving objects: 100% (20170/20170), 3.59 MiB | 3.09 MiB/s, done.
Resolving deltas: 100% (12839/12839), done.
~/.anyenv/plugins
~/.anyenv/envs/nodenv/plugins ~/.anyenv/plugins
Cloning https://github.com/nodenv/nodenv-vars.git master to nodenv-vars...
Cloning into 'nodenv-vars'...
remote: Enumerating objects: 211, done.
remote: Total 211 (delta 0), reused 0 (delta 0), pack-reused 211
Receiving objects: 100% (211/211), 31.82 KiB | 740.00 KiB/s, done.
Resolving deltas: 100% (76/76), done.
~/.anyenv/plugins

Install nodenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.
$ 
$ exec $SHELL -l

バージョン確認。

$ nodenv -v
nodenv 1.4.0+3.631d0b6

インストール可能なnodeを列挙してみる。

$ nodenv install -l
.
.
.

今回は14.15.4を入れてみます。

$ nodenv install 14.15.4
Downloading node-v14.15.4.tar.gz...
-> https://nodejs.org/dist/v14.15.4/node-v14.15.4.tar.gz
Installing node-v14.15.4...
Installed node-v14.15.4 to /Users/mia/.anyenv/envs/nodenv/versions/14.15.4

新しいバージョンを入れたらrehashしておく。

$ nodenv rehash

globalにつかうnodeを指定しておく。

$ nodenv global 14.15.4

特定のプロジェクトディレクトリ以下でのlocalでの指定方法は以下。

$ nodenv local 14.15.4

確認。

$ node -v
v14.15.4
$ which node
/Users/[your_acount]/.anyenv/envs/nodenv/shims/node
$ which npm 
/Users/[your_acount]/.anyenv/envs/nodenv/shims/npm

6. pyenv / Python3

最初にpyenvを入れます。nodenvと手順は大体一緒。

$ anyenv install pyenv

.
.
.
Cloning https://github.com/pyenv/pyenv.git master to pyenv...
Cloning into 'pyenv'...
remote: Enumerating objects: 74, done.
remote: Counting objects: 100% (74/74), done.
remote: Compressing objects: 100% (65/65), done.
remote: Total 18684 (delta 32), reused 14 (delta 4), pack-reused 18610
Receiving objects: 100% (18684/18684), 3.78 MiB | 3.07 MiB/s, done.
Resolving deltas: 100% (12670/12670), done.
~/.anyenv/envs/nodenv/plugins

Install pyenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.
$ 
$ exec $SHELL -l

バージョン確認。

$ pyenv -v
pyenv 1.2.22-47-g4c302a02

インストール可能なpythonを列挙してみる。

$ pyenv install -l
.
.
.

今回は3.8.7を入れてみます。

$ pyenv install 3.8.7
Downloading openssl-1.1.0j.tar.gz...
-> https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz
Installing openssl-1.1.0j...

BUILD FAILED (OS X 11.2 using python-build 1.2.22-47-g4c302a02)

Inspect or clean up the working tree at /var/folders/XXXXXXXXXXXX
Results logged to /var/folders/XXXXXXXXXXXX

Last 10 log lines:
      _conn_write in libcrypto.a(bss_conn.o)
      _conn_puts in libcrypto.a(bss_conn.o)
      _dgram_write in libcrypto.a(bss_dgram.o)
      _fd_write in libcrypto.a(bss_fd.o)
      _sock_write in libcrypto.a(bss_sock.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [link_shlib.darwin] Error 1
make[1]: *** [libcrypto.dylib] Error 2
make: *** [all] Error 2

と思ったら失敗しました。そっか、M1対応は3.9.1からってどこかで見たぞ。
試してみると...

$ pyenv install 3.9.1                                     
Downloading openssl-1.1.0j.tar.gz...
-> https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz
Installing openssl-1.1.0j...

BUILD FAILED (OS X 11.2 using python-build 1.2.22-47-g4c302a02)

Inspect or clean up the working tree at /var/folders/XXXXXXXXXXXX
Results logged to /var/folders/XXXXXXXXXXXX

Last 10 log lines:
      _conn_write in libcrypto.a(bss_conn.o)
      _conn_puts in libcrypto.a(bss_conn.o)
      _dgram_write in libcrypto.a(bss_dgram.o)
      _fd_write in libcrypto.a(bss_fd.o)
      _sock_write in libcrypto.a(bss_sock.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [link_shlib.darwin] Error 1
make[1]: *** [libcrypto.dylib] Error 2
make: *** [all] Error 2

...エラー内容同じですね。3.9.1からM1対応とのことなんですが、調べてみるとHomebrewから直接インストールだったりソース落としてきて自前でビルドしたりしてる事例ばかり。anyenvからのpyenv経由で使いたかったのでもう少し頑張ってみたら、Miniforgeならいけるんではないか説を発見しました。

$ pyenv install miniforge3-4.9.2
Downloading Miniforge3-4.9.2-5-MacOSX-arm64.sh...
-> https://github.com/conda-forge/miniforge/releases/download/4.9.2-5/Miniforge3-4.9.2-5-MacOSX-arm64.sh
Installing Miniforge3-4.9.2-5-MacOSX-arm64...
Collecting package metadata (current_repodata.json): done
Solving environment: done

## Package Plan ##

  environment location: /Users/mia/.anyenv/envs/pyenv/versions/miniforge3-4.9.2

  added / updated specs:
    - pip


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    certifi-2020.12.5          |   py39h2804cbe_1         143 KB  conda-forge
    pip-21.0.1                 |     pyhd8ed1ab_0         1.1 MB  conda-forge
    ------------------------------------------------------------
                                           Total:         1.2 MB

The following packages will be UPDATED:

  certifi                          2020.12.5-py39h2804cbe_0 --> 2020.12.5-py39h2804cbe_1
  pip                                   20.3.3-pyhd8ed1ab_0 --> 21.0.1-pyhd8ed1ab_0



Downloading and Extracting Packages
pip-21.0.1           | 1.1 MB    | ##################################################### | 100% 
certifi-2020.12.5    | 143 KB    | ##################################################### | 100% 
Preparing transaction: done
Verifying transaction: done
Executing transaction: done
Installed Miniforge3-4.9.2-5-MacOSX-arm64 to /Users/mia/.anyenv/envs/pyenv/versions/miniforge3-4.9.2

ビルド通りましたね!
いそいそとシェルを初期化し、

$ exec $SHELL -l

満を辞してmacOSのPythonからpyenvのpythonに切り替え。

$ python --version
Python 2.7.16
$ pyenv global miniforge3-4.9.2
$ exec $SHELL -l
$ python --version
Python 3.9.1
$ which python 
/Users/[your_acount]/.anyenv/envs/pyenv/shims/python
$ which pip
/Users/[your_acount]/.anyenv/envs/pyenv/shims/pip

これで3.9.1が動くようになりました。
本当はまだ3.8系を使っていたいんですが、一旦は仕方ないですね。

Miniforgeはconda環境の為、condaコマンドでenvを作ってactivateが必要だよー、という話もあるんですが、今回はMiniforgeの親であるpyenvで切り替えをさせるので、無視します。conda initとかactivateもしません。既存のプロジェクトとの兼ね合いで、condaでパッケージ管理したくないのです。
pipで問題のあるパッケージについては別途検証。

おまけ(condaでパッケージ管理する場合)

以下実用では試してません。

pyenvで環境を選択するパターン

anyenv > pyenv > miniforge3-[version]/envs/[env_name]

環境はの選択はpyenv、パッケージの管理はminiforge3-[version]、pyenvに選ばれた実際の環境はminiforge3-[version]/envs/[env_name]みたいなややこしいやつ。
使い勝手がcondaじゃない感じになるかも。

作業的には多分こういうことなのではないでしょうか...

$ pyenv global miniforge3-4.9.2
$ exec $SHELL -l

$ conda create -n python39 python=3.9

$ conda install -n python39 numpy
$ conda install -n python39 matplotlib
$ conda install -n python39 pandas

$ pyenv global miniforge3-4.9.2/envs/python39
$ exec $SHELL -l

condaで環境を選択するパターン

anyenv > pyenv > miniforge3-[version] > [env_name]

別のパターンとして、pyenvではminiforge3-[version]を選んでおき、miniforgeのcondaでenvをactivateすることもできます。あくまでconda環境が欲しい場合はこっちの方が順当かも。
普通にconda activateするとbash以外は知らん、みたいな感じで失敗するので、conda initが必要です。
~/.zshrcにinit結果が書き込まれるので、後で環境を戻したい場合は注意。

$ pyenv global miniforge3-4.9.2
$ exec $SHELL -l

$ conda create -n python39 python=3.9

$ conda install -n python39 numpy
$ conda install -n python39 matplotlib
$ conda install -n python39 pandas

$ conda init zsh
$ exec $SHELL -l
(base) $ conda activate python39
(base) $ exec $SHELL -l

(python39) $ 

まとめ

ここまでくれば、M1(ARM64)だから、という問題は各パッケージの互換性くらいかと思います。
Vue.jsとかはnpmから適宜インストールで行けると思います。

参考資料

https://qiita.com/rinpa/items/81766cd6a7b23dea9f3c
https://qiita.com/shuissnow/items/94621e8bf9c939ba8986
https://qiita.com/YoshinoriKanno/items/1fd4f8c89e4c92bf14d6
https://qiita.com/soarflat/items/d5015bec37f8a8254380
https://zenn.dev/hinastory/articles/71983c4ac8aa2d
https://qiita.com/shibukawa/items/797b7cbb7e530842e6f7
https://qiita.com/ttokdev/items/be675ac7bee0109db986
https://qiita.com/1000ch/items/41ea7caffe8c42c5211c
https://qiita.com/crankcube/items/15f06b32ec56736fc43a
https://qiita.com/hjmr/items/b81de997d4c2b64ef140
https://teratail.com/questions/313363
https://qiita.com/methane/items/5afdabd513a18049c34f
https://medium.com/@chezou/pythonの環境構築を自分なりに整理してみる-dc8d8f2fe989

Discussion