繁体   English   中英

Makefile 每次都重新编译

[英]Makefile recompiles every time

我是 C 的初学者,一直在尝试解决一些与 makefile 有关的大学任务。这是一个多文件项目,想法是编译nave.c porto.c meteo.c master.c

除最后一个外,其他都需要与common_ipcsutils链接,并单独编译。 也就是说,这一切似乎都工作正常,但我的问题是,如果我多次运行两个目标(调试或发布)中的任何一个,即使没有任何修改,它们也会从头开始编译所有内容。

有任何想法吗? 这是我的 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.csource/nave.csource/porto.csource/meteo.c ,如果目标rls已过期它应该运行一个由编译器的四次调用组成的配方,编译器将创建四个不同的程序:三个名为release/nave.orelease/porto.orelease/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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM