我刚刚学习如何创建makefile并意识到规则先决条件中的头文件和目标文件的顺序很重要,但我不明白为什么。
我和许多同学一起研究和交谈,并且有很多猜测,但没有人有答案。
我知道在编译的预处理步骤中,头文件和源文件中的代码都包含在目标文件中,所以如果我将目标文件和头文件作为先决条件传递,为什么这很重要?
我问,因为如果缺少头文件,我的Makefile就不应该编译。
以下是代码:
CC = gcc
SRC = main.c file1.c
OBJ = $(SRC:.c=.o)
NAME = my_executable
all: header.h $(OBJ)
$(CC) $(OBJ) -o $(NAME)
答案 0 :(得分:7)
我[...]意识到了这个顺序 规则先决条件中的标题和目标文件很重要,但我确实如此 不明白为什么?
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
最后一行表示$(OBJ)
中指定的每个目标都取决于header.h
。 $(NAME)
规则表明真实目标$(NAME)
取决于所有对象。有了这个,如果header.h
发生了变化,那么make将重建目标文件,但同时,如果 nothing 发生变化,那么make将不会做任何事情,甚至不会重新链接主可执行文件。如果缺少标题,则不会尝试构建任何目标文件,也不会构建主可执行文件。