変更されたヘッダーファイルを含むソースファイルをMakefileが自動的に再構築する方法を教えてください。(C / C ++の場合)


92

私が取り組んでいるプログラム(実際にはカーネル)をビルドするために使用する次のmakefileがあります。ゼロから、そして私はプロセスについて学んでいるので、完璧ではありませんが、メイクファイルを書く私のレベルの経験には、現時点で十分強力であると思います。

AS  =   nasm
CC  =   gcc
LD  =   ld

TARGET      =   core
BUILD       =   build
SOURCES     =   source
INCLUDE     =   include
ASM         =   assembly

VPATH = $(SOURCES)

CFLAGS  =   -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions \
            -nostdinc -fno-builtin -I $(INCLUDE)
ASFLAGS =   -f elf

#CFILES     =   core.c consoleio.c system.c
CFILES      =   $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
SFILES      =   assembly/start.asm

SOBJS   =   $(SFILES:.asm=.o)
COBJS   =   $(CFILES:.c=.o)
OBJS    =   $(SOBJS) $(COBJS)

build : $(TARGET).img

$(TARGET).img : $(TARGET).elf
    c:/python26/python.exe concat.py stage1 stage2 pad.bin core.elf floppy.img

$(TARGET).elf : $(OBJS)
    $(LD) -T link.ld -o $@ $^

$(SOBJS) : $(SFILES)
    $(AS) $(ASFLAGS) $< -o $@

%.o: %.c
    @echo Compiling $<...
    $(CC) $(CFLAGS) -c -o $@ $<

#Clean Script - Should clear out all .o files everywhere and all that.
clean:
    -del *.img
    -del *.o
    -del assembly\*.o
    -del core.elf

このメイクファイルの主な問題は、1つ以上のCファイルに含まれるヘッダーファイルを変更すると、Cファイルが再構築されないことです。すべてのヘッダーファイルをすべてのCファイルの依存関係にすることで、これを簡単に修正できますが、ヘッダーファイルを変更または追加すると、プロジェクトが完全に再構築されます。

私が欲しいのは、変更したヘッダーファイルを含む Cファイルのみをリビルドして、プロジェクト全体を再度リンクすることです。すべてのヘッダーファイルをターゲットの依存関係にすることでリンクを作成できますが、含まれているヘッダーファイルが新しい場合にCファイルを無効にする方法を理解できません。

GCCにはこれを可能にするコマンドがいくつかあると聞いたことがあります(そのため、makefileはどのファイルを再構築する必要があるかを何らかの形で把握できます)。メイクファイルでこの動作を可能にするソリューションを誰かが投稿できますか?

編集:私は明確にする必要があります、私は個々のターゲットを配置し、各target.oにヘッダーファイルを要求させるという概念に精通しています。そのため、ヘッダーファイルをどこかにインクルードするたびにメイクファイルを編集する必要がありますが、これは少し面倒です。ヘッダーファイルの依存関係を独自に導出できるソリューションを探しています。これは、他のプロジェクトで見たことがかなり確実です。

回答:


30

このサイトの他の場所で既に指摘したように、このページを参照してください: 自動依存関係の生成

つまり、gccは自動的に.d依存ファイルを作成できます。これは、コンパイルした.cファイルの依存関係を含むミニmakefileフラグメントです。.cファイルを変更してコンパイルするたびに、.dファイルが更新されます。

gccに-Mフラグを追加するほかに、メイクファイルに.dファイルを含める必要があります(クリスが上で書いたように)。ページにはsedを使用して解決されるより複雑な問題がいくつかありますが、存在しないヘッダーファイルを作成できないというメッセージが出るたびに、それらを無視して「make clean」を実行して.dファイルを削除できます。 。


2
私は間違っているかもしれませんが、GCCには実際にそのsedの問題を回避するための機能が追加されていると思います。チェックアウトgcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html特に-MPを。
Eugene Marcotte 2013年

はい、-MPはGCC 3以降に存在し、clangとiccに存在し、sedの必要性を無効にします。bruno.defraine.net/techtips/makefile-auto-dependencies-with-gcc/…–
hmijailが辞任を悼む

回答のリンクの最新バージョンには、GCCフラグを使用した例が含まれています。
MadScientist

20

他の人が述べたように、 'makedepend'コマンドを追加することもできますが、なぜgccに依存関係を作成させ、同時にコンパイルさせないのですか:

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

-include $(DEPS)

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

'-MF'パラメーターは、依存関係を格納するファイルを指定します。

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

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


18
これは私にはうまくいきませんでした。たとえば、makefileが生成してこれを実行したとしg++ -c -Wall -Werror -MM -MF main.d -o main.o main.cpp ます。main.dファイルを取得しましたが、main.oは0バイトでした。ただし、-MMDフラグは必要なことを正確に実行するようです。:になった私の作業のmakefileルールだから$(CC) -c $(CFLAGS) -MMD -o $@ $<
ダレン・クック

17

これはChris Doddの回答と同じですが、異なる命名規則を使用しています(偶然にもsedマジックは必要ありません。後の複製からコピーしまし


GNUコンパイラーを使用している場合、コンパイラーは依存関係のリストをアセンブルします。Makefileフラグメント:

depend: .depend

.depend: $(SOURCES)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^>>./.depend;

include .depend

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


4
なぜSOURCESを詳しく説明しないのですか?特に多くの文字を必要とせず、頭字語のように見える "SRCS"ほど難読化されていません。
HelloGoodbye 2015

@HelloGoodbye少しスタイル。私はいつも使用し、常に見て、きたSRCSOBJS。ほとんどの場合、私は同意しますが、誰もがそれらが何であるかを知っているべきです。
sherrellbc

@sherrellbc知っていて、「すべきである」とは何人何人が実際に知っている、多くの場合、2つの異なるものです:P
HelloGoodbye

7

Cファイルごとに個別のターゲットを作成し、依存関係としてヘッダーファイルをリストする必要があります。次のように、引き続き汎用ターゲットを使用して、.h後で依存関係を配置することができます。

%.o: %.c
        @echo Compiling $<...
        $(CC) $(CFLAGS) -c -o $@ $<

foo.c: bar.h
# And so on...

4

基本的に、ヘッダーファイルが変更されたときにオブジェクトファイルを再構築するには、makefileルールを動的に作成する必要があります。gccとgnumakeを使用する場合、これはかなり簡単です。次のようなものを置くだけです:

$(OBJDIR)/%.d: %.c
        $(CC) -MM -MG $(CPPFLAGS) $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@

ifneq ($(MAKECMDGOALS),clean)
include $(SRCS:%.c=$(OBJDIR)/%.d)
endif

あなたのメイクファイルで。


2
(-MMフラグと-MGフラグが新しいことを除けば)暗号テキストの正規表現の行が何のためにあるのか理解していないことを除いて、私はこれをある程度理解しています。チームメイトを幸せにするわけではありません... ^ _ ^でもやってみて、結果があるかどうか確認します。
ニコラスフリント

sedは、ファイルを使用せずにテキストのストリームを変更できる「ストリームエディタ」の略です。これは標準のUnixツールであり、小型で高速であるため、awkやperlよりも頻繁に使用されます。
Zan Lynx

ああ、問題があります。これはWindowsで実行しています。
Nicholas Flynt、

3

@mipadiの発言に加えて-M、依存関係のレコードを生成するための ' 'オプションの使用を検討することもできます。それらを別のファイル(おそらく 'depend.mk')に生成してから、メイクファイルに含めることもできます。またはmake depend、正しい依存関係でメイクファイルを編集する ' 'ルールを見つけることができます(Google用語:「この行を削除しないでください」および依存します)。


1

答えはどれもうまくいきませんでした。たとえば、Martin Fidoの回答はgccが依存関係ファイルを作成できることを示唆していますが、試したところ、警告やエラーなしで空の(0バイト)オブジェクトファイルが生成されました。これはgccのバグである可能性があります。私はついています

$ gcc --version gcc(GCC)4.4.7 20120313(Red Hat 4.4.7-16)

だから私のために働く私の完全なMakefileはここにあります; それはソリューションの組み合わせ+他の誰も言及しなかったものです(例えば.cc.o:として指定された「サフィックス置換規則」):

CC = g++
CFLAGS = -Wall -g -std=c++0x
INCLUDES = -I./includes/

# LFLAGS = -L../lib
# LIBS = -lmylib -lm

# List of all source files
SRCS = main.cc cache.cc

# Object files defined from source files
OBJS = $(SRCS:.cc=.o)

# # define the executable file 
MAIN = cache_test

#List of non-file based targets:
.PHONY: depend clean all

##  .DEFAULT_GOAL := all

# List of dependencies defined from list of object files
DEPS := $(OBJS:.o=.d)

all: $(MAIN)

-include $(DEPS)

$(MAIN): $(OBJS)
    $(CC) $(CFLAGS) $(INCLUDES) -o $(MAIN) $(OBJS) $(LFLAGS) $(LIBS)

#suffix replacement rule for building .o's from .cc's
#build dependency files first, second line actually compiles into .o
.cc.o:
    $(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<

clean:
    $(RM) *.o *~ $(MAIN) *.d

上記のMakefileは.cファイルに合わせて簡単に調整できます。

これら2つの行の重要性にも注意してください。

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

したがって、gccは、最初に依存ファイルを構築するために一度呼び出され、次に実際に.ccファイルをコンパイルします。各ソースファイルについても同様です。


0

より簡単な解決策:Makefileを使用して、.cから.oへのコンパイルルールをヘッダーファイルやその他の依存関係としてプロジェクトに関連するものに依存させるだけです。

たとえば、Makefileのどこかに:

DEPENDENCIES=mydefs.h yourdefs.h Makefile GameOfThrones.S07E01.mkv

::: (your other Makefile statements like rules 
:::  for constructing executables or libraries)

# Compile any .c to the corresponding .o file:
%.o: %.c $(DEPENDENCIES)
        $(CC) $(CFLAGS) -c -o $@ $<

-1

私は信じているmkdepコマンドが何をしたいです。実際に.cファイルをスキャンして#include行を探し、それらの依存関係ツリーを作成します。Automake / Autoconfプロジェクトはデフォルトでこれを使用すると思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.