[英]Makefile recompiles every time
我是 C 的初学者,一直在尝试解决一些与 makefile 有关的大学任务。这是一个多文件项目,想法是编译nave.c
porto.c
meteo.c
。 和master.c
。
除最后一个外,其他都需要与common_ipcs
和utils
链接,并单独编译。 也就是说,这一切似乎都工作正常,但我的问题是,如果我多次运行两个目标(调试或发布)中的任何一个,即使没有任何修改,它们也会从头开始编译所有内容。
有任何想法吗? 这是我的 makefile,删除了不相关的目标。 dbg
也被删除,因为它与rls
相同。
# basic rules
CC = gcc
LDFLAGS = -lm
COMMON = common_ipcs.c utils.c
TARGET = master
SOURCE = master.c nave.c porto.c meteo.c
# directories
DIRSRC = source
DIRHDR = headers
DIRDBG = debug
DIRRLS = release
# compiling flags
CFLAGS = -std=c89
DCFLAGS = $(CFLAGS) -g -O0 -pedantic -DDEBUG
RCFLAGS = $(CFLAGS) -O2 -Wall -Wextra -DNDEBUG
# $< is the first prerequisite
# $@ is the target
# $^ is all the prerequisites
.PHONY: all prep rls dbg drun run clean
# build all the prerequisites for compiling the project
all: clean prep rls
prep:
@mkdir -p $(DIRDBG) $(DIRRLS)
rls: $(addprefix $(DIRSRC)/, $(SOURCE))
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/nave.c -o $(DIRRLS)/nave.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/porto.c -o $(DIRRLS)/porto.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/meteo.c -o $(DIRRLS)/meteo.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/master.c -o $(DIRRLS)/$(TARGET) $(LDFLAGS)
几天来我一直在弄乱这个 makefile,它经历了难以想象的重写,此时我什至不确定该尝试什么。 与此迭代相关,我还尝试删除.PHONY
,但重新编译没有任何变化,因为我已经解释过.PHONY
还会强制重新编译所有文件。 我查看了不同的类似问题,但似乎没有一个真正适用于这个特定的 makefile 问题。
我认为您对makefile 规则是什么感到困惑。 规则由三部分组成:一个或多个目标、零个或多个先决条件以及要运行的命令配方。
Make 会将每个目标的时间戳与其列出的所有先决条件进行比较,如果任何先决条件比目标更新,它将启动一个 shell 来运行预计会使目标更新的配方。
你有这个规则:
rls: $(addprefix $(DIRSRC)/, $(SOURCE))
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/nave.c -o $(DIRRLS)/nave.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/porto.c -o $(DIRRLS)/porto.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/meteo.c -o $(DIRRLS)/meteo.o $(LDFLAGS)
$(CC) $(RCFLAGS) $(addprefix $(DIRSRC)/, $(COMMON)) $(DIRSRC)/master.c -o $(DIRRLS)/$(TARGET) $(LDFLAGS)
我们暂时忽略编译器的错误调用(您正在构建程序但将它们命名为.o
文件,这是不正确的,或者至少不是一个好主意)。
这条规则是怎么说的? 它告诉 make 有一个名为rls
的目标,它具有先决条件source/master.c
、 source/nave.c
、 source/porto.c
和source/meteo.c
,如果目标rls
已过期它应该运行一个由编译器的四次调用组成的配方,编译器将创建四个不同的程序:三个名为release/nave.o
、 release/porto.o
、 release/meteo.o
,最后一个名为release/master
。
因此,make 尽职尽责地检查磁盘上名为rls
的文件的时间戳,该文件不存在,因此永远不会被认为是最新的,并且由于它已过时,它会运行调用所有四个编译行的配方。 每次。
当您编写makefile规则时,您应该遵循以下规则:(a) 每个配方都应该只构建一个目标,不能超过一个; (b) 规则的目标名称必须是配方创建的文件的确切名称:如果配方创建了一个名为blahblah.o
的文件,那么规则的目标必须是blahblah.o
。 如果配方创建了一个名为some/other/dir/foo
的文件,那么规则的目标必须是some/other/dir/foo
。
当您在 makefile 方面做得更好时,您会意识到有时违反这些规则是有用的,也是个好主意。 但这些都是一个很好的起点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.