NAME = test
CC = gcc
CFLAGS = -Wall -Wextra -Werror
INC = -I ./include
FILES = test.c main.c
LIBFT = ../ft_printf/libftprintf.a
OBJ = $(addprefix build/, $(FILES:.c=.o))
SRC = $(addprefix src/, $(FILES))
all: $(NAME)
$(NAME): $(OBJ)
@$(CC) -o $(NAME) $(LIBFT) $(OBJ)
build/%.o: src/%.c | build
@$(CC) -c $(CFLAGS) $(INC) $< -o $@
build:
@mkdir build
如果您运行 Make 命令,构建的顺序是什么?我以为 all: $(NAME) 和之后 $(NAME): $(OBJ) 会被执行,但是如何知道 build/%.o: src/%.c | 构建@$(CC) -c $(CFLAGS) $(INC) $< -o $@ build: @mkdir build?
不带参数运行时
make
,执行第一个目标。虽然这样说是不对的。make
(至少)分两遍工作:首先,它找到所有依赖项(就像在图中的广度优先搜索),然后它以相反的顺序执行命令。所以第一个目标
all
。这取决于先决条件(目标)test
。“取决于”意味着为了实现目标all
,你需要实现目标test
。在这里和下面,我将扩展宏以使机制可见:目标
test
取决于build/test.o
和build/main.o
。要实现它,您需要构建两个目标文件并运行gcc
以构建可执行模块:目标
build/test.o
对应于一般规则。据他说,这取决于build/test.с
和build
。|
暂时忽略图标。通用规则生成特定规则:目标
build/main.o
的处理方式类似:目标
src/test.c
并src/main.c
没有相应的规则。在这种情况下,make
它会确保此类文件在磁盘上并将目标标记为已实现。目标
build
不依赖于任何东西,但build
如果它在磁盘上不存在,则会导致创建目录:搜索完成。现在以相反的顺序运行命令:
在图中对搜索的描述中,我省略了文件时间的比较。
make
比较目标的时间及其先决条件,如果目标是新鲜的,则认为它立即达到。您可以要求
make
显示他将执行哪些命令 (make -n
) 或解释他为什么要执行这些命令 (make --trace
)。我注意到评论中的一个重要点。
make
所有目标都被视为磁盘上的文件。如果您在磁盘上有一个文件名all
并且日期比 y 新test
,那么它会make
认为不需要做任何事情。像这样标记“非文件”的目标: