109

ルールを含むメイクファイルがあるとしましょう

%.o: %.c
 gcc -Wall -Iinclude ...

ヘッダー ファイルが変更されるたびに *.o が再構築されるようにします。依存関係のリストを作成するのではなく、ヘッダー ファイルが/include変更されるたびに、ディレクトリ内のすべてのオブジェクトを再構築する必要があります。

これに対応するためにルールを変更する良い方法は思いつきません。提案は受け付けています。ヘッダーのリストをハードコードする必要がない場合のボーナス ポイント

4

10 に答える 10

125

GNU コンパイラを使用している場合、コンパイラは依存関係のリストを作成できます。Makefile フラグメント:

depend: .depend

.depend: $(SRCS)
        rm -f "$@"
        $(CC) $(CFLAGS) -MM $^ -MF "$@"

include .depend

また

depend: .depend

.depend: $(SRCS)
        rm -f "$@"
        $(CC) $(CFLAGS) -MM $^ > "$@"

include .depend

whereSRCSは、ソース ファイルのリスト全体を指す変数です。

ツールもありますmakedependが、私はそれほど好きではありませんでしたgcc -MM

于 2010-03-07T00:33:15.320 に答える
29

ここに投稿したように、gcc は依存関係を作成し、同時にコンパイルできます。

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<

「-MF」パラメーターは、依存関係を保管するファイルを指定します。

「-include」の先頭のダッシュは、.d ファイルが存在しない場合 (最初のコンパイル時など) に続行するように Make に指示します。

-o オプションに関して gcc にバグがあるようです。オブジェクト ファイル名を obj/_file__c.o に設定すると、生成されたファイル.d には obj/_file__c.o ではなく、ファイル.o が含まれます。

于 2010-03-23T16:27:01.753 に答える
23

次のようなものはどうですか:

includes = $(wildcard include/*.h)

%.o: %.c ${includes}
    gcc -Wall -Iinclude ...

ワイルドカードを直接使用することもできますが、複数の場所でワイルドカードが必要になる傾向があります。

これは、すべてのオブジェクト ファイルがすべてのヘッダー ファイルに依存することを前提としているため、小さなプロジェクトでのみうまく機能することに注意してください。

于 2010-03-07T00:15:45.857 に答える
5

上記のマーティンのソリューションはうまく機能しますが、サブディレクトリにある .o ファイルを処理しません。Godric は、-MT フラグがその問題を処理することを指摘していますが、同時に .o ファイルが正しく書き込まれないようにします。以下は、これらの問題の両方を処理します。

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) -o $@ $<
于 2015-04-01T00:05:58.083 に答える
3

これにより、問題なくジョブが実行され、指定されたサブディレクトリも処理されます。

    $(CC) $(CFLAGS) -MD -o $@ $<

gcc 4.8.3でテストしました

于 2014-12-15T12:36:29.477 に答える
2

*.d ファイルを別のフォルダーに出力できるようにするソフィーの回答のわずかに変更されたバージョン (依存関係ファイルを生成する興味深い部分のみを貼り付けます):

$(OBJDIR)/%.o: %.cpp
# Generate dependency file
    mkdir -p $(@D:$(OBJDIR)%=$(DEPDIR)%)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MM -MT $@ $< -MF $(@:$(OBJDIR)/%.o=$(DEPDIR)/%.d)
# Generate object file
    mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@

パラメータに注意してください

-MT $@

生成された *.d ファイルのターゲット (つまり、オブジェクト ファイル名) に、ファイル名だけでなく、*.o ファイルへのフル パスが含まれていることを確認するために使用されます。

-MMD を -cと組み合わせて使用​​する場合(ソフィーのバージョンのように) 、このパラメーターが必要ない理由がわかりません。この組み合わせでは、*.o ファイルのフル パスを *.d ファイルに書き込むようです。この組み合わせを使用しない場合、-MMD はディレクトリ コンポーネントを含まない純粋なファイル名のみを *.d ファイルに書き込みます。-c と組み合わせたときに -MMD がフルパスを書き込む理由を誰かが知っているかもしれません。g++ の man ページにヒントが見つかりませんでした。

于 2018-12-22T18:24:02.763 に答える
1

Michael Williamson が受け入れた回答よりも、このソリューションを好みます。ソース + インライン ファイル、ソース + ヘッダー、最後にソースのみの変更をキャッチします。ここでの利点は、わずかな変更が加えられた場合、ライブラリ全体が再コンパイルされないことです。いくつかのファイルを含むプロジェクトでは大きな考慮事項ではありませんが、10 個または 100 個のソースがある場合は、違いに気付くでしょう。

COMMAND= gcc -Wall -Iinclude ...

%.o: %.cpp %.inl
    $(COMMAND)

%.o: %.cpp %.hpp
    $(COMMAND)

%.o: %.cpp
    $(COMMAND)
于 2014-06-16T12:44:42.750 に答える
1

以下は私にとってはうまくいきます:

DEPS := $(OBJS:.o=.d)

-include $(DEPS)

%.o: %.cpp
    $(CXX) $(CFLAGS) -MMD -c -o $@ $<
于 2016-12-15T19:34:05.610 に答える