競プロを始めようと思って
手持ちのMacbookに環境構築を進めていました。
C++のコンパイラ周りで困ったことがあったのでメモ。
環境
- Macbook Pro (13-inch, M1, 2020)
- macOS Monterey 12.2
- gcc 11.2.0 (Homebrew GCC 11.2.0_3)
- Apple clang version 12.0.5 (clang-1205.0.22.9)
tl;dr
- ClangからGCCに切り替えた
-
#include<bits/stdc++.h>
を含むcppファイルをコンパイルしたらerror: assert.h: No such file or directory
の怒られが発生 -
export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)
← 結論
長くなったので結論までの流れをコンパクトにまとめました(えらい)
ちなみにですがClangでも普段なんら困ることはないみたいなので,面倒なのが嫌な人はここまでにしましょう。
GCCのインストールとClangからの切り替え
別にこだわりはなかったんですが,競プロで等でよく見かけるヘッダ(bits/stdc++.h
)を提供しているのがGCCだったりしたのでMac標準(?)のClangではなくてGCCを利用することにしました。
インストールはbrew install gcc
。(Intel MacとM1 MacではHomebrewを使ったパッケージのインストール先が異なるので注意)
次に,まだこの段階ではClangが呼び出されてしまうgcc
とg++
それぞれのコマンドでGCCが呼び出されるように切り替えます。
brew
コマンドでインストールされたGCCは/opt/homebrew/Cellar/
に入っているのですが,インストールが済んだ時点で自動的に/opt/homebrew/bin/
からシンボリックリンクが張られているのでls -l .. | grep ..
コマンドで確認。
$ ls -l /opt/homebrew/bin | grep gcc
... gcc-11 -> ../Cellar/gcc/11.2.0_3/bin/gcc-11
$ ls -l /opt/homebrew/bin | grep g++
... g++-11 -> ../Cellar/gcc/11.2.0_3/bin/g++-11
上のgcc-11/g++-11
がそうです(実際にはgcc/g++を含む他の結果も表示されます)。
(↑ 11という数字はインストールされた時点でのバージョンによるので適宜読み替えてください)
つまり,この時点で (opt/homebrew/bin
にパスが通っていれば) gcc-11
とg++-11
のコマンドでGCCを呼び出せるわけです。
毎度バージョンを入力するのも面倒なので,ln -fs
コマンドでバージョンを省略した名前のシンボリックリンクを張っておきます(-fs
はシンボリックリンクを作成して,同名のリンクファイルが既にある場合に削除してねというお願いをするオプションです)。
$ ln -fs /opt/homebrew/bin/gcc-11 /opt/homebrew/bin/gcc
$ ln -fs /opt/homebrew/bin/g++-11 /opt/homebrew/bin/g++
ここでwhich
コマンドを使って各コマンドからどのファイルが呼び出されているか確認します。
$ which gcc
/opt/homebrew/bin/gcc
$ which g++
/opt/homebrew/bin/g++
このように先ほど指定したシンボリックリンクのファイルが呼び出されていればOKです。
まだ/usr/bin/gcc
,/usr/bin/g++
が表示されている場合,
-
/opt/homebrew/bin/
よりも/usr/bin/
の方がパスの優先度が高い - そもそも
opt/homebrew/bin/
にパスが通っていない
コマンド実行時OSのシェルは,パスが通っている(登録されている)ディレクトリを優先度の高い順に探します。
以下のコマンドで/opt/homebrew/bin/
にパスを通します。
(~/.zshrcがない場合はtouch ~/.zshrc
をしてから), echo "export PATH=/opt/homebrew/bin:$PATH" >> ~/.zshrc
これを実行して,source ~/.zshrc
で設定を再度読み込めばOKです。
使ってみる
意気揚々と#include<bits/stdc++.h>
したcppファイルをコンパイルしたら,以下の怒られが発生してしまいました。
$ g++ main.cpp
In file included from /opt/homebrew/Cellar/gcc/11.2.0_3/include/c++/11/aarch64-apple-darwin21/bits/stdc++.h:33,
from a.cpp:2:
/opt/homebrew/Cellar/gcc/11.2.0_3/include/c++/11/cassert:44:10: fatal error: assert.h: No such file or directory
44 | #include <assert.h>
| ^~~~~~~~~~
compilation terminated.
この問題,色々調べて勉強になったのですが,こちらの記事が詳しくて分かりやすかったので参考にさせていただきました。感謝。
Xcodeのアップデートに伴ってヘッダーファイル等の参照すべきフォルダが変わっているということのようです。
The Command Line Tools package installs the macOS system headers inside the macOS SDK.
The command line tools will search the SDK for system headers by default. However, some software may fail to build correctly against the SDK and require macOS headers to be installed in the base system under /usr/include. If you are the maintainer of such software, we encourage you to update your project to work with the SDK or file a bug report for issues that are preventing you from doing so.
macOS SDKにシステムヘッダとか入ってるからそっちを参照するようにしてくれと。
元々は/usr/include
というフォルダがあったけど無くなってしまったらしいです。
で,これは環境変数SDKROOT
を設定することで解決することができるようです。
$ g++ main.cpp
In file included from /opt/homebrew/Cellar/gcc/11.2.0_3/include/c++/11/aarch64-apple-darwin21/bits/stdc++.h:33,
from a.cpp:2:
/opt/homebrew/Cellar/gcc/11.2.0_3/include/c++/11/cassert:44:10: fatal error: assert.h: No such file or directory
44 | #include <assert.h>
| ^~~~~~~~~~
compilation terminated.
$ export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
$ g++ main.cpp
$ ls
a.out main.cpp
SDKROOT
の設定の後はヘッダファイルの参照エラーが解消し,無事コンパイルできました!
こちらの変更もecho "export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" >> ~/.zshrc
しておきましょう。
感想
~~Clangで良かったんじゃねえか...~~いや非常に勉強になって楽しかったです。
(SDKROOTの環境変数設定したのちゃんと覚えておかないと後々困ることがありそうな気がする)
*Qiitaに類するサービスを含め記事の投稿が初めてなので間違いや分かりづらい点が多々あるかと思いますのでご指摘いただけるととても嬉しいです。