在很长一段时间没有使用 C 进行编码后,我试图创建一个简单的 makefile,但我陷入了困境。
编译后我只能访问第一个函数(这里是ft_isalpha),但我不知道为什么。
这是生成文件:
1 SRC = ft_isalpha.c \
2 ft_strlen.c
3
4 SRC_DIR = src/
5
6 SRC_PREFIXED = $(addprefix $(SRC_DIR), $(SRC))
7
8 NAME = libft.a
9
10 OBJS_DIR = objs/
11
12 OBJS = $(SRC:.c=.o)
13
14 OBJS_PREFIXED = $(addprefix $(OBJS_DIR), $(OBJS))
15
16 CC = gcc
17
18 FLAGS = -Wall -Wextra -Werror
19
20
21 $(OBJS_DIR)%.o : $(SRC_PREFIXED)
22 @mkdir -p $(OBJS_DIR)
23 gcc $(FLAGS) -c $< -o $@
24
25 $(NAME): $(OBJS_PREFIXED)
26 ar r $(NAME) $(OBJS_PREFIXED)
27 @echo $(SRC_PREFIXED)
28
29 all: $(NAME)
30
31
32 clean:
33 @rm -rf $(OBJS_DIR)
34 @echo "objects directory deleted"
35
36 fclean: clean
37 @rm -rf $(NAME)
38 @echo ".a file deleted"
我已经检查了使用这些变量生成的变量和命令行的内容,但一切看起来都很好。当我切换 ft_isalpha 和 ft_strlen 时,ft_strlen 是可访问的,而不是 isalpha ad 等等。
你的错误是...
$(OBJS_DIR)%.o : $(SRC_PREFIXED) # ... <- here (A)
@mkdir -p $(OBJS_DIR)
gcc $(FLAGS) -c $< -o $@ # ... <- and here (B)
模式规则 (A) 表示 each 目标文件
objs/(ft_isalpha.o|ft_strlen.o)
取决于所有源文件src/ft_isalpha.c
,src/ft_strlen.c
。的
当然这是假的。
那么命令(B)意味着每个目标目标文件
$@
将由
编译源文件$<
。根据
GNU Make 手册:10.5.3 自动变量,
$<
的意思是:
$<
第一个先决条件的名称。 ...[切]...
所以每个目标目标文件
objs/(ft_isalpha.o|ft_strlen.o)
都是通过编译生成的
相同源文件src/ft_isalpha.c
。
因此您创建了一个库
libft.a
,其中包含两个目标文件ft_isalpha.o
,ft_strlen.o
两者都定义了相同的函数 ft_isalpha
并且都没有定义 ft_strlen
。
您的链接将失败,并出现对
ft_strlen
的未定义引用。您的链接不会产生
ft_isalpha
的多重定义错误,因为链接器满足了程序的引用
ft_isalpha
通过提取和链接libft.a(ft_isalpha.o)
然后没有理由链接libft.a(ft_strlen.o)
:库中没有定义更多未解析的符号。
当您颠倒
ft_isalpha.c
和 ft_strlen.c
的顺序时,会发生相反的事情,因为您
观察到 - 因为所有目标文件现在都是从 ft_strlen.c
编译的。
要纠正此特定错误,请更改:
$(OBJS_DIR)%.o : $(SRC_PREFIXED)
至:
$(OBJS_DIR)%.o : $(SRC_DIR)%.c
这使得每个目标文件仅依赖于对应的源文件;第一个前提
$<
成为唯一先决条件,每个目标文件都将从正确的源进行编译。