为什么 Make 不为隐式规则定义 LD 变量?
Why doesn't Make define a LD variable for implicit rules?
我目前正在学习汇编。我编写了简单的测试程序,所以我整理了一个简单的 makefile :
AS = nasm
CC = ld
ASFLAGS = -f elf64
all: hello_name put_digit
hello_name: hello_name.o
put_digit: put_digit.o
clean:
${RM} *.o
fclean: clean
${RM} hello_name put_digit
.PHONY: all clean fclean
我一直认为隐式规则并不是很有用,因为你最终会在任何实质性项目中重写规则。但是尝试在试验时快速建立一个 makefile 对他们来说似乎是一个很好的用例,而不是编写构建脚本。所以我在这里使用它们。
发现没有 LD 变量是多么令人沮丧,所以我不得不破解 CC
以获得 ld
。
隐式规则也不考虑 .asm
文件,所以我必须将它们伪装成 .s
文件,尽管我使用的是 intel
/nasm
语法。
这是否有任何 good/historical 原因,或者隐含规则是半生不熟的东西?
有一个内置和定义的LD
变量,只是它没有用在这个隐式规则中。规则本身是:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
其中 LINK.o
被定义为
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
我相信这是正确的做法。编译器驱动程序应该像一般情况一样调用 运行 链接器(除非您使用自定义链接脚本)它还包括一些编译器提供的启动文件,否则您需要自己指定,这是特定于编译器。
考虑这个简单的例子:
$ cat hello.c
int main(int argc, char *argv[]) {
return 0;
}
有人可能认为这是一个完整的程序,但事实并非如此。它编译的平台需要一些额外的准备工作。事实上,链接器本身会发出警告:
$ gcc -c hello.c
$ ld -o hello hello.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ./hello
Segmentation fault
使用编译器驱动程序时,它会向链接器提供一堆选项和启动文件:
$ gcc -Wl,-v -o hello hello.o
collect2 version 9.3.0
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccRdkBP1.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. -v hello.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.34
$ ./hello
$ echo $?
0
因此最终的 hello
二进制文件链接自 Scrt1.o
、crti.o
、crtbeginS.o
、hello.o
、crtendS.o
、crtn.o
,其中大部分是由编译器提供的。这些是二进制文件工作所必需的。
您的具体示例使用了不同的工具,这些工具可能与此方法不兼容。这不会使隐式规则“半生不熟”,并且随时欢迎您自己定义链接规则以匹配所使用的工具集。
我目前正在学习汇编。我编写了简单的测试程序,所以我整理了一个简单的 makefile :
AS = nasm
CC = ld
ASFLAGS = -f elf64
all: hello_name put_digit
hello_name: hello_name.o
put_digit: put_digit.o
clean:
${RM} *.o
fclean: clean
${RM} hello_name put_digit
.PHONY: all clean fclean
我一直认为隐式规则并不是很有用,因为你最终会在任何实质性项目中重写规则。但是尝试在试验时快速建立一个 makefile 对他们来说似乎是一个很好的用例,而不是编写构建脚本。所以我在这里使用它们。
发现没有 LD 变量是多么令人沮丧,所以我不得不破解 CC
以获得 ld
。
隐式规则也不考虑 .asm
文件,所以我必须将它们伪装成 .s
文件,尽管我使用的是 intel
/nasm
语法。
这是否有任何 good/historical 原因,或者隐含规则是半生不熟的东西?
有一个内置和定义的LD
变量,只是它没有用在这个隐式规则中。规则本身是:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
其中 LINK.o
被定义为
# default
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
我相信这是正确的做法。编译器驱动程序应该像一般情况一样调用 运行 链接器(除非您使用自定义链接脚本)它还包括一些编译器提供的启动文件,否则您需要自己指定,这是特定于编译器。
考虑这个简单的例子:
$ cat hello.c
int main(int argc, char *argv[]) {
return 0;
}
有人可能认为这是一个完整的程序,但事实并非如此。它编译的平台需要一些额外的准备工作。事实上,链接器本身会发出警告:
$ gcc -c hello.c
$ ld -o hello hello.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ./hello
Segmentation fault
使用编译器驱动程序时,它会向链接器提供一堆选项和启动文件:
$ gcc -Wl,-v -o hello hello.o
collect2 version 9.3.0
/usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccRdkBP1.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. -v hello.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.34
$ ./hello
$ echo $?
0
因此最终的 hello
二进制文件链接自 Scrt1.o
、crti.o
、crtbeginS.o
、hello.o
、crtendS.o
、crtn.o
,其中大部分是由编译器提供的。这些是二进制文件工作所必需的。
您的具体示例使用了不同的工具,这些工具可能与此方法不兼容。这不会使隐式规则“半生不熟”,并且随时欢迎您自己定义链接规则以匹配所使用的工具集。