操作系统:Linux系统
场景:g++编译,连接动态库文件时
错误示例(中文):
/tmp/cccgNNpb.o:在函数‘main’中:
test.cpp:(.text+0x55):对‘myprint()’未定义的引用
错误示例(英文):
/tmp/cccgNNpb.o: In function 'main':
test.cpp:(.text+0x55):undifined reference to 'myprint()'
分析:命令的格式正确,怎么就会出现未定义的情况?会不会是动态库的问题,因此,先手动写个动态库进行分析
头文件yxjay.h
#ifndef __YXJAY__
#define __YXJAY__
void myprint();
#endif
源码文件yxjay.c
#include <stdio.h>
#include "yxjay.h"
void myprint()
{
printf("<span>oba没有马</span>\n");
}
测试主函数文件main.c
#include <stdio.h>
#include "yxjay.h"
int main(void)
{
myprint();
return 0;
}
编译成动态库文件:
gcc -fPIC -shared yxjay.c -o libyxjay.so
编译主函数,并连接动态库
gcc -o main main.c -L ./ -lyxjay
其中-L为指定动态库路径, ./表示当前路径,也可以用-L.表示连接到当前路径
执行命令./main
发现报以下错误:
./main: error while loading shared libraries: libyxjay.so: cannot open shared object file: No such file or directory
用ldd main查看库依赖关系ldd main
root@yxjay:~/桌面# ldd main
linux-vdso.so.1 (0x00007fff69961000)
libyxjay.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc42bf18000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc42c2c3000)
发现动态库libyxjay.so并未加载到内存中。
原因是因为gcc连接动态库又连接到系统目录去了,可以使用以下命令暂时将当前目录加到系统目录中去(当前工作路径/root/桌面,libyxjay.so存放在该目录中),但是重启后就无效
ldconfig /root/桌面
或者将libyxjay.so文件加入系统的库文件目录中,默认搜索路径(/lib或者/usr/lib)以及动态库配置文件(/etc/ld.so.conf)
再次用ldd main查看库连接关系
root@yxjay:~/桌面# ldd main
linux-vdso.so.1 (0x00007ffe405f7000)
libyxjay.so => /root/桌面/libyxjay.so (0x00007fb64a5d9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb64a22e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb64a7da000)
发现已经能找到libyxjay.so的入口了
执行命令./main也能正确显示出对应的结果
root@yxjay:~/桌面# ./main
oba没有马
前面的库文件是用gcc编译的,链接库时也是用gcc编译,那如果用g++编译连接gcc编译的库,结果如何呢?
用以下命令将main.c改成main.cpp
mv main.c main.cpp
然后用以下命令编译连接
g++ main.cpp -o main -L. -lyxjay
问题出现了:
root@yxjay:~/桌面# g++ main.c -o main -L. -lyxjay
/tmp/ccc4AcJv.o:在函数‘main’中:
main.c:(.text+0x5):对‘myprint()’未定义的引用
collect2: error: ld returned 1 exit status
居然显示未定义myprint()函数!但是明明已经在库中编译过了!!!
把main.cpp中的引用库文件代码改成extern “C"试试,改动后的代码如下:
#include <stdio.h>
extern "C"{
#include "yxjay.h"
}
int main(void)
{
myprint();
return 0;
}
再次编译
g++ main.cpp -o main -L. -lyxjay
编译成功,执行命令
root@yxjay:~/桌面# ./main
oba没有马
也能成功执行!
原因分析:gcc和g++分别对应的是C语音的变成和C++的编译,它们两者对函数名的编译方式不同,导致生成的符号也不一样,因此gcc编译的动态库和g++编译的动态库是不能完全等价的!c++调用gcc编译的动态库,头文件加上extern "C"就行,c调用g++编译的动态库??开玩笑吧!!