IntelからARMへ開発環境の移行と互換設定

M3 Macへの買い替えに伴って環境構築をしつつ、いつも同じようなことを調べているなと思い、今回はプロセッサ考慮の要素も増えたため、覚えている範囲で備忘録を残します。

## 前提

| Processor | OS (Ver) |
|:--:|:--:|
| Apple M3 Pro | macOS (Sonoma 14.1) |

※ 移行アシスタントは使わず、クリーンインストール状態からのセットアップを想定

## システム設定

### defaults コマンドによる設定

```sh
# すべてのファイルの拡張子を表示
defaults write NSGlobalDomain AppleShowAllExtensions -bool true

# 隠しファイルの表示/非表示を設定（表示）
defaults write com.apple.finder AppleShowAllFiles TRUE

# デスクトップに表示する項目：ハードディスク（表示）
defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true

# デスクトップに表示する項目：外部ディスク（表示）
defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true

# デスクトップに表示する項目：接続中のサーバ（表示）
defaults write com.apple.finder ShowMountedServersOnDesktop -bool true

killall Finder
```

### GUIからの設定

- [MacのメニューバーでVPN状況アイコンを使用する](https://support.apple.com/ja-jp/guide/mac-help/mchl7f06ab80/mac)
- [Macのアイコン表示で項目の配置とサイズを変更する](https://support.apple.com/ja-jp/guide/mac-help/mchlp2209/mac)

### macOS Sonoma から実装されたテキスト入力時にカーソル下に表示される青いバルーン（インジケータ）を消す

下記それぞれを実行後、OSを再起動。
参考：[macOS Sonomaのかな漢字変換で表示される吹き出しを消す方法](https://techracho.bpsinc.jp/hachi8833/2023_11_17/135935)

```sh
sudo mkdir -p /Library/Preferences/FeatureFlags/Domain
sudo /usr/libexec/PlistBuddy -c "Add 'redesigned_text_cursor:Enabled' bool false" /Library/Preferences/FeatureFlags/Domain/UIKit.plist
```

## ターミナル環境の分岐設定

[M1 MacでARMとIntelのターミナルを切り替えて使う (Homebrew 3以降の場合)](https://qiita.com/funatsufumiya/items/cec08f1ba3387edc2eed) を参考に、ネイティブ（ARM）とRosetta 2（x86_64互換）でターミナル環境を分離する。

目的としては、バージョン管理ツールで降ってくるアーキテクチャごとのビルドを棲み分けるためで、動作的には、参考記事の通りARM版ターミナルでは`/opt/homebrew/bin` 以下に、Intel版ターミナルでは`/usr/local/bin` 以下に、keg（Formulaのインストール先の実体）のシンボリックリンクが振り分けられる。

### ARM側環境にHomebrewでツールをインストール

```sh
brew_formulae=(
  "gpg"
  "git"
  "git-lfs"
  "gh"
  "mysql"
  "nvm"
  "docker-compose"
  "zellij"
  "rbenv"
  "pyenv"
  "fzf"
  "mkcert"
  "sheldon"
  "zsh-autosuggestions"
  "zsh-syntax-highlighting"
  "mas"
  "blackhole-2ch"
)

for it in "${brew_formulae[@]}"; do
  brew install "$it"
done
```

### 今回から移行・導入したツール

#### sheldon
https://github.com/rossmacarthur/sheldon

Oh-My-Zsh から移行。Zsh, Bashに対応のRust製のシェルプラグインマネージャー。
powerlevel10k など諸々セットアップがサクッとできて便利だった。

#### zellij（ゼリージュ）
https://github.com/zellij-org/zellij

tmux から移行。ターミナルマルチプレクサや、ターミナルワークスペース系ツールの一種。
機能面でtmuxとの互換性があり、移行による学習コストはそこまで高くない。

tmux は多機能かつ柔軟である一方、自分はセッションやペインの利用がメインで機能を持て余していたことや、tmux-resurrect などの管理がやや手間であった為、移行に至った。

現状で便利だと感じた特徴は下記の通り。

- デフォルトでキーバインドが表示されているなど、UIがユーザーフレンドリーである
- デフォルトでセッション保存・復元など最低限の機能が備わっているなど、ゼロコンフィグでも結構使える
- tmuxの主要機能である、Window, Session, Pane が、zellijでは、Tab, Session, Pane のように近い使い勝手となっている

コマンドのイメージ

```
# セッション開始
zellij
# セッション復元
zellij attach <session-name>
# セッション名変更
zellij action rename-session <new-name>
```

ちなみに名前はアラビア語の「幾何学模様のタイルスタイル」という意味のゼリージュが由来となっていそうだった。

### CaskでGUIアプリケーションをインストール

```sh
cask_applications=(
  "appcleaner" # アプリケーションを関連ファイルごとアンインストールできる -> https://freemacsoft.net/appcleaner/
  "keka" # ファイルアーカイバ -> https://www.keka.io/ja/
  "google-japanese-ime"
  "mos" # マウススクロールを滑らかにできる -> https://mos.caldis.me/
  "caffeine" # メニューバーからスリープ切り替え等を制御できる -> https://www.caffeine-app.net/
  "lunar" # 外部ディスプレイの設定をコントロールできる -> https://lunar.fyi/
  "karabiner-elements"
  "cmd-eikana"
  "iterm2"
  "warp" # Rust製のモダンターミナル -> https://www.warp.dev/
  "cleanmymac" # クリーナー、パフォーマンス最適化（シェアウェア） -> https://cleanmymac.macpaw.com/21
  "cleanshot" # キャプチャツール（シェアウェア） -> https://cleanshot.com/
  "transmit"
  "obsidian"
  "notion"
  "visual-studio-code"
  "postman"
  "sequel-ace"
  "docker"
  "graphiql"
  "graphql-playground"
  "virtualbox"
  "parallels"
  "1password"
  "google-chrome"
  "firefox"
  "slack"
  "asana"
  "discord"
  "google-drive"
  "vlc"
  "audacity"
  "drawio"
  "figma"
  "adobe-creative-cloud"
  "adobe-acrobat-reader"
  "clipy"
  "microsoft-teams"
  "background-music" # サウンドミキサー -> https://github.com/kyleneideck/BackgroundMusic
  "zoom"
)

for it in "${cask_applications[@]}"; do
  brew install --cask "$it"
done
```

## mas-cliでApp Storeのアプリケーションをインストール

```sh
mas_applications=(
  "539883307" # LINE
  "302584613" # Kindle
  "886882252" # Near Lock
  "497799835" # Xcode
)

for it in "${mas_applications[@]}"; do
  mas install "$it"
done
```

## 各種バージョン管理ツールの初期設定

### 前提

各言語のバージョンごとのアーキテクチャが混ざってしまうと困るケースとして、たとえばNode.jsが、アーキテクチャに対応していてもプロジェクトの環境次第では、ネイティブモジュールなどの依存が非対応であったりするケースが存在する。そうした場合に、環境変数の調整や各種引数での対応が可能であることも多いが、バージョン管理自体を棲み分けておくと対応がしやすいと感じたため、今回はこのようにした。

### Node.js

nvmを使う場合の例

#### Rosetta 2のターミナルで実行

```sh
mkdir ~/.nvm_x64 && export NVM_DIR="$HOME/.nvm_x64"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
```

#### ネイティブのターミナルで実行

```sh
mkdir ~/.nvm_arm64 && export NVM_DIR="$HOME/.nvm_arm64"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
```

#### .zshrcに追記

```sh
# 実行アーキテクチャごとにディレクトリの読み先を変更
if [ "$(uname -m)" = "arm64" ]; then
  # arm64
  export NVM_DIR="$HOME/.nvm_arm64"
else
  # x86_64
  export NVM_DIR="$HOME/.nvm_x64"
fi

[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

# .nvmrc を検出して自動でバージョンを切り替える
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
```

#### 各アーキテクチャ環境で、任意の同バージョンをインストールし、棲み分けができているか確認

```sh
node -p process.arch
```

### php

ARM環境でのphpenv環境構築にやや苦戦したため、あまり時間をかけず下記ツールで解決とした。
phpは主にDocker上で動かすもののホストにも入れておきたい程度だった為。

[phpenv-installer](https://github.com/phpenv/phpenv-installer)

### python

pythonは先ほどの [M1 MacでARMとIntelのターミナルを切り替えて使う (Homebrew 3以降の場合)](https://qiita.com/funatsufumiya/items/cec08f1ba3387edc2eed#pyenv%E3%81%AE%E5%A0%B4%E5%90%88) の「pyenvの場合」を参考に分岐の設定を行った

## shellやコマンド周りの設定

### 各コマンドのalias等

```sh
# pnpm
alias pn='pnpm'

# zellij
alias zlj='zellij'
```

### git push時にリモートブランチ名を省略

```sh
git config --global push.default current
```

### gpgの設定でcommitを署名付きとする

GitHubの[新しい GPG キーを生成する](https://docs.github.com/ja/authentication/managing-commit-signature-verification/generating-a-new-gpg-key)を参考に設定を行う

## アプリケーション設定

### Safari

```sh
# Safariの「開発」メニューの表示/非表示を切り替え（表示）
defaults write com.apple.Safari IncludeDevelopMenu -bool true
```

コマンドで切り替わらない場合は、[MacのSafariで「開発」メニューのデベロッパツールを使用する](https://support.apple.com/ja-jp/guide/safari/sfri20948/mac) を参考にマニュアルで設定

### Transmit

- 接続情報の再設定

### Xcode

- ライセンス同意からシミュレータのインストールまで

### その他

- セキュリティソフトのディスクアクセスや必要に応じてFirewall設定
- 画面収録の許可（zoomやmeet、キャプチャツール周り）

## 参考記事

- [高速で設定しやすいZsh/BashプラグインマネージャーSheldonの紹介](https://zenn.dev/ganta/articles/e1e0746136ce67)
- [SSH接続を10倍速くするたった3行の設定](https://qiita.com/suin/items/1708dc78fc412297f885)