Linux下C/C++如何使用共享库so

 从源代码到可执行程序,通常要经过最重要的两大步是:编译,链接。编译就是将源文件生成中间文件的过程,在linux下就是生成   .obj  文件。链接就是用链接器将,这些个中间文件有序地”糅合“在一起,构成一个可执行文件。通常,一个.c文件或者.cpp源文件编译后,就会对应生成一个.obj文件。     
     那么库文件是什么东西呢?其实库文件就是将这些中间文件.obj进行打包生成的文件。那么为什么要将这些obj文件打包成库文件呢?一个很重要的原因是,方便代码复用。通常,我们都会有自己写的一些公用的函数,一般是一些工具类的函数。然后再不同的项目中,经常会引用到这些公用的函数。显而易见的做法是,将公用函数的.h文件和.cpp文件分别丢到某个项目的.h文件目录或.cpp文件目录中,编译的时候也跟对待其他的源文件一样调用g++或者gcc进行编译。如果是引用的第三方文件不多还好,要是使用到了一些大型的第三方库比如zlib,openssl等,那么编译这些库都得花很长的时间。
     那么那些懒的程序员就想到了一个办法,只编译一次,并将这些第三方库编译后生成的中间文件全部保留下来,下次可以直接用了。那么又来了个问题,加入某个第三方库有许多源文件,那岂不是要保存好多.obj文件??至少看起来,目录都是乱糟糟的。因此,就想到了一个办法将这些个.obj文件打包起来放在一起,也就产生了所谓的库文件。
     链接的时候又有问题了,如果这些第三方库很大或者很多,直接将项目自己的中间文件跟第三方库文件链接成可执行程序,最终这个程序一定非常臃肿,挺占空间。而且关键是,执行程序的时候,会将程序丢到内存里去,那么如果多个程序同时调用了这些第三方库,那么在内存里,可能会存在两份第三方库的拷贝,貌似挺占内存。好的,聪明的程序员又想到好办法了,生成动态库,链接的时候不会将第三库文件”糅合“进可执行程序中,程序占的硬盘变小了。第二,当程序运行时,会将第三方库丢进内存中,但是如果有多个程序也动态链接了这个第三方库,内存中只会有一份拷贝,也就是多个程序共享一个第三方库,哈,内存占用解决了。

一、制作库文件
     1,制作静态库文件
          使用linux下的ar命令可以打包中间文件生成静态库文件。通过man ar查看ar的具体用法。一般可以使用 ar -crv 来产生静态库。比如:
          g++ -g -c add.cpp  生成add.o
          g++ -g -c sub.cpp  生成sub.o
          ar -crv libmymth.a add.o sub.o生成归档文件,也就是我们的静态库文件。
     2 ,制作动态库文件
          g++ -fPIC -g -c add.cpp 生成add.o
          g++ -fPIC -g -c sub.cpp 生成sub.o
          -fPIC选项是为了生成与地址无关的编译程序,这样让中间文件能够在多个程序中共享
          g++ -shared -o libmymath.so add.o sub.o 生成相应的动态库
          或者直接合成一步:
          g++ -shared -fPIC -o libmymath.so add.cpp sub.cpp

 二、使用库文件
    动态库或者静态库都可以在链接的时候,使用 -l 进行链接。但是要注意的是,-l 选项只会在特定的目录里去寻找指定的库文件。这些特定的目录指的是 /usr/lib,还有$LD_LIBRARY_PATH指定的路径,还有ld.so.cache中的缓存内容。其中ld.so.cache是通过ldconfig命令来生成的,改命令会读取 /etc/ld.so.conf文件中的目录列表,并写入ld.so.cache文件中。
     因此常规的做法是,将生成的库文件直接丢到 /usr/lib下,或者放到$LD_LIBRARY_PATH的某一个目录中,或者再/etc/ld.so.conf中配置库文件所在的目录。这样链接器就可以找到库文件。
     特别的,对于动态库。程序在运行的时候还会寻找动态库文件,如果链接的时候存在动态库而运行的时候不存在动态库,也会报错。静态库就不一样,只要链接的时候存在库文件就行了,应为库文件和其他中间文件一起打包进了最终的二进制文件。
     例子:
          假设你把生成的库文件放到了上述链接器可以找到的地方,那么你可以这样链接你的程序:
               g++ -o main main.o -lmymath  
          
          另外g++提供了一个 -L选项用来指定库文件的目录,例如假设你的库文件放在了 /root/data/lib下,那么你可以这样链接你的程序:
               g++ -o main main.o -L/root/data/lib -lmymath
          这样链接后生成的程序,如果是链接了静态库,就可以直接正常运行。但是如果是链接的动态库,那么在运行程序的时候,通常都会报错显示找不到动态库。原因上面已经提过了,链接的时候指定了动态库的目录,但是运行的时候没有指定动态库的目录,解决的办法是,将动态库丢到链接器搜寻的目录下。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
linuxC++动态 实现接口提供类导出的一个例子 注意其使用函数返回基类指针的用法,因为Linux的动态链接不能像MFC那样直接导出类 一、介绍 如何使用dlopen API动态地加载C++函数和类,是Unix C++程序员经常碰到的问题。 事实上,情况偶尔有些复杂,需要一些解释。这正是写这篇mini HOWTO的缘由。 理解这篇文档的前提是对C/C++语言dlopen API有基本的了解。 这篇HOWTO的维护链接是: http://www.isotton.com/howtos/C++-dlopen-mini-HOWTO/ 二、问题所在 有时你想在运行时加载一个(并使用的函数),这在你为你的程序写一些插件或模块架构的时候经常发生。 在C语言,加载一个轻而易举(调用dlopen、dlsym和dlclose就够了),但对C++来说,情况稍微复杂。 动态加载一个C++的困难一部分是因为C++的name mangling (译者注:也有人把它翻译为“名字毁坏”,我觉得还是不翻译好), 另一部分是因为dlopen API是用C语言实现的,因而没有提供一个合适的方式来装载类。 在解释如何装载C++之前,最好再详细了解一下name mangling。 我推荐您了解一下它,即使您对它不感兴趣。因为这有助于您理解问题是如何产生的,如何才能解决它们。 1. Name Mangling 在每个C++程序(或、目标文件, 所有非静态(non-static)函数在二进制文件都是以“符号(symbol)”形式出现的。 这些符号都是唯一的字符串,从而把各个函数在程序、、目标文件区分开来。 在C,符号名正是函数名:strcpy函数的符号名就是“strcpy”,等等。 这可能是因为两个非静态函数的名字一定各不相同的缘故。 而C++允许重载(不同的函数有相同的名字但不同的参数), 并且有很多C所没有的特性──比如类、成员函数、异常说明──几乎不可能直接用函数名作符号名。 为了解决这个问题,C++采用了所谓的name mangling。它把函数名和一些信息(如参数数量和大小)杂糅在一起, 改造成奇形怪状,只有编译器才懂的符号名。 例如,被mangle后的foo可能看起来像foo@4%6^,或者,符号名里头甚至不包括“foo”。 其一个问题是,C++标准(目前是[ISO14882])并没有定义名字必须如何被mangle, 所以每个编译器都按自己的方式来进行name mangling。 有些编译器甚至在不同版本间更换mangling算法(尤其是g++ 2.x和3.x)。 即使您搞清楚了您的编译器到底怎么进行mangling的,从而可以用dlsym调用函数了, 但可能仅仅限于您手头的这个编译器而已,而无法在下一版编译器下工作。 三、类 使用dlopen API的另一个问题是,它只支持加载函数。 但在C++,您可能要用到的一个类,而这需要创建该类的一个实例,这不容易做到。 四、解决方案 1. extern "C" C++有个特定的关键字用来声明采用C binding的函数: extern "C" 。 用 extern "C"声明的函数将使用函数名作符号名,就像C函数一样。 因此,只有非成员函数才能被声明为extern "C",并且不能被重载。 尽管限制多多,extern "C"函数还是非常有用,因为它们可以象C函数一样被dlopen动态加载。 冠以extern "C"限定符后,并不意味着函数无法使用C++代码了, 相反,它仍然是一个完全的C++函数,可以使用任何C++特性和各种类型的参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值