问题描述:
今天在复习C的链接(静态链接,动态链接,混合链接)的时候出现了一点小问题,事情起因是这样的,我先熟悉了一下动态库的编译以及调用指令。
gcc -o libhello.so -fPIC -shared hello.c
gcc -o main main.c -L./ -lhello
LD_LIBRARY_PATH=/home/Desktop/helloworld ./main
然后能够成功调用,于是我将so文件删除之后准备尝试一下打包静态库
ar crv libhello.a hello.c
命令执行之后,确实也是成功生成了静态库文件libhello.a,但是接下来我去调用的时候就发现不对劲了
gcc -o main2 main.c -L./ -lhello
./main2
当我运行main2的时候出现了报错:
/usr/bin/ld: /home/chenqi/Desktop/helloworld/libhello.a: error adding symbols: archive has no index; run ranlib to add one
collect2: error: ld returned 1 exit status
于是我根据报错信息在网上搜寻解决办法,尝试了很多办法都没有反应,最后是看到了有位大佬的文章我才明白我哪里出现了错误。点这里
我再检查了我的静态库文件是否可用的时候突然发现,我打包的文件是hello.c而不是hello.o,于是我重新将hello.o打包后发现后续运行就不会出现报错了。
ar crv libhello.a hello.o
gcc -o main2 main.c -L./ -lhello
./main2
原因分析:
那为什么会出现这种情况呢,明明动态库可以用*.c打包而到了静态库就不行了呢。后来去查阅了资料才知道原因。
-
动态库的编译和链接特性:
- 编译动态库时,会生成一个包含编译后代码和符号信息的
.so
文件。这个文件在运行时被动态加载到内存中,因此需要包含完整的编译后的二进制代码和符号信息。 - 链接动态库时,动态链接器(如
ld.so
)能够在程序运行时正确地加载和链接动态库,因为动态库本身就是一个完整的可执行二进制文件。
- 编译动态库时,会生成一个包含编译后代码和符号信息的
-
静态库的编译和链接特性:
- 编译静态库时,使用
ar
命令将多个编译后的目标文件(.o
文件)打包成一个.a
文件。这个过程仅仅是将多个目标文件打包在一起,不包含编译后的二进制代码和符号信息。 - 链接静态库时,链接器需要从静态库中提取编译后的目标文件,然后将它们与主程序或其他目标文件链接在一起形成最终的可执行文件。因此,静态库在
ar
命令时必须使用编译后的.o
文件,而不是源文件.c
。
- 编译静态库时,使用
总结来说就是动态库和静态库在编译时的处理方式不同,动态库需要包含完整的编译后二进制代码和符号信息,因此可以直接使用源文件(.c
文件)进行编译。而静态库在编译时只是打包了编译后的目标文件,需要在链接时提供这些目标文件,所以必须使用编译后的 .o
文件来创建静态库。
至此,如果你的问题也是和我一样没有弄清楚动态库和静态库的不同的编译处理方式的话,那问题应该解决了,如果没有,欢迎讨论!