如何让Makefile自动重建包含已修改头文件的源文件? (在C / C ++中)

时间:2021-10-29 01:54:17

I have the following makefile that I use to build a program (a kernel, actually) that I'm working on. Its from scratch and I'm learning about the process, so its not perfect, but I think its powerful enough at this point for my level of experience writing makefiles.

我有以下makefile用于构建我正在处理的程序(实际上是内核)。它从头开始,我正在学习这个过程,所以它并不完美,但我认为它在这一点上足够强大,因为我的编写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

My main issue with this makefile is that when I modify a header file that one or more C files include, the C files aren't rebuilt. I can fix this quite easily by having all of my header files be dependencies for all of my C files, but that would effectively cause a complete rebuild of the project any time I changed/added a header file, which would not be very graceful.

我对makefile的主要问题是,当我修改一个或多个C文件包含的头文件时,不会重建C文件。通过让我的所有头文件都是我所有C文件的依赖项,我可以很容易地解决这个问题,但是这会在我更改/添加头文件时有效地导致项目的完全重建,这不会非常优雅。

What I want is for only the C files that include the header file I change to be rebuilt, and for the entire project to be linked again. I can do the linking by causing all header files to be dependencies of the target, but I cannot figure out how to make the C files be invalidated when their included header files are newer.

我想要的只是包含我改变的头文件的C文件重建,以及整个项目再次链接。我可以通过使所有头文件成为目标的依赖关系来进行链接,但是当我们包含的头文件较新时,我无法弄清楚如何使C文件失效。

I've heard that GCC has some commands to make this possible (so the makefile can somehow figure out which files need to be rebuilt) but I can't for the life of me find an actual implementation example to look at. Can someone post a solution that will enable this behavior in a makefile?

我听说GCC有一些命令可以实现这一点(所以makefile可以以某种方式找出需要重建的文件)但我不能在我的生活中找到一个实际的实现示例来查看。有人可以发布一个解决方案,在makefile中启用此行为吗?

EDIT: I should clarify, I'm familiar with the concept of putting the individual targets in and having each target.o require the header files. That requires me to be editing the makefile every time I include a header file somewhere, which is a bit of a pain. I'm looking for a solution that can derive the header file dependencies on its own, which I'm fairly certain I've seen in other projects.

编辑:我应该澄清,我熟悉将各个目标放入并拥有每个目标的概念.o需要头文件。这要求我每次在某处包含头文件时都要编辑makefile,这有点痛苦。我正在寻找一个可以自己派生头文件依赖的解决方案,我相当肯定我已经在其他项目中看到了。

9 个解决方案

#1


27  

As already pointed out elsewhere on this site, see this page: http://make.paulandlesley.org/autodep.html

正如本网站其他地方已经指出的那样,请参阅此页面:http://make.paulandlesley.org/autodep.html

In short, gcc can automatically create .d dependency files for you, which are mini makefile fragments containing the dependencies of the .c file you compiled. Every time you change the .c file and compile it, the .d file will be updated.

简而言之,gcc可以自动为您创建.d依赖文件,这些文件是包含您编译的.c文件的依赖项的迷你makefile片段。每次更改.c文件并进行编译时,都会更新.d文件。

Besides adding the -M flag to gcc, you'll need to include the .d files in the makefile (like Chris wrote above). There are some more complicated issues in the page which are solved using sed, but you can ignore them and do a "make clean" to clear away the .d files whenever make complains about not being able to build a header file that no longer exists.

除了向gcc添加-M标志外,还需要在makefile中包含.d文件(如上面的Chris所述)。在页面中有一些更复杂的问题,使用sed解决,但你可以忽略它们并做“清理”以清除.d文件,只要抱怨无法生成不再存在的头文件。

#2


20  

You could add a 'make depend' command as others have stated but why not get gcc to create dependencies and compile at the same time:

您可以像其他人所说的那样添加'make depend'命令,但为什么不让gcc创建依赖项并同时编译:

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

-include $(DEPS)

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

The '-MF' parameter specifies a file to store the dependencies in.

'-MF'参数指定用于存储依赖项的文件。

The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).

'-include'开头的破折号告诉Make在.d文件不存在时继续(例如在第一次编译时)。

Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated _file_.d will still contain _file_.o, not obj/_file_c.o.

注意gcc中似乎存在关于-o选项的错误。如果将对象文件名设置为obj / _file__c.o,则生成的_file_.d仍将包含_file_.o,而不是obj / _file_c.o。

#3


16  

This is equivalent to Chris Dodd's answer, but uses a different naming convention (and coincidentally doesn't require the sed magic. Copied from a later duplicate.

这相当于克里斯多德的答案,但使用了不同的命名约定(巧合的是不需要sed魔法。从后来的副本复制。


If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:

如果您使用的是GNU编译器,编译器可以为您组装一个依赖项列表。 Makefile片段:

depend: .depend

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

include .depend

There is also the tool makedepend, but I never liked it as much as gcc -MM

还有工具makedepend,但我从来没有像gcc -MM那样喜欢它

#4


7  

You'll have to make individual targets for each C file, and then list the header file as a dependency. You can still use your generic targets, and just place the .h dependencies afterwards, like so:

您必须为每个C文件创建单独的目标,然后将头文件列为依赖项。您仍然可以使用通用目标,之后只需放置.h依赖项,如下所示:

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

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

#5


3  

Over and above what @mipadi said, you can also explore the use of the '-M' option to generate a record of the dependencies. You might even generate those into a separate file (perhaps 'depend.mk') which you then include in the makefile. Or you can find a 'make depend' rule which edits the makefile with the correct dependencies (Google terms: "do not remove this line" and depend).

除了@mipadi所说的,你还可以探索使用'-M'选项来生成依赖关系的记录。您甚至可以将它们生成一个单独的文件(可能是“depend.mk”),然后将其包含在makefile中。或者您可以找到一个'make depend'规则,该规则使用正确的依赖关系编辑makefile(Google术语:“不要删除此行”并依赖)。

#6


3  

Basically, you need to dynamically create the makefile rules to rebuild the object files when the header files change. If you use gcc and gnumake, this is fairly easy; just put something like:

基本上,您需要动态创建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

in your makefile.

在你的makefile中。

#7


0  

None of the answers worked for me. E.g. Martin Fido's answer suggests gcc can create dependency file, but when I tried that it was generating empty (zero bytes) object files for me without any warnings or errors. It might be a gcc bug. I am on

这些答案都不适合我。例如。 Martin Fido的回答表明gcc可以创建依赖文件,但是当我尝试它为我生成空(零字节)对象文件时没有任何警告或错误。它可能是一个gcc bug。我在

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

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

So here's my complete Makefile that works for me; it's a combination of solutions + something that wasn't mentioned by anyone else (e.g. "suffix replacement rule" specified as .cc.o:):

所以这是我完整的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

Notice I used .cc .. The above Makefile is easy to adjust for .c files.

注意我使用.cc ..上面的Makefile很容易调整.c文件。

Also important to note importance of these two lines :

同样重要的是要注意这两行的重要性:

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

so gcc is called once to build a dependency file first, and then actually compiles a .cc file. And so on for each source file.

所以首先调用gcc来构建一个依赖文件,然后实际编译一个.cc文件。等等每个源文件。

#8


0  

Simpler solution: Just use the Makefile to have the .c to .o compilation rule be dependent on the header file(s) and whatever else is relevant in your project as a dependency.

更简单的解决方案:只需使用Makefile使.c到.o编译规则依赖于头文件以及项目中作为依赖项的任何其他相关内容。

E.g., in the Makefile somewhere:

例如,在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 $@ $<

#9


-1  

I believe the mkdep command is what you want. It actually scans .c files for #include lines and creates a dependency tree for them. I believe Automake/Autoconf projects use this by default.

我相信mkdep命令就是你想要的。它实际上扫描.c文件中的#include行并为它们创建依赖树。我相信Automake / Autoconf项目默认使用它。

#1


27  

As already pointed out elsewhere on this site, see this page: http://make.paulandlesley.org/autodep.html

正如本网站其他地方已经指出的那样,请参阅此页面:http://make.paulandlesley.org/autodep.html

In short, gcc can automatically create .d dependency files for you, which are mini makefile fragments containing the dependencies of the .c file you compiled. Every time you change the .c file and compile it, the .d file will be updated.

简而言之,gcc可以自动为您创建.d依赖文件,这些文件是包含您编译的.c文件的依赖项的迷你makefile片段。每次更改.c文件并进行编译时,都会更新.d文件。

Besides adding the -M flag to gcc, you'll need to include the .d files in the makefile (like Chris wrote above). There are some more complicated issues in the page which are solved using sed, but you can ignore them and do a "make clean" to clear away the .d files whenever make complains about not being able to build a header file that no longer exists.

除了向gcc添加-M标志外,还需要在makefile中包含.d文件(如上面的Chris所述)。在页面中有一些更复杂的问题,使用sed解决,但你可以忽略它们并做“清理”以清除.d文件,只要抱怨无法生成不再存在的头文件。

#2


20  

You could add a 'make depend' command as others have stated but why not get gcc to create dependencies and compile at the same time:

您可以像其他人所说的那样添加'make depend'命令,但为什么不让gcc创建依赖项并同时编译:

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

-include $(DEPS)

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

The '-MF' parameter specifies a file to store the dependencies in.

'-MF'参数指定用于存储依赖项的文件。

The dash at the start of '-include' tells Make to continue when the .d file doesn't exist (e.g. on first compilation).

'-include'开头的破折号告诉Make在.d文件不存在时继续(例如在第一次编译时)。

Note there seems to be a bug in gcc regarding the -o option. If you set the object filename to say obj/_file__c.o then the generated _file_.d will still contain _file_.o, not obj/_file_c.o.

注意gcc中似乎存在关于-o选项的错误。如果将对象文件名设置为obj / _file__c.o,则生成的_file_.d仍将包含_file_.o,而不是obj / _file_c.o。

#3


16  

This is equivalent to Chris Dodd's answer, but uses a different naming convention (and coincidentally doesn't require the sed magic. Copied from a later duplicate.

这相当于克里斯多德的答案,但使用了不同的命名约定(巧合的是不需要sed魔法。从后来的副本复制。


If you are using a GNU compiler, the compiler can assemble a list of dependencies for you. Makefile fragment:

如果您使用的是GNU编译器,编译器可以为您组装一个依赖项列表。 Makefile片段:

depend: .depend

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

include .depend

There is also the tool makedepend, but I never liked it as much as gcc -MM

还有工具makedepend,但我从来没有像gcc -MM那样喜欢它

#4


7  

You'll have to make individual targets for each C file, and then list the header file as a dependency. You can still use your generic targets, and just place the .h dependencies afterwards, like so:

您必须为每个C文件创建单独的目标,然后将头文件列为依赖项。您仍然可以使用通用目标,之后只需放置.h依赖项,如下所示:

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

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

#5


3  

Over and above what @mipadi said, you can also explore the use of the '-M' option to generate a record of the dependencies. You might even generate those into a separate file (perhaps 'depend.mk') which you then include in the makefile. Or you can find a 'make depend' rule which edits the makefile with the correct dependencies (Google terms: "do not remove this line" and depend).

除了@mipadi所说的,你还可以探索使用'-M'选项来生成依赖关系的记录。您甚至可以将它们生成一个单独的文件(可能是“depend.mk”),然后将其包含在makefile中。或者您可以找到一个'make depend'规则,该规则使用正确的依赖关系编辑makefile(Google术语:“不要删除此行”并依赖)。

#6


3  

Basically, you need to dynamically create the makefile rules to rebuild the object files when the header files change. If you use gcc and gnumake, this is fairly easy; just put something like:

基本上,您需要动态创建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

in your makefile.

在你的makefile中。

#7


0  

None of the answers worked for me. E.g. Martin Fido's answer suggests gcc can create dependency file, but when I tried that it was generating empty (zero bytes) object files for me without any warnings or errors. It might be a gcc bug. I am on

这些答案都不适合我。例如。 Martin Fido的回答表明gcc可以创建依赖文件,但是当我尝试它为我生成空(零字节)对象文件时没有任何警告或错误。它可能是一个gcc bug。我在

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

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

So here's my complete Makefile that works for me; it's a combination of solutions + something that wasn't mentioned by anyone else (e.g. "suffix replacement rule" specified as .cc.o:):

所以这是我完整的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

Notice I used .cc .. The above Makefile is easy to adjust for .c files.

注意我使用.cc ..上面的Makefile很容易调整.c文件。

Also important to note importance of these two lines :

同样重要的是要注意这两行的重要性:

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

so gcc is called once to build a dependency file first, and then actually compiles a .cc file. And so on for each source file.

所以首先调用gcc来构建一个依赖文件,然后实际编译一个.cc文件。等等每个源文件。

#8


0  

Simpler solution: Just use the Makefile to have the .c to .o compilation rule be dependent on the header file(s) and whatever else is relevant in your project as a dependency.

更简单的解决方案:只需使用Makefile使.c到.o编译规则依赖于头文件以及项目中作为依赖项的任何其他相关内容。

E.g., in the Makefile somewhere:

例如,在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 $@ $<

#9


-1  

I believe the mkdep command is what you want. It actually scans .c files for #include lines and creates a dependency tree for them. I believe Automake/Autoconf projects use this by default.

我相信mkdep命令就是你想要的。它实际上扫描.c文件中的#include行并为它们创建依赖树。我相信Automake / Autoconf项目默认使用它。