我有以下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,这有点痛苦。我正在寻找一种可以自己导出头文件依赖关系的解决方案,我相当肯定我已经在其他项目中看到过。答案 0 :(得分:29)
正如本网站其他地方已经指出的那样,请参阅此页面: http://make.paulandlesley.org/autodep.html
简而言之,gcc可以自动为您创建.d依赖文件,这些文件是包含您编译的.c文件的依赖项的迷你makefile片段。 每次更改.c文件并进行编译时,都会更新.d文件。
除了向gcc添加-M标志外,还需要在makefile中包含.d文件(如上面的Chris所述)。 在页面中有一些更复杂的问题,使用sed解决,但你可以忽略它们并做“清理”以清除.d文件,只要抱怨无法生成不再存在的头文件
答案 1 :(得分:20)
您可以像其他人所说的那样添加'make depend'命令,但为什么不让gcc创建依赖项并同时编译:
DEPS := $(COBJS:.o=.d)
-include $(DEPS)
%.o: %.c
$(CC) -c $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<
'-MF'参数指定用于存储依赖关系的文件。
'-include'开头的短划线告诉Make在.d文件不存在时继续(例如在第一次编译时)。
注意gcc中似乎存在关于-o选项的错误。如果您将对象文件名设置为obj/_file__c.o
,则生成的_file_.d
仍会包含_file_.o
,而不是obj/_file_c.o
。
答案 2 :(得分:16)
这相当于Chris Dodd's answer,但使用了不同的命名约定(巧合的是不需要sed
魔法。从a later duplicate复制。
如果您使用的是GNU编译器,编译器可以为您组装一个依赖项列表。 Makefile片段:
depend: .depend
.depend: $(SOURCES)
rm -f ./.depend
$(CC) $(CFLAGS) -MM $^>>./.depend;
include .depend
还有工具makedepend
,但我从不喜欢它gcc -MM
答案 3 :(得分:7)
您必须为每个C文件制作单独的目标,然后将头文件列为依赖项。您仍然可以使用通用目标,然后放置.h
依赖项,如下所示:
%.o: %.c
@echo Compiling $<...
$(CC) $(CFLAGS) -c -o $@ $<
foo.c: bar.h
# And so on...
答案 4 :(得分: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
在您的makefile中。
答案 5 :(得分:3)
除了@mipadi所说的,你还可以探索使用'-M
'选项来生成依赖关系的记录。您甚至可以将它们生成一个单独的文件(可能是“depend.mk”),然后将其包含在makefile中。或者,您可以找到一个“make depend
”规则,该规则使用正确的依赖项编辑makefile(Google术语:“不删除此行”并依赖)。
答案 6 :(得分:0)
这些答案都不适合我。例如。 Martin Fido的回答表明gcc可以创建依赖文件,但是当我尝试它时,它为我生成空(零字节)对象文件而没有任何警告或错误。它可能是一个gcc bug。我在
$ gcc --version gcc(GCC)4.4.7 20120313(Red Hat 4.4.7-16)
所以,这是我完整的Makefile,对我有用;它是解决方案的组合+其他任何人都没有提到的东西(例如&#34;后缀替换规则&#34;指定为.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
注意我使用.cc ..上面的Makefile很容易调整.c文件。
同样重要的是要注意这两行的重要性:
$(CC) $(CFLAGS) $(INCLUDES) -c -MM -MF $(patsubst %.o,%.d,$@) $<
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
因此首先调用gcc一次构建一个依赖文件,然后实际编译一个.cc文件。等等每个源文件。
答案 7 :(得分: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 $@ $<
答案 8 :(得分:-1)
我相信mkdep
命令就是你想要的。它实际上扫描.c文件中的#include
行,并为它们创建依赖树。我相信Automake / Autoconf项目默认使用它。