我有以下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
我对makefile的主要问题是,当我修改一个或多个C文件包含的头文件时,不会重建C文件 . 通过让我的所有头文件都是我所有C文件的依赖项,我可以很容易地解决这个问题,但是这会在我更改/添加头文件时有效地导致项目的完全重建,这不会非常优雅 .
我想要的只是包含我改变的头文件的C文件重建,以及整个项目再次链接 . 我可以通过使所有头文件成为目标的依赖项来进行链接,但是当我们包含的头文件较新时,我无法弄清楚如何使C文件失效 .
我听说GCC有一些命令可以使这成为可能(因此makefile可以以某种方式找出需要重建的文件)但我不能在我的生活中找到一个实际的实现示例来查看 . 有人可以发布一个解决方案,在makefile中启用此行为吗?
编辑:我应该澄清,我熟悉将各个目标放入并拥有每个目标的概念.o需要头文件 . 这要求我每次在某处包含头文件时都要编辑makefile,这有点痛苦 . 我正在寻找一个可以自己派生头文件依赖的解决方案,我相当肯定我已经在其他项目中看到了 .
9 回答
正如本网站其他地方已经指出的那样,请参阅此页:http://make.paulandlesley.org/autodep.html
简而言之,gcc可以自动为您创建.d依赖文件,这些文件是包含您编译的.c文件的依赖项的迷你makefile片段 . 每次更改.c文件并进行编译时,都会更新.d文件 .
除了向gcc添加-M标志外,还需要在makefile中包含.d文件(如上面的Chris所述) . 在页面中有一些更复杂的问题,使用sed解决,但你可以忽略它们并做“清理”以清除.d文件,只要抱怨无法生成不再存在的头文件 .
您可以像其他人所说的那样添加'make depend'命令,但为什么不让gcc创建依赖项并同时编译:
'-MF'参数指定用于存储依赖项的文件 .
'-include'开头的破折号告诉Make在.d文件不存在时继续(例如在第一次编译时) .
注意gcc中似乎存在关于-o选项的错误 . 如果将对象文件名设置为
obj/_file__c.o
,则生成的_file_.d
仍将包含_file_.o
,而不是obj/_file_c.o
.这相当于Chris Dodd's answer,但使用了不同的命名约定(巧合的是不需要
sed
magic . 从a later duplicate复制 .如果您使用的是GNU编译器,编译器可以为您组装一个依赖项列表 . Makefile片段:
还有工具
makedepend
,但我从来没有像gcc -MM
那样喜欢它您必须为每个C文件创建单独的目标,然后将头文件列为依赖项 . 您仍然可以使用通用目标,之后只需放置
.h
依赖项,如下所示:除了@mipadi所说的,你还可以探索使用'
-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
'规则来编辑带有正确依赖关系的makefile(Google术语:"do not remove this line"和depend) .基本上,您需要动态创建makefile规则,以便在头文件更改时重建目标文件 . 如果你使用gcc和gnumake,这很容易;只是说:
在你的makefile中 .
这些答案都不适合我 . 例如 . Martin Fido的回答表明gcc可以创建依赖文件,但是当我尝试它为我生成空(零字节)对象文件时没有任何警告或错误 . 它可能是一个gcc bug . 我在
所以这是我完整的Makefile,对我有用;它是解决方案的组合其他人没有提到的东西(例如“后缀替换规则”指定为.cc.o :):
注意我使用.cc ..上面的Makefile很容易调整.c文件 .
同样重要的是要注意这两条线的重要性:
所以首先调用gcc来构建一个依赖文件,然后实际编译一个.cc文件 . 等等每个源文件 .
更简单的解决方案:只需使用Makefile使.c到.o编译规则依赖于头文件以及项目中作为依赖项的任何其他相关内容 .
例如,在Makefile中的某个地方:
我相信
mkdep
命令就是你想要的 . 它实际上会扫描.c文件中的#include
行并为它们创建依赖关系树 . 我相信Automake / Autoconf项目默认使用它 .