提问人:Lineath 提问时间:2/16/2023 更新时间:2/16/2023 访问量:72
为什么这个 Makefile 是错误的?仅当编译器错误之前出现链接器错误时,链接器才会失败
Why is this Makefile wrong? Linker fails only if preceded by compiler error
问:
这是示例程序,以便于解释。有这 4 个文件,main.c、sum.c 和 header.h。最后是 Makefile。
main.c
#include <stdio.h>
#include "header.h"
int main()
{
int a = 1;
int b = 1;
int c = sum(a, b);
printf("Sum: %i\n",c);
return (0);
}
sum.c
#include "header.h"
int sum(int a, int b)
{
return (a + b);
}
标头.h
int sum(int a, int b);
生成文件
TEST_SRCS = *.c
TEST_OBJS = $(TEST_SRCS:%.c=%.o)
%.o : %.c *.h
gcc -c $^
assemble_test: $(TEST_OBJS);
test: assemble_test
gcc -o test *.o
./test
clean:
@rm -rf *.o *.gch test
@echo "Cleaned"
重现步骤:
调用测试规则:使测试>一切正常。
故意引入任何错误,例如两个逗号:
printf("Sum: %i\n",,c);
调用测试规则:make test > 获取正常语法错误。
删除错误。保存文件。
调用测试规则:make test > 无论如何都会出现链接器错误。
gcc -o test *.o Undefined symbols for architecture x86_64: "_main", referenced from: implicit entry/start for main executable ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [test] Error 1
每次都使用干净的规则重新开始。
有一段时间了,我无法弄清楚问题所在。老实说,我是 Makefiles 的新手,所以我一定做错了什么。
关于测试规则调用assemble_test。这是因为更大的 Makefile 的一部分,我需要不同的规则来编译对象,所以不要介意。
你能帮我了解发生了什么吗?
谢谢。
答:
对目标文件使用通配符是错误的。通配符匹配运行时磁盘上已存在的文件。这无济于事,因为显然它们不会匹配尚不存在的文件,而 makefile 的全部意义在于创建不存在的文件。make
所以这个:
TEST_SRCS = *.c
TEST_OBJS = $(TEST_SRCS:%.c=%.o)
留下字符串的值和字符串的值(也许您认为通配符会以某种方式立即扩展?不,事实并非如此)。TEST_SRCS
*.c
TEST_OBJS
*.o
然后这一行:
assemble_test: $(TEST_OBJS);
使目标作为先决条件列出:这将扩展到目录中已存在的所有对象文件。但当然,它不会扩展到您想要创建但尚不存在的目标文件。assemble_test
*.o
这里还有很多其他问题:例如,您不想编译,因为这会扩展到所有先决条件,但您只想编译源文件,而不是头文件。而且添加似乎很奇怪,使事情变得更加困难。$^
assemble_test
你可能想要这个,假设你使用的是 GNU make:
TEST_SRCS := $(wildcard *.c )
TEST_OBJS = $(TEST_SRCS:%.c=%.o)
%.o : %.c *.h
gcc -c $<
test: $(TEST_OBJS)
gcc -o $@ $^
./$@
通过使用该函数,您可以先扩展源 glob 的值,然后再将结果替换为 。wildcard
.o
评论
gcc -c $^
$^
foo.c foo.h bar.h baz.h
gcc -c foo.c foo.h bar.h baz.h
$<
gcc -c foo.c
assemble_test
test: $(TEST_OBJS) ; gcc -o $@ $^
run: test ; ./$<
make run
.PHONY: run
评论