web-dev-qa-db-ja.com

CおよびC ++プロジェクトでinclude /ディレクトリを作成する理由

個人のCおよびC++プロジェクトで作業するときは、通常file.hfile.cppを同じディレクトリに配置し、file.cppfile.hディレクティブで#include "file.h"を参照できます。

ただし、すべての.hファイルがinclude/ディレクトリ内に配置され、.cppファイルが残っているライブラリや他の種類のプロジェクト(LinuxカーネルやfreeRTOSなど)を見つけるのが一般的です別のディレクトリ。これらのプロジェクトでは、.hの代わりに#include "file.h"ファイルも#include "include/file.h"の代わりに含まれています。

このすべてについていくつか質問があります。

  1. このファイル構造編成の利点は何ですか?
  2. .h内のinclude/ファイルが#include "file.h"ではなく#include "include/file.h"に含まれているのはなぜですか?私は本当のトリックがMakefileの中にあることを知っていますが、インクルードするファイルが実際にinclude/ディレクトリにあることを(コードで)明らかにするのではなく、そのようにする方が本当に良いですか?
27
user4546925

これを行う主な理由は、コンパイルされたライブラリが最終的なユーザーによって消費されるためにヘッダーが必要だからです。慣例により、includeディレクトリのコンテンツは、一般消費者向けに公開されるヘッダーです。ソースディレクトリには、内部で使用するためのヘッダーがありますが、これらはnotであり、コンパイルされたライブラリとともに配布されます。

そのため、ライブラリを使用する場合、バイナリにリンクし、ビルドシステムのヘッダーパスにライブラリのincludeディレクトリを追加します。同様に、コンパイルされたライブラリを中央の場所にインストールする場合、どのファイルを中央の場所(コンパイルされたバイナリとincludeディレクトリ)にコピーする必要があり、どのファイルはコピーしない(ソースディレクトリ)など)。

31
Nicol Bolas

<header>スタイルインクルードは暗黙のパスタイプでした。つまり、includes環境変数パスまたはビルドマクロで見つかり、"header"スタイルインクルードはソースファイルが含まれている場所とまったく同じように、明示的な形式のas-inでした。いくつかのビルドツールチェーンではこの区別が可能ですが、多くの場合、デフォルトで効果的に無効にする構成がデフォルトになります。

あなたの質問は興味深いのです。なぜなら、それは本当に良いのか、暗黙的か、明示的かという質問を持ち出すからです。暗黙の形式は確かに簡単です:

  1. ディレクトリの階層にある関連ヘッダーの便利なグループ化。
  2. includesパスにいくつかのディレクトリを含めるだけでよく、ファイルの正確な場所に関するすべての詳細を認識する必要はありません。コードを変更せずに、ライブラリのバージョンとそれに関連するヘッダーを変更できます。
  3. [〜#〜] dry [〜#〜]
  4. フレキシブル!ビルド環境は私のビルド環境と一致する必要はありませんが、ほとんど同じ結果を得ることができます。

一方、Explicitには次のものがあります。

  1. 反復可能なビルド。 includesマクロ/環境変数のパスの順序を変更しても、ビルド中に見つかったヘッダーファイルは変更されません。
  2. ポータブルビルド。ビルドのルートからすべてをパッケージ化し、別の開発者に出荷します。
  3. 情報の近接。 #include "\X\Y\Z"でヘッダーの場所が正確にわかります。暗黙的な形式では、複数のパスに沿って検索する必要があり、同じファイルの複数のバージョンを見つけることさえあります。どのファイルがビルドで使用されているかをどのように確認しますか?

ビルダーは何十年もこれら2つのアプローチについて議論してきましたが、2つのハイブリッド形式は、純粋に明示的な形式に基づいてビルドを維持するために必要な労力と、コードに慣れる明らかな困難のために、ほとんど勝ちます純粋に暗黙的な性質のもの。さまざまなツールチェーンが特定の場所に特定の共通ライブラリとヘッダーを配置し、ユーザーやプロジェクト間で共有できることを一般的に理解しているため、1か所で標準のC/C++ヘッダーを見つけることを期待していますが、最初はそうではありませんローカルに十分に文書化された慣習に欠けている任意のプロジェクトの特定の構造について何かを知っているので、それらのプロジェクトのコードは、それらに固有の非標準ビットに関して明示的であり、標準ビットに関して暗黙的であることを期待します。

プロジェクト固有ではないすべての標準ヘッダーとその他のライブラリには常に<header>形式のincludeを使用し、他のすべてには"header"形式を使用することをお勧めします。ローカルインクルード用にプロジェクトにインクルードディレクトリを作成する必要がありますか?それは、それらのヘッダーがライブラリーへのインターフェースとして出荷されるか、単にコードによって消費されるか、またユーザーの好みにある程度依存します。プロジェクトの規模と複雑さは?内部インターフェイスと外部インターフェイスが混在している場合、または多数の異なるコンポーネントがある場合は、個別のディレクトリにグループ化することをお勧めします。

完成した製品が展開するディレクトリ構造は、その製品を開発および構築するディレクトリ構造のように見える必要はないことに留意してください。c/ .cppファイルとヘッダーが数個しかない場合は、配置しても構いませんこれらはすべて1つのディレクトリに格納されていますが、最終的には自明ではない何かに取り組むことになり、ビルド環境の選択の結果を検討し、他の人が理解できるようにドキュメント化する必要があります。

7
jwdonahue

1 .hppと.cppは1対1の関係を持つ必要はありません。異なる条件(例:異なる環境)に応じて、同じ.hppを使用する複数の.cppが存在する場合があります。例:マルチプラットフォームライブラリ、クラスがあると想像アプリのバージョンを取得するには、ヘッダーは次のようになります。

Utilities.h

#include <string.h>
class Utilities{
    static std::string getAppVersion();
}

main.cpp

#include Utilities.h
int main(){
    std::cout << Utilities::getAppVersion() << std::ends;
    return 0;
}

プラットフォームごとに1つの.cppがあり、.cppを異なる場所に配置して、対応するプラットフォームで簡単に選択できるようにすることができます。例:

iOS用の.cpp(パス:DemoProject/ios/Utilities.cpp):

#include "Utilities.h"
std::string Utilities::getAppVersion(){
    //some Objective C code
}

.cpp for Android(path:DemoProject/Android/Utilities.cpp):

#include "Utilities.h"
std::string Utilities::getAppVersion(){
    //some jni code
}

そしてもちろん2 .cppは通常同時に使用されません。


2。

#include "file.h" 

の代わりに

#include "include/file.h" 

ヘッダーが「include」フォルダーに配置されなくなったときに、ソースコードを変更せずに保持できます。

1
ocomfd