3

依存関係リゾルバーを使用して、単純なC++インクリメンタルビルドツールを作成しようとしています。私はcppビルドプロセスに関する1つの問題について混乱しています。ライブラリがいくつかのファイルで構成されていると想像してください。

// h1.h
void H1();

// s1.cpp
#include "h1.h"
#include "h2.h"
void H1(){ H2(); }

// h2.h
void H2();

// s2.cpp
#include "h2.h"
#include "h3.h"
void H2(){ /*some implementation*/ }
void H3(){ /*some implementation*/ }

// h3.h
void H3();

h1.hを含むクライアントコードの場合

// app1.cpp
#include "h1.h"
int main()
{
  H1();
  return 0;
}

s2.cpp実装には暗黙の依存関係があります:our_src-> h3-> s1->h2->s2。したがって、2つのobjファイルとリンクする必要があります。

g++ -o app1 app1.o s1.o s2.o

対照的に、h3.hが含まれている場合

// app2.cpp
#include "h3.h"
int main()
{
  H3();
  return 0;
}

ソースの依存関係は1つだけです:our_src-> h3-> s2

したがって、h3.hをインクルードする場合、コンパイルする必要があるのはs2.cppのみです(s1.cpp-> h2.hをインクルードしているにもかかわらず)。

g++ -o app2 app2.o s2.o

これは問題の非常に単純な例です。実際のプロジェクトでは、確かに数百のファイルがあり、非効率的なインクルードのチェーンにはさらに多くのファイルが含まれている可能性があります。

だから私の質問は:依存関係をチェックするときに(CPP解析なしで)どのヘッダーインクルージョンを省略できるかを見つける方法や手段はありますか?

ご回答いただければ幸いです。

4

3 に答える 3

3

s2.cppへの暗黙の依存関係を確認すると述べた場合、s1モジュールがs2を使用していることがわかるのは、実装モジュールs1.cppを解析する必要があるためです。したがって、「。cppファイルを解析せずにこの問題を解決できるか」という質問に対する答えは明らかにノーです。

ちなみに、言語に関する限り、ヘッダーファイルと実装ファイルに入れることができるものに違いはありません。#includeディレクティブはC++レベルでは機能しません。言語を理解していない、単なるテキストマクロ関数です。さらに、「ちょうど」C ++宣言を解析することさえ、真の悪夢です(C ++構文の難しい部分は、ステートメント/式ではなく、宣言です)。

C ++ファイルを解析し、検査可能なXMLデータ構造を返すgccxmlの結果を使用できる可能性があります。

于 2011-09-25T17:51:41.067 に答える
0

これは簡単な問題ではありません。これを困難にする多くのことのほんの2、3:

  1. 1つのヘッダーファイルがN>1のソースファイルに実装されている場合はどうなりますか?たとえば、、、、およびclass Fooで定義されているが、でfoo.h実装されているとします。foo_cotr_dotr.cppfoo_this_function.cppfoo_that_function.cpp
  2. 同じ機能が複数のソースファイルに実装されている場合はどうなりますか?たとえば、、、にFoo::bar()実装があるとします。使用する実装は、ターゲットプラットフォームによって異なります。foo_bar_linux.cppfoo_bar_osx.cppfoo_bar_sunos.cpp

簡単な解決策の1つは、共有ライブラリまたはダイナミックライブラリを構築し、そのライブラリに対してリンクすることです。ツールチェーンにそれらの依存関係を解決させます。問題#1は完全に解消され、問題#2も、十分にスマートなmakefileがある場合は解消されます。

この簡単な解決策を打ち負かすことを主張する場合は、それらの依存関係を自分で解決するために何かをする必要があります。プロジェクトルール1つのヘッダーファイル==1つのソースファイルによって、上記の問題(完全なリストではありません)を排除できます。私はそのようなルールを見たことがありますが、1つの関数==1つのソースファイルを示すプロジェクトルールを見たほど頻繁ではありません。

于 2011-09-25T17:47:57.797 に答える
0

私がWandをどのように実装したかをご覧ください。ディレクティブを使用して、個々のソースファイルの依存関係を追加します。ドキュメントはまだ完全には完成していませんが、GabiのソースコードにWandディレクティブの例があります。

スレッドクラスインクルードファイル

Thread.hはリンク時にthread.oを必要とします

#ifdef __WAND__
dependency[thread.o]
target[name[thread.h] type[include]]
#endif

Windowsでのスレッドクラスの実装(thread-win32.cpp)

このファイルは、Windowsがターゲットプラットフォームである場合にのみコンパイルする必要があります

#ifdef __WAND__
target[name[thread.o] type[object] platform[;Windows]]
#endif

GNU / Linuxでのスレッドクラスの実装(thread-linux.cpp)

このファイルは、GNU/Linuxがターゲットプラットフォームである場合にのみコンパイルする必要があります。GNU / Linuxでは、リンク時に外部ライブラリのpthreadが必要です。

#ifdef __WAND__
target
    [
    name[thread.o] type[object] platform[;GNU/Linux]
    dependency[pthread;external]
    ]
#endif

長所と短所

長所

  • ワンドを拡張して、他のプログラミング言語で機能するようにすることができます
  • ワンドは、コマンドワンドを与えるだけで、新しいプログラムを正常にリンクするために必要なすべてのデータを保存します
  • これらはソースファイルに保存されているため、プロジェクトファイルで依存関係について言及する必要はありません。

短所

  • ワンドでは、各ソースファイルに追加のディレクティブが必要です
  • このツールは、図書館の執筆者によってまだ広く使用されていません
于 2014-04-07T08:28:46.953 に答える