这是我在本网站上的第二篇文章,旨在了解与gcc的编译/链接过程。当我尝试生成可执行文件时,需要在链接时解析符号,但是当我尝试创建共享库时,在此库的链接时不会解析符号。当我尝试使用此共享库创建可执行文件时,它们可能会得到解决。动手:
bash$ cat printhello.c
#include <stdio.h>
//#include "look.h"
void PrintHello()
{
look();
printf("Hello World\n");
}
bash$ cat printbye.c
#include <stdio.h>
//#include "look.h"
void PrintBye()
{
look();
printf("Bye bye\n");
}
bash$ cat look.h
void look();
bash$ cat look.c
#include <stdio.h>
void look()
{
printf("Looking\n");
}
bash$ gcc printhello.c printbye.c
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/cck21S0u.o: In function `PrintHello':
printhello.c:(.text+0x7): undefined reference to `look'
/tmp/ccNWbCnd.o: In function `PrintBye':
printbye.c:(.text+0x7): undefined reference to `look'
collect2: ld returned 1 exit status
bash$ gcc -Wall -shared -o libgreet printhello.c printbye.c
printhello.c: In function 'PrintHello':
printhello.c:6: warning: implicit declaration of function 'look'
printbye.c: In function 'PrintBye':
printbye.c:5: warning: implicit declaration of function 'look'
所以我的问题是为什么在链接共享库时没有解析符号。当我使用这个库来制作可执行文件时,需要完成这项工作(解析其下游的符号),但这意味着我们需要知道这个库在使用这个库时所依赖的内容,但这不是不可取的吗?
谢谢, Jagrati
答案 0 :(得分:6)
在构建库时添加-z defs
是否符合要求?如果没有,请查看ld手册页,处理未定义的符号有很多选项。
答案 1 :(得分:4)
由于您没有给出-c(仅编译)选项,因此您请求gcc编译两个源文件并将它们与标准库(libc)和c运行时启动(通常为crt0)链接到制作一个正在运行的程crt0尝试通过调用main()来输入你的程序,这是链接器找不到的未定义符号。它找不到它,因为你的.c文件中没有main(),对吗?
那么,关于你的实际问题,“为什么在链接时没有解决共享库的符号?”答案是,“链接时间”是什么意思?根据定义,动态链接的程序在启动之前不会“链接”(或者甚至可能不会,直到它开始,具体取决于您的系统。)
在Linux系统上,您可以使用ldd命令查看程序所依赖的动态库(在Mac OS上使用'otool -L')。 ldd的输出将告诉你程序依赖哪些动态库,哪些在库搜索路径中找到,哪些找不到(如果有的话)。
当动态程序启动时,链接到它的动态链接器会定位并加载程序所依赖的动态库,并“修复”对外部符号的引用。如果其中任何一个失败,您的程序将无法启动。所有以前未解析的符号都已解析,动态链接器返回,C运行时将调用main()函数。 (在Mac OS上有些不同,但实际上类似,在程序启动后会发生链接。)
答案 2 :(得分:2)
我认为链接器选项-Bsymbolic
正是您所需要的。
答案 3 :(得分:0)
链接无法至少在ELF中知道符号所在的位置(即在哪些库中)。另一方面,在OS X中,您需要按照描述的方式链接库。最后,这是一个设计问题。一个更灵活,另一个更严谨。
答案 4 :(得分:0)
即使您构建共享库,它也必须解析所有依赖项。
因此,当在编译时加载共享库时,它知道在运行时加载哪些其他共享库,以便它可以解析其他依赖项。
1)使用look()
构建一个共享(look。&lt; sharedLib&gt;)库
2)使用hello()bye()链接构建一个共享(hg。&lt; sharedLib&gt;)库,以查看。&lt; sharedLib&gt;
3)使用main()构建应用程序,链接hg。&lt; sharedlib&gt;
在运行时,应用程序将加载hg。&lt; sharedlib&gt;它将实习加载共享库外观。&lt; sharedlib&gt;
答案 5 :(得分:0)
可执行文件需要entry point。但是可以在没有入口点的情况下构建共享库,之后可以使用此共享库编译可执行文件。