从源代码到可执行程序,通常要经过最重要的两大步是:编译,链接。编译就是将源文件生成中间文件的过程,在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
          这样链接后生成的程序,如果是链接了静态库,就可以直接正常运行。但是如果是链接的动态库,那么在运行程序的时候,通常都会报错显示找不到动态库。原因上面已经提过了,链接的时候指定了动态库的目录,但是运行的时候没有指定动态库的目录,解决的办法是,将动态库丢到链接器搜寻的目录下。
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐