M1 MacでC++の競プロ用のGCC環境構築

# [0] はじめに
## (1) 本記事の目的
本記事では、パッケージ管理システムであるHomebrewを用いて、M1 Mac上でGCCの環境構築を行います。なお、私自身がこういったことに関して極めて初心者であり、従ってこの記事も私のような初心者を想定して作成しています。Qiita上でさまざまな情報が共有されているにかかわらず地味にハマって一筋縄では行かなかったので、少し丁寧な備忘録として記録します。

## (2) なぜGCCを導入するのか
競技プログラミングにおいてしばしば見かける「おまじない」であるところの、

```cpp:include.cpp
#include <bits/stdc++.h>
using namespace std;
```

をローカル環境で実現するためです。AtCoder社が提供する教材「[C++入門 AtCoder Programming Guide for beginners (APG4b)](https://atcoder.jp/contests/apg4b)」を利用した方は馴染みが深いのではないでしょうか。

:::note info
Macの場合は標準で（正確には、Xcode CommandLineToolsをインストールすることで）すぐにClangを使用できます。C言語やC++などを通常の用途（標準ライブラリを一つひとつ読み込む方法）で利用する場合はClangで十分なので、以下の作業は必要ありません。
:::

## (3) 環境の確認
- macOS Ventura
- Apple Silicon (M2)
- XCode CommandLineTools と Homebrew はインストール済

# [1] GCCのインストール
下記のコマンドにより、Homebrewを通してGCCをインストールできます。

```
% brew install gcc
```

`brew info gcc`というコマンドを実行して情報が表示されれば、正常にインストールされています。以下に例として私の環境での出力を示します。

```
% brew info gcc

==> gcc: stable 12.2.0 (bottled), HEAD
GNU compiler collection
https://gcc.gnu.org/
/opt/homebrew/Cellar/gcc/12.2.0 (1,470 files, 358.8MB) *
  Poured from bottle using the formulae.brew.sh API on [インストール日時]
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb
License: GPL-3.0-or-later with GCC-exception-3.1
==> Dependencies
Required: gmp ✔, isl ✔, libmpc ✔, mpfr ✔, zstd ✔
==> Options
--HEAD
	Install HEAD version
==> Analytics
install: 2,521 (30 days), 120,489 (90 days), 1,258,439 (365 days)
install-on-request: 1,466 (30 days), 60,013 (90 days), 611,420 (365 days)
build-error: 34 (30 days)
```

ここで、1行目に表示されている　`==> gcc: stable 12.2.0 （GCCのバージョン情報）`を確認しましょう。私の場合は`12`でした。


# [2] Clang環境からGCC環境への移行
## (1) 現状の確認
HomebrewでGCCをインストールするだけでは、GCCを簡単に利用することはできません。現時点でC++プログラムをコンパイルしようとすると、Clangが使用されます。`g++ -v`のコマンドでこの様子を確認することができます。

```zsh
% g++ -v

Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

`g++`とはC++のコンパイラを呼び出すコマンドです。現時点ではClang系が呼び出されていることがわかります。GCC系のコンパイラを呼び出すには、コマンドラインに`g++-{先ほど確認したGCCのバージョン}`を入力する必要があります。私の環境ではGCCのバージョンは`12`だったので、`g++-12`を呼び出した例を以下に示します

```zsh
% g++-12 -v

Using built-in specs.
COLLECT_GCC=g++-12
...
（中略）
...
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.0 (Homebrew GCC 12.2.0) 
```

出力に`Homebrew`とあるのが確認できました。

本節では、シンボリックリンクを利用してコマンドの呼び出し先を変更することで、`g++`コマンドによってGCC系のコンパイラが呼び出されるようにします。より具体的には、`g++`コマンドの呼び出し先を`g++-12`の呼び出し先に一致させます。

## (2) `/usr/local/bin/g++`にGCC系をリンクさせる。
まず、`which g++-{GCCバージョン}`のコマンドを使って、GCC系がどこにあるのか調べます。以下に例として私の場合を示します。

```zsh
% which g++-12

/opt/homebrew/bin/g++-12
```

`g++-12`というコマンドは、`/opt/homebrew/bin/g++-12`を呼び出していたようです。これを「GCC系の場所」として覚えておきます。続いて、ターミナルで以下のコマンドを実行します。

```zsh
% sudo ln -s {先ほど確認したGCCの場所} /usr/local/bin/g++
```

半角スペースの場所に注意してください。私の場合は、以下のようになります。多くの方が同じだと思います。

```zsh
% sudo ln -s /opt/homebrew/bin/g++-12 /usr/local/bin/g++

Password:
```

パスワードの入力を求められた場合には、管理者ユーザーのログインパスワード (多くの場合、Macを起動したときやスリープ状態から解除したときに入力するパスワードと同じです) を入力してください。

:::note info
パスワード入力中はターミナルの画面にキー入力が表示されません。本当に入力できているのか不安になりますが、自分を信じてEnterキーを押下してください。
:::

<details><summary>管理者コマンドの実行について</summary>

`/usr`の周辺に新しいディレクトリを作成したりシンボリックリンクを張ったりする場合には管理者権限が必要となる場合があります。

```zsh
% ln -s /opt/homebrew/bin/g++-12 /usr/local/bin/g++

ln: /usr/local/bin/g++: Permission denied
```

コマンドを実行する権限がない場合には、上記のように「Permission denied」というエラーが表示されます。これを回避するため、`sudo` コマンドを使用してスーパーユーザ権限でコマンドを実行しています。sudoは、「superuser do」の略らしいです。

</details>

ここでエラーが出て、`no such file or directory:`と表示される場合ことがあります（私のことです）。その際には`/usr/local/bin`にディレクトリを作成してから再び実行してください。

```zsh
% sudo ln -s /opt/homebrew/bin/g++-12 /usr/local/bin/g++

ln: usr/local/bin/g++: No such file or directory

% sudo mkdir /usr/local/bin
% sudo ln -s /opt/homebrew/bin/g++-12 /usr/local/bin/g++
```

特にエラー出力が出なければ成功です。

<details><summary>すでにファイルが存在する場合のエラー</summary>

`/usr/local/bin/g++`が何らかの理由ですでに存在する場合には、「File exists」というエラーが発生します。

```zsh
% sudo ln -s /opt/homebrew/bin/g++-12 /usr/local/bin/g++
Password:

ln: /usr/local/bin/g++: File exists
```

このような場合には、まず`readlink`コマンドなどで先客の`/usr/local/bin/g++`が何者なのか確認しましょう。

```zsh
% readlink /usr/local/bin/g++

{すでに存在している /usr/local/bin/g++　のリンク先が表示される}
```

問題がなければリンク先を変更しましょう。シンボリックリンクの上書きには `-f` オプションが利用できます。

```zsh
% sudo ln -sf /opt/homebrew/bin/g++-12 /usr/local/bin/g++
```

</details>


## (3) `g++`コマンドの呼び出し先を確認する
ターミナルで`which g++`のコマンドを実行します。出力は以下の2通りがあり得ます。

#### パターンA. `/usr/local/bin/g++`と表示される場合
```
% which g++

/usr/local/bin/g++
```
あなたは幸運です。(4)に進むことができます。

#### パターンB. それ以外
```
% which g++

/usr/bin/g++
```
私がこれでした。(3.5)の作業を終えてから(4)に進むことができます。

## (3.5) `g++`の呼び出し先を`usr/local/bin`に変更する。
コマンド検索パスを設定して、`/usr/local/bin/g++`を`g++`というコマンドで呼び出します。ホームディレクトリに存在する`.zshrc`という名前の隠しファイルに以下の一行を書き込んでから、`source ~/.zshrc`というコマンドを実行します。

<details>

`~/`とは、ホームディレクトリを指し、`アプリケーション`、`ダウンロード`、`ピクチャ`、`ミュージック`、`ムービー`、`書類`といったフォルダの親ディレクトリです。Finder上でキーボードの`Command` + `Shift` + `.`を押すことで`.zshrc`などの隠しファイルが見えるようになります。


</details>

```zsh:.zshrc
export "PATH=/usr/local/bin:$PATH"
```

```zsh:Terminal
% source ~/.zshrc
% which g++

/usr/local/bin/g++
```
`/usr/local/bin/g++`と表示されれば成功です。

<details><summary>ボヤき</summary>

コマンド検索パスを設定する環境変数は`PATH`です。`PATH`は`:`によって区切られており、区切られた中で左にあるディレクトリにあるコマンドから優先して呼び出されます。通っているPATHを確認するために以下のコマンドを入力して、出力を見ます。

```zsh
% echo $PATH
```

Macのデフォルトでは以下のような出力になります。Python等をインストールしていれば、さらに長くなる場合があります。

```zsh
% echo $PATH

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
```

上記のように、`/usr/local/bin`が含まれていて、かつ`/usr/bin`よりも優先順位が高い（左側に書かれてある）場合は、本来であれば`/usr/bin`の`g++`よりも`/usr/local/bin`の`g++`が優先して呼び出されるはずなのですが、私は何故かダメでした。なので、多少強引ですが、`/usr/local/bin`のPATHを改めて通すことで解決しました。

</details>

## (4) `g++`コマンドがGCC系とリンクしたことを確認する

(2)節でGCC系の場所と`/usr/local/bin/g++`をリンクさせてあるため、

```zsh
% which g++

/usr/local/bin/g++
```

が表示された時点で、`g++`コマンドをGCC系にリンクする作業が完了しています。
`g++` --[呼出]-->`/usr/local/bin/g++` --[Link]-->`/opt/homebrew/bin/g++-12`
という構図です。`g++ -v`を実行すると、今度は、

```zsh
% g++ -v

Using built-in specs.
COLLECT_GCC=g++-12
...
（中略）
...
Supported LTO compression algorithms: zlib zstd
gcc version 12.2.0 (Homebrew GCC 12.2.0) 
```

と表示されるはずです。これをもって環境構築は完了です。お疲れ様でした。
C++言語だけでなくC言語においてもGCC環境のコンパイルを行いたい場合には、(2)〜(3)の節の作業で`g++`の部分をそっくりそのまま`gcc`に置き換えて同様に行ってください。すなわち、

```zsh
% which gcc-12

/opt/homebrew/bin/gcc-12
```

でGCC系の場所を確認して、

```zsh
% ln -s /opt/homebrew/bin/gcc-12 /usr/local/bin/gcc
```

によって`/usr/local/bin/gcc`をGCC系にリンクさせ、

```zsh
% which gcc

/usr/local/bin/gcc
```

で`gcc`コマンドが
`gcc` --[呼出]-->`/usr/local/bin/gcc` --[Link]-->`/opt/homebrew/bin/gcc-12`
の構図になっていることを確認してください。

# [3] おまけ： やっぱりClang系に戻したい
Clang系とGCC系のどちらが良いかというのは人によります。「GCC系を準備したけど、やっぱりClang系に戻したい！」という場合には、以下のコマンドで `/usr/local/bin/g++`のリンクを解除することで元のClang系に戻すことができます。

```zsh
% sudo unlink /usr/local/bin/g++
```

Clang系に戻ったことが以下のように確認できます。

```zsh
% which g++

/usr/bin/g++


% g++ -v

Apple clang version 14.0.3 (clang-1403.0.22.14.1)
Target: arm64-apple-darwin22.4.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

HomebrewでインストールしたGCC系を削除しているわけではないので、再びGCC系に変えたくなった場合には改めて上の手順の「[[2] Clang環境からGCC環境への移行](#[2]Clang環境からGCC環境への移行)」以降を行えばOKです。

<br>

以上です。ありがとうございました！

# [4]参考記事

https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146

https://qiita.com/hayapo/items/21032ae726ed15b11563