您的位置:首页 > 运维架构 > Linux

linux下动态链接和静态链接

2014-02-12 12:45 148 查看
在linux下的c++编程中,存在两种链接方式,动态链接和静态链接,

假设test1.cpp中的代码如下:

#include<stdio.h>

void myFunction()
{
  printf("this is a test function\n");
}

int f()
{
return 3;
}


test2.cpp中的代码如下:

#include<stdio.h>

int g()
{
return 4;
}


app.cpp中的代码如下所示:

#include<stdio.h>

extern int f();
extern int g();

int main()
{
int res = f();
printf("%d\n",res);
res = g();
printf("%d\n",res);
return 0;
}


  可以看到app.cpp中分别调用了test1.cpp中的f()函数和test2.cpp中的g()函数,如果要通过静态链接来生成可执行文件app可以由以下步骤,首先将test1.cpp,test2.cpp编译成目标.o文件

  g++ -c test1.cpp

  g++ -c test2.cpp

  然后将生成的test1.o和test2.o打包成一个静态库.a文件,ar cr libtest.a test1.0 test2.o

  最后将生成的静态库文件include到app中就可以了,注意-ltest要写在最后面,因为g++在第一次遇到-ltest的时候就会搜寻test静态库文件中是否存在需要的函数或变量.

  g++ -o app app.cpp -L. -ltest //ok

  g++ -o app -L. -ltest app.cpp //error,会显示找不到这两个文件

  最终生成的app可执行文件就会将test静态库中用到的test1.o和test2.o都包含进来

  至于动态库文件,在生成test1.o,test2.o的时候要加入一个参数-fPIC(position independent code,位置独立代码),这个参数高数g++编译器,该生成的目标文件要作为一个动态共享库的一部分.然后用g++ -shared -fPIC libtest.so test1.o test2.o生成动态共享库libtest.so,g++ -o app app.cpp -L. -ltest

  编译器搜寻库的路径,首先搜寻-L选项后的参数目录,然后搜寻系统的搜索路径,直至找到需要的库,若同名的动态库和静态库在不同的目录中,则编译器先找到哪个库就用该库,若一个目录中同时存在动态库和静态库,编译器优先选择动态库,如果想固定只使用静态库,就可以加一个-static选项.即g++ -static -o app app.cpp -L. -ltest

  当系统在运行由动态链接库生成的可执行文件时,可执行文件中只包含了动态链接库的名称,而没有这些动态链接库的路径信息,因此系统会在默认的路径/lib和/usr/lib中搜寻动态链接库,如果需要的动态链接库不在这些目录中,可执行文件就无法正确执行,因此解决方法之一就是在编译链接生成可执行文件时加上-Wl,-rpath 库的路径目录,如g++ -o app app.cpp -L. -ltest -Wl,-rpath,/usr/local/lib,这样当生成的app在执行时会自动去/usr/local/lib下寻找需要的动态库.另外一种解决的方法是在环境变量LD_LIBRARY_PATH中加入库路径

  ldd命令可以查看可执行文件中需要的动态库.

  库与库之间有时也存在相互依赖关系,若是动态链接,链接器在链接时能自动链接到需要依赖的库,若是加上-static选项要进行静态链接,则需要依次将需要依赖的库列举出来.并且如果存在互相依赖的情况,则有时候需要多次列举相同的库名,如g++ -o app app.cpp -L. -lfoo -lbar -l foo,此时若libfoo.a和libbar.a存在互相依赖情况,也能够正常的链接并生成.

  在程序中也可以直接load动态链接库并调用库中定义好的函数,需要用到的函数是dlopen,在编译时需要链接dl库,即加上-ldl参数,相关代码如下,注意此时需要对test1.cpp和test2.cpp中的函数都改成类似extern "C" void myFunction()的形式,否则在动态库中会无法找到该函数:

#include<stdio.h>
#include<dlfcn.h>

int main()
{
void* handle = dlopen("libtest.so",RTLD_LAZY);
char *lError = dlerror();//查看加载动态库过程中的错误信息

if(lError)
{
printf("error:%s\n",lError);
}
void (*test)() = (void(*)())dlsym(handle,"myFunction");//test函数指针指向test1.cpp中的myFunction函数

lError = dlerror();
if(lError)
{
printf("error:%s\n",lError);
}
(*test)();//执行myFunction()函数

int (*test1)() = (int(*)())dlsym(handle,"f");//test1指针指向test1.cpp中的f()函数,注意dlsym返回的是void* 指针类型,要进行强制类型转换

lError = dlerror();

if(lError)
{
printf("error:%s\n",lError);
}

int res = (*test1)();//执行f()函数,将函数运行结果返回给res变量
printf("res=%d\n",res);
dlclose(handle);

return 0;
}


运行结果:

this is a test function
res=3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: