我刚刚学习如何创建makefile并意识到规则的先决条件中的头文件和目标文件的顺序很重要,但我不明白为什么.
我和许多同学一起研究和交谈,并且有很多猜测,但没有人有答案.
我知道在编译的预处理步骤中,头文件和源文件中的代码都包含在目标文件中,所以如果我将目标文件和头文件作为先决条件传递,为什么这很重要?
我问,因为如果缺少头文件,我的Makefile不应该编译.
这是代码:
CC = gcc
SRC = main.c file1.c
OBJ = $(SRC:.c=.o)
NAME = my_executable
all: header.h $(OBJ)
$(CC) $(OBJ) -o $(NAME)
Run Code Online (Sandbox Code Playgroud)
我[...]意识到规则先决条件中的头文件和目标文件的顺序很重要,但我不明白为什么?
make按照它们在Makefile中出现的顺序处理每个目标的依赖关系的典型实现.当这样make构建你的例子Makefile的"所有"目标时,它会hello.h在列出的任何文件之前检查依赖关系$(OBJ).由于没有构建它的规则,make如果该文件尚不存在,则会失败.根据实现和配置,它可能会或可能不会尝试构建先决条件$(OBJ).
另一方面,如果在其他先决条件之后列出标题make,则按顺序处理先决条件的过程将尝试在检查标题之前构建缺少或过期的任何对象文件.
我问,因为如果缺少头文件,我的Makefile不应该编译.
往上看.但也确实理解你是在依靠kludge.您Makefile的缺陷在于它不能正确表达项目的依赖关系.的all目标是合成的; 它本身并不依赖于任何标题.我想这是部分或全部$(OBJ)文件.因此,您应该表达这些依赖关系.如果没有这样做,那么如果构建项目然后修改了标头,make则会重建目标文件,尽管它会重新链接它们.
假设所有目标文件都依赖于头文件,我会修改Makefile,如下所示:
CC = gcc
SRC = main.c file1.c
OBJ = $(SRC:.c=.o)
NAME = my_executable
all: $(NAME)
$(NAME): $(OBJ)
$(CC) $(OBJ) -o $@
$(OBJ): header.h
Run Code Online (Sandbox Code Playgroud)
最后一行表示命名的每个目标都$(OBJ)取决于header.h.该$(NAME)规则说,真正的目标$(NAME)依赖于所有对象.有了这个,如果header.h更改然后make将重建目标文件,但同时,如果没有任何变化,那么make将什么也不做,甚至不重新链接主可执行文件.如果缺少标头,则不会尝试构建任何目标文件,因此也不会构建主可执行文件.