当头文件更改时,GNU-Make 不会重新编译
GNU-Make does not recompile when a header file changed
当 hdr.h 文件更改时,GNU-Make 不会重新编译。
如下所示,即使生成了 main.d 文件,它也没有尝试重新编译。
你能告诉我为什么会这样吗?
hdr.h
#ifndef __HDR_H__
#define LOOP_CNT 1000
#endif /* __HDR_H__ */
main.c
#include <stdio.h>
#include "hdr.h"
int main(void)
{
int i, sum = 0;
for (i = 0; i < LOOP_CNT; i++) sum += i;
(void)printf("sum = %d\n", sum);
return 0;
}
生成文件
SUFFIXES += .d
.PHONY: clean
OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))
CC = armcc
LD = armcc
CFLAGS +=
# Default target
all: sum
sum : $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
# Generating dependency files
%.d : %.c
@$(CC) -M $< > $@
# Include dependency file to have gcc recompile necessary sources
include $(patsubst %.c,%.d,$(wildcard *.c))
#$(info $(patsubst %.c,%.d,$(wildcard *.c)))
clean:
rm -f *.o *.d core $(EXEC_NAME)
这是秒打印的行。
C:\project\dep>make all
Makefile:24: main.d: No such file or directory
armcc -o main.o -c main.c
armcc -o sum main.o
C:\project\dep>make all
make: Nothing to be done for `all'.
main.d 文件生成如下。
__image.axf: main.c
__image.axf: C:\Program Files\ARM\RVCT\Data.13\include\windows\stdio.h
__image.axf: hdr.h
你在构建之前尝试过 make clean 吗?
清理和构建应该有效
一般来说,如果一个源文件需要编译生成目标文件,那么它的依赖文件也需要重新构建。
因此,不用为 .d
文件设置单独的目标,而是在编译时简单地重新生成它。为此,一个简单的方法是替换
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
# Generating dependency files
%.d : %.c
@$(CC) -M $< > $@
和
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
@$(CC) -M $< > $@
注意只有编译成功才会重新生成依赖文件。如果编译失败,目标文件将被删除,所以无论依赖文件是否是最新的,都会强制重新编译。
作为一个快速而肮脏的 Makefile 修复程序,用于在头文件更改时重建,我只是列出了我所有的头文件,然后将 $(HEADERS)
作为依赖项添加到从 C src 文件构建目标文件的部分中。它的效率不如预期,但我发现它已经足够好了,即
HEADERS = \
my_header.h \
my_other_header.h
$(BUILD_DIR)/%.o: %.c $(HEADERS)
$(LINK.c) $< -c -o $@
要让它在头文件更改时重建您的依赖文件,您可以将它们的构建规则更改为如下所示:
%.d : %.c
$(CC) -M $< > $@
@$(CC) -M $< -MT $*.d >> $@
因为这还将附加到依赖性规则,即 .d 文件是从 .c 和 .h 文件构建的。
至于如何让它们首先(重新)构建 - 如果您的 make 版本太旧并且不会自动(重新)构建它们,您可以有这样的东西:
all: depend subs
depend: $(patsubst %.c,%.d,$(wildcard *.c))
(顺便说一句,我认为如果它在变量 BTW 中看起来会更干净并且效率更高)
或者像这样向对象构建添加依赖:
$(OBJECTS) : %.o : %.c %.d
$(CC) $(CFLAGS) -o $@ -c $<
但这两种解决方案都需要您 运行 进行两次,否则不会 include
更改
Makefile 的问题是:
不正确:
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
正确(注意添加的 %.d 依赖项,%.c 不能被删除):
$(OBJECTS) : %.o : %.c %.d
$(CC) $(CFLAGS) -o $@ -c $<
依赖链是这样的:
all
+->sum
+->x.o
+->x.c
---------------------------------
x.d
+->x.c
[generate rule: "x.d: x.c x.h"]
after include:
x.d
+->x.c
+->x.h
在原始版本中,%.d
规则被触发,我猜 include
指令负责(没有它, %.d
-s 将不会被构建) .但即使它们被触发,也没有任何东西将它们连接到 %.o
文件。因此,即使重建它们,由于更改了 %.h
个文件,也没有到 %.o
个文件的依赖链。
连接依赖链解决了这个问题。
请注意 运行 clean
之后更正后的 Makefile
将生成如下错误消息:
Makefile:123: x.d: No such file or directory
如 make docs 中所述,当 include
找不到 Makefile
时,它会发出错误消息,但此时它不认为这是致命错误并尝试找到创建丢失文件的规则。
正在添加
$(info $(shell ls))
目标文件创建/链接配方可以确认当时规则确实存在。
当 hdr.h 文件更改时,GNU-Make 不会重新编译。 如下所示,即使生成了 main.d 文件,它也没有尝试重新编译。 你能告诉我为什么会这样吗?
hdr.h
#ifndef __HDR_H__
#define LOOP_CNT 1000
#endif /* __HDR_H__ */
main.c
#include <stdio.h>
#include "hdr.h"
int main(void)
{
int i, sum = 0;
for (i = 0; i < LOOP_CNT; i++) sum += i;
(void)printf("sum = %d\n", sum);
return 0;
}
生成文件
SUFFIXES += .d
.PHONY: clean
OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))
CC = armcc
LD = armcc
CFLAGS +=
# Default target
all: sum
sum : $(OBJECTS)
$(CC) $(CFLAGS) -o $@ $^
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
# Generating dependency files
%.d : %.c
@$(CC) -M $< > $@
# Include dependency file to have gcc recompile necessary sources
include $(patsubst %.c,%.d,$(wildcard *.c))
#$(info $(patsubst %.c,%.d,$(wildcard *.c)))
clean:
rm -f *.o *.d core $(EXEC_NAME)
这是秒打印的行。
C:\project\dep>make all
Makefile:24: main.d: No such file or directory
armcc -o main.o -c main.c
armcc -o sum main.o
C:\project\dep>make all
make: Nothing to be done for `all'.
main.d 文件生成如下。
__image.axf: main.c
__image.axf: C:\Program Files\ARM\RVCT\Data.13\include\windows\stdio.h
__image.axf: hdr.h
你在构建之前尝试过 make clean 吗? 清理和构建应该有效
一般来说,如果一个源文件需要编译生成目标文件,那么它的依赖文件也需要重新构建。
因此,不用为 .d
文件设置单独的目标,而是在编译时简单地重新生成它。为此,一个简单的方法是替换
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
# Generating dependency files
%.d : %.c
@$(CC) -M $< > $@
和
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
@$(CC) -M $< > $@
注意只有编译成功才会重新生成依赖文件。如果编译失败,目标文件将被删除,所以无论依赖文件是否是最新的,都会强制重新编译。
作为一个快速而肮脏的 Makefile 修复程序,用于在头文件更改时重建,我只是列出了我所有的头文件,然后将 $(HEADERS)
作为依赖项添加到从 C src 文件构建目标文件的部分中。它的效率不如预期,但我发现它已经足够好了,即
HEADERS = \
my_header.h \
my_other_header.h
$(BUILD_DIR)/%.o: %.c $(HEADERS)
$(LINK.c) $< -c -o $@
要让它在头文件更改时重建您的依赖文件,您可以将它们的构建规则更改为如下所示:
%.d : %.c
$(CC) -M $< > $@
@$(CC) -M $< -MT $*.d >> $@
因为这还将附加到依赖性规则,即 .d 文件是从 .c 和 .h 文件构建的。
至于如何让它们首先(重新)构建 - 如果您的 make 版本太旧并且不会自动(重新)构建它们,您可以有这样的东西:
all: depend subs
depend: $(patsubst %.c,%.d,$(wildcard *.c))
(顺便说一句,我认为如果它在变量 BTW 中看起来会更干净并且效率更高)
或者像这样向对象构建添加依赖:
$(OBJECTS) : %.o : %.c %.d
$(CC) $(CFLAGS) -o $@ -c $<
但这两种解决方案都需要您 运行 进行两次,否则不会 include
更改
Makefile 的问题是:
不正确:
$(OBJECTS) : %.o : %.c
$(CC) $(CFLAGS) -o $@ -c $<
正确(注意添加的 %.d 依赖项,%.c 不能被删除):
$(OBJECTS) : %.o : %.c %.d
$(CC) $(CFLAGS) -o $@ -c $<
依赖链是这样的:
all
+->sum
+->x.o
+->x.c
---------------------------------
x.d
+->x.c
[generate rule: "x.d: x.c x.h"]
after include:
x.d
+->x.c
+->x.h
在原始版本中,%.d
规则被触发,我猜 include
指令负责(没有它, %.d
-s 将不会被构建) .但即使它们被触发,也没有任何东西将它们连接到 %.o
文件。因此,即使重建它们,由于更改了 %.h
个文件,也没有到 %.o
个文件的依赖链。
连接依赖链解决了这个问题。
请注意 运行 clean
之后更正后的 Makefile
将生成如下错误消息:
Makefile:123: x.d: No such file or directory
如 make docs 中所述,当 include
找不到 Makefile
时,它会发出错误消息,但此时它不认为这是致命错误并尝试找到创建丢失文件的规则。
正在添加
$(info $(shell ls))
目标文件创建/链接配方可以确认当时规则确实存在。