MacでのGCCのコンパイルエラーの対処法について

#[1]前書き

この記事は[MacでGCCを"正しく"環境構築しよう！](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146)の続編なので、**先に読んでからこちらの記事を読む**ことをお勧めします。手順通りに進めていただければGCCを使えるはずです[^7]。

この記事では、HomebrewでインストールしたGCCでコンパイルしようとすると、**`fatal error: '〇〇.h' file not found`とエラーが出る場合の対応策**について紹介します。

また、GCC以外の場面で`fatal error: '〇〇.h' file not found`のエラーが出た場合も紹介した方法を応用することで問題を解決することができるような解説を以下では心がけています。



#[2]前提

まず、GCCが使える状態になっていることを以下のコマンドで確認します。バージョンの違いはありますが、一番下の行が`Homebrew GCC`になっていればHomebrewのGCCが使える状態になっています。異なる場合は[MacでGCCを"正しく"環境構築しよう！](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146)を先に読んでください。

```zsh
% g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/10.2.0/libexec/gcc/x86_64-apple-darwin20/10.2.0/lto-wrapper
Target: x86_64-apple-darwin20
Configured with: ../configure --build=x86_64-apple-darwin20 --prefix=/usr/local/Cellar/gcc/10.2.0 --libdir=/usr/local/Cellar/gcc/10.2.0/lib/gcc/10 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-10 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --with-pkgversion='Homebrew GCC 10.2.0' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk SED=/usr/bin/sed
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (Homebrew GCC 10.2.0) 
```

#[3]サーチパスの確認と`〇〇.h`の検索

`file not found`への対処を見れば基本的には解決するので、この章を読むのは必須ではありません。但し、**解決しない場合に自力で解決するのにこの章は役立つと期待しています**。

##(1)原因の確認

`fatal error: '〇〇.h' file not found`は`〇〇.h`(ヘッダファイル)が見つからないことが原因です。まずは**ヘッダファイルのインクルード元を見つけるためにサーチパスを確認しましょう**。

サーチパスは適当なC++のファイル(`hoge.cc`)を用意して`-v`オプション付きでコンパイル(`% g++ -v hoge.cc`[^1])した時の出力の中にあります[^2]。また、自分の出力結果の該当部分のみを参考に載せておきます[^5]。

つまり、以下のサーチしているディレクトリに`〇〇.h`がない場合に`fatal error: '〇〇.h' file not found`というエラーが発生します。

```zsh
% g++ -v hoge.cc
#その他の出力
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/usr/local/include"
ignoring nonexistent directory "/usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/../../../../../../x86_64-apple-darwin20/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/../../../../../../include/c++/10.2.0
 /usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/../../../../../../include/c++/10.2.0/x86_64-apple-darwin20
 /usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/../../../../../../include/c++/10.2.0/backward
 /usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/include
 /usr/local/Cellar/gcc/10.2.0/lib/gcc/10/gcc/x86_64-apple-darwin20/10.2.0/include-fixed
 /Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/usr/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/System/Library/Frameworks
End of search list.
#その他の出力
```

ちなみに、Macに元々あるclang++のサーチパスは以下のようになりました。

```zsh
% clang++ -v hoge.cc
#その他の出力
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1
 /Library/Developer/CommandLineTools/usr/lib/clang/12.0.0/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include
 /Library/Developer/CommandLineTools/usr/include
 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
#その他の出力
```


##(2)サーチパスの詳細

サーチパスはシステム側で決められています[^3]。自分の環境を含む複数の環境で確かめた限りでは、**HomebrewでインストールしたGCC**\(`/usr/local/Cellar/gcc/10.2.0/`\)の配下と**CommandLineToolsの一部としてインストールされるMacOSXの[SDK](https://ja.wikipedia.org/wiki/%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%82%AD%E3%83%83%E3%83%88)[^9]**\(`/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/`\)の配下のヘッダファイルを含むディレクトリを指します[^4]。

##(3)`〇〇.h`の検索

サーチパスを把握し出力をメモしたらlocateコマンドを用いて`〇〇.h`を探します。

同様の検索用のコマンドのfindコマンドもありますが、ここでは高速なlocateコマンドの利用を推奨します。Macでのlocateコマンドの使い方は[環境構築で最も役に立ったlocateコマンドを紹介する](https://qiita.com/DaikiSuyama/items/8e8d4811d8cad39ab057)を参考にしてください。

例えば、`fatal error: 'wchar.h' file not found`となる場合、自分の環境で`wchar.h`を探すと以下のようになります。

```zsh
% locate /wchar.h
/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/wchar.h
/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/usr/include/wchar.h
/Library/Developer/CommandLineTools/usr/include/c++/v1/wchar.h
/usr/local/Cellar/gcc/10.2.0/include/c++/10.2.0/tr1/wchar.h
```

#[4]`file not found`への対処

まず、[MacでGCCを"正しく"環境構築しよう！](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146)の内容を完遂すれば、HomebrewでインストールしたGCCの配下のヘッダファイルは普通はインクルードできます。従って、**MacOSのSDKの配下のヘッダファイルがインクルードできていない**と考えられます。

具体的には以下の手順で実行を行い、その都度エラーが消えるかを確認してください。

##(1)CommandLineTollsの確認

まず、**CommandLineToolsに問題がないかを確認**しましょう。具体的な手順は[「MacでGCCを"正しく"環境構築しよう！」の[1]](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146#1commandlinetools%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)に書いてあります。

##(2)SDKの確認

次は、**インストールすべきSDKが異なる場合がある**ので確認しましょう。`% g++ -v`を実行し、出力の中の`--with-sysroot`オプションの指すディレクトリを確認してください。自分であれば`/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk`となっています。

実は、**`--with-sysroot`オプションで指定されたMacOSのSDKの配下からヘッダファイルがインクルードされます**[^10]。従って、SDKのバージョンの合うCommandLineToolsをインストールしてください。SDKのバージョンの合うCommandLineToolsのインストール方法については[「MacでGCCを"正しく"環境構築しよう！」の[1]の(2)](https://qiita.com/DaikiSuyama/items/09f5aa399aad37783146#2%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E6%99%82%E3%81%AE%E6%B3%A8%E6%84%8F)を参考にしてください。

##(3)`-sysroot`オプションでの指定

(2)まででうまくいかない場合や最新のSDKを使いたい場合は**用いるSDKをコンパイル時のオプションで指定**します。インストール済みのSDKを`% ls /Library/Developer/CommandLineTools/SDKs`で調べ、使いたいSDKを`-sysroot`オプションで指定すれば良いです[^13]。

オプションとして`-sysroot`オプションのみを使うと、以下のようなコマンドになると思います。

```zsh
% g++ -syroot=/Library/Developer/CommandLineTools/SDKs/〇〇.sdk hoge.cc
```


以上を正確に行ってもうまくいかない場合は他の問題が発生してるので、自分で対処方法を考えるか検索してください[^12]。



#[5]C++のサンプルファイル(`hoge.cc`)

何回か出てくる`hoge.cc`を載せておきます。`〇〇.h`をインクルードして終了するだけのソースファイルです。`〇〇.h`は適当に置き換えてください。

```c++:hoge.cc
#include<〇〇.h>
int main(){
    return 0;
}
```

<!--

\#[6]参考記事

https://xanadu62.blogspot.com/2015/03/command-line-tools-for-xcodegoogle.html

https://xanadu62.blogspot.com/2016/11/command-line-tools-for-xcode.html


CommandLineToolsには二通りある話、いつかしたい

-->



[^1]: これ以降、`% コマンド名`で実行するコマンドを示します。シェルによっては`%`が`$`ですが、適宜読み替えてください。

[^2]: [GCCのドキュメントのサーチパス](https://gcc.gnu.org/onlinedocs/cpp/Search-Path.html)に書いてあります。

[^3]: 調査してもわからなかったので、設定ファイルの場所がわかる方は教えていただきたいです。

[^4]: バージョンなどが環境により少し異なる可能性があることに注意してください。また、GCCもSDKも複数ある場合は気をつけてください。

[^5]: `ignoring nonexistent directory`は存在しないディレクトリにもサーチパスが通っていることを表します。

[^7]: この記事でかなり網羅してあると思うので、うまくいかない場合は**一つ一つの手順を完遂できているか**ということに着目してデバッグしてください。


[^9]: MaxOSXをターゲットプラットフォームとしたC++アプリケーションの開発に必要な一連のファイルが含まれています。詳しくは[［SDK マネージャ］](http://docwiki.embarcadero.com/RADStudio/XE5/ja/%EF%BC%BBSDK_%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3%EF%BC%BD)を参考にすると良いです。

[^10]: 設定ファイルを書き換えて--with-sysrootのデフォルトを直接書き換えようと思ったのですが、わかりませんでした。[teratailで質問](https://teratail.com/questions/312416)しているので、**有識者の方はこちらのコメント欄またはteratailで教えていただけるとありがたいです**。


[^12]: コメントをいただけると反応できるかもしれません。

[^13]: `/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`というバージョン名のついていないSDKがある場合、`% ls -l /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`で確認してわかるようにシンボリックリンクになります。**リンク先が正しければ**こちらを指定しても問題ありません。

<!--

どうしてもインクルードしたい場合はlocateで探したパスを(1)-lオプションで指定,(2)環境変数(CPLUS_INCLUDE_PATH)に追加,(3)パスの通ってるディレクトリに移動,などの対応方法があります。

-->