2017-09-04 227 views
2

Makefile在第一个示例中正常工作并且绝对无法在第二个示例中工作,只是有点困惑。混淆Makefile规则

工作:

CC=gcc 
CFLAGS=-Wall -Wextra -Werror 
FILES=$(addprefix src/, ft_putnbr ft_putchar main) 
OBJ=$(addsuffix .o, $(FILES)) 
NAME=put 

$(NAME): $(OBJ) 
    $(CC) -o $(NAME) $(OBJ) 
%.o: %.c 
    gcc -c $^ -o [email protected] $(CFLAGS) -I includes/ 
clean: 
    rm -f $(OBJ) 

不工作:

CC=gcc 
CFLAGS=-Wall -Wextra -Werror 
FILES=$(addprefix obj/, ft_putnbr ft_putchar main) 
OBJ=$(addsuffix .o, $(FILES)) 
NAME=put 

$(NAME): $(OBJ) 
    $(CC) -o $(NAME) $(OBJ) 
%.o: $(subst obj,src, %.c) 
    gcc -c $^ -o [email protected] $(CFLAGS) -I includes/ 
clean: 
    rm -f $(OBJ) 

唯一的区别是FILES前缀设置为OBJ /因为我想分开OBJ从源文件文件,所以我需要使用$(替代)函数在其中一个规则中更改目录。 第二Makefile中产生:

make: *** No rule to make target 'obj/ft_putnbr.o', needed by 'put'. Stop. 

有谁看到我的错误?

回答

2

在生成文件,其受扩张的上下文是形式 $(...)${...}

的图案规则不是那些之一。所以:

%.o: %.c 
    ... 

make解释为意味着stem.ostem.c...,为stem任何价值制成,但%.o: %.c的形式$(...)的不是,这是 没有展开。

因此,在上下文中,

%.o: $(subst obj,src, %.c) 

所述的含义:

$(subst obj,src, %.c) 

很简单:字符串src替换的obj所有出现的结果%.c。 字符串%.c中没有出现obj。所以结果只是%.c, 不变。所以,你的第二个makefile文件等同于:其中,

CC=gcc 
CFLAGS=-Wall -Wextra -Werror 
FILES=$(addprefix obj/, ft_putnbr ft_putchar main) 
OBJ=$(addsuffix .o, $(FILES)) 
NAME=put 

$(NAME): $(OBJ) 
    $(CC) -o $(NAME) $(OBJ) 
%.o: %.c 
    gcc -c $^ -o [email protected] $(CFLAGS) -I includes/ 
clean: 
    rm -f $(OBJ) 

例如,目标obj/ft_putnbr.o将满足 规则%.o: %.c,当且仅当存在一个前提obj/ft_putnbr.c。 它不存在。因此:

No rule to make target 'obj/ft_putnbr.o 

而是使用:

的Makefile

CC=gcc 
CFLAGS=-Wall -Wextra -Werror 
SRCS=ft_putnbr.c ft_putchar.c main.c 
OBJS=$(addprefix obj/,$(SRCS:.c=.o)) 
NAME=put 

$(NAME): $(OBJS) 
    $(CC) -o $(NAME) $(OBJS) 

obj/%.o: src/%.c | obj 
    gcc -c $< -o [email protected] $(CFLAGS) -I includes/ 

obj: 
    mkdir -p [email protected] 

clean: 
    rm -fr obj $(NAME) 

或相似。顺便说一句,这个makefile确保目录obj存在 ,然后尝试编译任何目标文件,方法是将该目录设置为order-only prerequisite ,$(OBJS)