HOWTO · C++
C++ インクルード パス:ヘッダー検索の設定
C++ インクルード パスがコンパイラのヘッダー検索にどう役立つかを学び、コンパイラ フラグ、IDE 設定、Makefile を使ってプロジェクトのヘッダー ディレクトリを設定します。
このページの内容
インクルード パスとは、#include ディレクティブで指定されたヘッダーを解決する際に C++ コンパイラが考慮するディレクトリです。ソース ファイルが、コンパイラがすでに検索する場所にはないヘッダーをインクルードする場合は、プロジェクトのヘッダー ディレクトリをビルド設定に追加してください。ディレクティブはソース コードに属し、インクルード パスはコンパイラまたはビルドの設定に属します。
C++ インクルード パスとは
プロジェクトでは、宣言をヘッダー ディレクトリに、実装をソース ファイルに置くことができます。以下の Bash の例では、一時プロジェクト ディレクトリに tmp_dir/ → include/message.h と src/main.cpp という構成が含まれます。
main.cpp に #include <message.h> が含まれている場合、コンパイラは include/ が検索ディレクトリであることを知る必要があります。インクルード パスはヘッダーのコピーではなく、その内容を変更することもありません。インクルード処理の際にコンパイラがどこを探してよいかを伝えるものです。システム ヘッダーやツールチェーン ヘッダーも、コンパイラとビルド環境が設定した場所を通じて見つかります。
C++ インクルード パスの設定方法
使用するビルドに属する設定を選んでください。ヘッダー ディレクトリとそのパスは、ローカル ビルド、IDE 設定、自動化の間で一貫させてください。
コンパイラ フラグ
GCC または互換コンパイラでは、-I がヘッダー検索設定にディレクトリを追加します。以下の自己完結型の Bash の例は、一時ディレクトリに小さなプロジェクトを作成するため、どの作業ディレクトリからでも実行できます。
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT
mkdir -p "$tmp_dir/include" "$tmp_dir/src"
cat > "$tmp_dir/include/message.h" <<'HEADER'
#pragma once
#define MESSAGE "Hello from the project header"
HEADER
cat > "$tmp_dir/src/main.cpp" <<'SOURCE'
#include <iostream>
#include <message.h>
int main() {
std::cout << MESSAGE << '\n';
}
SOURCE
g++ -I"$tmp_dir/include" "$tmp_dir/src/main.cpp" -o "$tmp_dir/app"
"$tmp_dir/app"
Hello from the project header
-I オプションはヘッダーのファイル名ではなく、ヘッダーを含むディレクトリを受け取ります。ここではコンパイラが src/main.cpp を受け取り、-o で実行ファイルを一時ディレクトリに書き出します。Microsoft C++(cl)の場合は、代わりに /I の後にディレクトリを続けてください。フラグの構文はコンパイラによって異なります。
IDE のプロジェクト設定
Visual Studio では、C/C++ インクルード オプションの下にあるプロジェクトの Additional Include Directories 設定にヘッダー ディレクトリを追加します。プロパティ ページの正確なラベルは、Visual Studio のバージョンやプロジェクトの種類によって異なる場合があります。設定は、Debug や x64 など、ビルドする構成とプラットフォームに適用してください。パスを移植しやすくするのに役立つ場合は、プロジェクトのディレクトリ変数を使用してください。他の IDE にも同等のコンパイラまたはプロジェクトのインクルード ディレクトリ設定があります。アクティブなビルド構成がそれを使用していることを確認してください。
Makefile
コンパイラ フラグを Makefile のコンパイル フラグに入れて、各ソースのコンパイルで受け取れるようにします。たとえば、関連する設定は CXXFLAGS += -Iinclude と書けます。ビルド ルールは、ソース ファイルをコンパイルする際に $(CXXFLAGS) を使用する必要があります。選択したコンパイラによってフラグが決まります。Microsoft の cl を呼び出す Makefile では、代わりに /Iinclude が必要です。これは構文の例示であり、完全な Makefile でも実行済みのビルドでもありません。
C++ のヘッダー検索の仕組み
#include ディレクティブは、名前付きヘッダーを処理するようプリプロセッサに依頼します。考慮される場所は、ディレクティブの形式、それを含むファイル、コンパイラ オプション、実装によって異なります。すべてのコンパイラが同じ順序で普遍的なリストを検索したり、プロジェクトの親ディレクトリを自動的に確認したりすると想定しないでください。
ヘッダーが見つからない場合は、スペルと大文字小文字を確認し、次に設定したディレクトリがそのファイルを含むものであることを確認してください。フラグまたは IDE プロパティが、ビルドしている構成のコンパイラ呼び出しに届いていることを確認してください。ヘッダーが別のヘッダーからインクルードされている場合は、インクルードするファイルの場所とコンパイラの文書化されたルールを考慮してください。詳細なビルドや、検索パスを表示するコンパイラ オプションは、どの構成がアクティブかを示すのに役立ちます。利用できる診断コマンドはツールチェーンによって異なります。
#include "..." と #include <...> の違い
引用符形式の #include "message.h" は、通常、まずインクルードするファイルのディレクトリを検索し、その後、実装の追加の検索ルールに従います。山括弧形式の #include <message.h> は、実装の設定済み検索場所を使用します。残りの正確な検索動作は実装定義であるため、順序が重要な場合はコンパイラのドキュメントを参照してください。
これらの形式は、「カスタム」と「標準」のヘッダーを厳密に区別するラベルではありません。プロジェクト ヘッダーは、そのディレクトリが設定されていれば、上の例のように山括弧を使用できます。引用符形式は、実装の検索ルールの下で到達可能な任意のヘッダーを指定できます。プロジェクトの慣例に合った形式を選び、名前が解決されるかどうかはコンパイラの設定済みパスによって決まることを理解してください。