[英]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.