gccg++动态库和静态库,编译与链接(含⽰例)
程序编译⼀般需要经预处理、编译、汇编和链接⼏个步骤。在实际应⽤中,有些公共代码需要反复使⽤,就把这些代码编译成为“库”⽂件。在链接步骤中,连接器将从库⽂件取得所需的代码,复制到⽣成的可执⾏⽂件中,这种库称为静态(链接)库,其特点是可执⾏⽂件中包含了库代码的⼀份完整拷贝,缺点是被多次使⽤就会多份冗余拷贝。还有⼀种库,就是程序在开始运⾏后调⽤库函数时才被载⼊,这种库独⽴于现有的程序,其本⾝不可执⾏,但包含着程序需要调⽤的⼀些函数,这种库称为动态(链接)库(Dynamic Link Library)。
在widows平台下,静态链接库是.lib⽂件,动态库⽂件是.dll⽂件。在linux平台下,静态链接库是.a⽂件,动态链接库是.so⽂件。这⾥主要讲在linux平台下的动态库和静态库的⽣成以及链接。
⼀、库的基本知识
⾸先说明要对库有⼀个⽐较直观的理解。库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义⾮同寻常。本质上说来库是⼀种可执⾏代码的⼆进制形式(注,其本⾝不可执⾏),可以被操作系统载⼊内存执⾏。
静态链接库,之所以称为“静态库”,是因为在链接阶段,会将汇编⽣成的⽬标⽂件.o与引⽤到的库⼀起链接打包到可执⾏⽂件中,因此对应的链接⽅式为静态链接。其实⼀个静态链接库可以简单看成⼀组⽬标⽂件(.o/.obj⽂件)的集合,即很多⽬标⽂件经过压缩打包后形成的⼀个⽂件。静态库特点总结:
1. 静态库对函数库的链接是放在编译时期完成
2. 程序在运⾏时对函数库再唔⽠葛,⼀直⽅便。
3. 浪费空间和资源,因为所有相关的⽬标⽂件和牵涉到的函数库被链接合成⼀个可执⾏⽂件。
linux下使⽤ar⼯具(windows下⽤)(具体的⽤法参考【5】),可以将⽬标⽂件压缩到⼀起,并且对其进⾏编号和索引,⼀便于查和索引。⼀般创建静态链接库的步骤如下:
静态链接库的命名规则,库的名称和库⽂件名称不同,有联系,假定库名称为"my_library_name",那么起库⽂件名
为"lib[my_library_name].a"(⽅括号是为了区分,实际上没有)
动态链接库,在程序编译是并不会被连接到⽬标代码中,⽽是在程序运⾏时才被载⼊。不同的应⽤程序如果调⽤相同的库,那么在内存⾥只需要有⼀份该共享库的实例,规避了空间浪费问题。动态库的⼀些总结:
1. 动态库把对⼀些库函数的链接载⼊推迟到程序运⾏时期
2. 可以实现进程之间的资源共享,(动态库也成为共享库)
3. 将⼀些程序升级变得简单
4. 设置可以真正做到链接载⼊完全由程序员在程序代码中控制(显式调⽤)
Linux下gcc编译的执⾏⽂件默认是ELF格式,不需要初始化⼊⼝,亦不需要函数做特别的声明,编写⽐较⽅便。与windows系统下的格式不同。与创建静态库不同的是,不需要打包⼯具,直接使⽤编译器即可创建动态库。
动态链接库的命名规则,与静态链接库的⽅式相同,不过其后缀名为.so,命名形式为 "lib[my_library_name].so"    。但是在实际使⽤过程中libxxx.so ⼤多数情况只是⼀个链接,它链接到⼀个包含版本信息的库⽂件 ,如下图。当然⾃⼰可以使⽤ ln 命令,制作链接 ln -s libxxxx.so。
⼆、库的编译和使⽤
下⾯使⽤⼀个例⼦来说明链接库是如何⽣成与链接的。这个例⼦的源代码参考【4】。这⾥有五个⽂件,头⽂
件“SoDemoTest.h”,三个cpp⽂件“one.cpp”、"two.cpp"、"three.cpp",main函数实现⽂件“main.cpp”。
#ifndef _SO_DEMO_TEST_HEADER_
#define _SO_DEMO_TEST_HEADER_
#include <iostream>
using namespace std;
void one();
void two();
void three();
#endif
/* one.cpp */
#include "SoDemoTest.h"
void one(){
cout << "call one() function" << endl;
}
/* two.cpp */
#include "SoDemoTest.h"
void two(){
cout << "call two() function" << endl;
}
/
* three.cpp */
#include "SoDemoTest.h"
void three(){
cout << "call three() function" << endl;
}
/* main.cpp */
#include "SoDemoTest.h"
int main(){
one();
two();
three();
return 0;
}
gcc/g++的编译参数,这⾥只介绍 -L 、-l、-include、-I、-shared、-fPIC
-L :表⽰要链接的库所在的⽬录。-L.  表⽰要链接的库在当前⽬录, -L/usr/lib 表⽰要连接的库在/usr/lib下。⽬录在/usr/lib时,系统会⾃动搜索这个⽬录,可以不⽤指明。
-l (L的⼩写):表⽰需要链接库的名称,注意不是库⽂件名称,⽐如库⽂件为 libtest.so,那么库名称为test
-include :包含头⽂件,这个很少⽤,因为⼀般情况下在源码中,都有指定头⽂件。
-I (i 的⼤写):指定头⽂件的所在的⽬录,可以使⽤相对路径。
-shared :指定⽣成动态链接库
-fPIC:  表⽰编译为位置独⽴的代码,不⽤此选项的话编译后的代码是位置相关的所以动态载⼊时事通过代码拷贝的⽅式来满⾜不同进程的需要,⽽不能达到真正代码共享的⽬的。
⽣成链接库
第1步,⽣成⽬标⽂件:g++ -c xxx.cpp
第2步,创建静态链接库:  ar  cqs  libxxxx.a  xx1.o xx2.o xx3.o (参数选项请看【5】)
第3步,程序中使⽤静态链接库
第4步,创建动态链接库 g++ -fPIC -shared -o libxxx.so xx1.cpp xx2.cpp xx3.cpp
第5步,动态链接库使⽤
解决⽅法:缺少动态连接库.so--cannot open shared object file: No such file or directory
⽅法1:
运⾏的时候有可能可执⾏⽂件m不到动态链接库,出现如下错误:
./m: error while loading shared libraries: libthostmduserapi.so: cannot open shared object file: No suc
h file or directory
这是因为程序默认会到/lib64/⽬录中动态链接库,⽽程序中所使⽤的的thostmduserapi.so不在/lib64/中。因此需要增加如下命令,让程序也到指令的⽬录中库
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./traderapi
sudo ldconfig
⽅法2:
如果不喜欢-lthostmduserapi这种写法,或者不习惯动态链接库的lib打头。也可以将lib去掉,直接携程XXXX.so只是编译的时候,需要将动态链接库当做.cpp⽂件来编译。
假设动态链接库的名字是thostmduserapi.so,那么编译命令:
g++ -o m main.cpp ZY_FtdcMdApi.cpp ./traderapi/thostmduserapi.so -I./traderapi/
且这种⽅法不会发⽣“说明1”中问题。挺好的。
⽅法3:
1. ⽤ln将需要的so⽂件链接到/usr/lib或者/lib这两个默认的⽬录下边
ln -s /where/you/install/lib/*.so /usr/lib
linux下gcc编译的四个步骤sudo ldconfig
⽅法4:
修改/etc/f,然后刷新
vim /etc/f
add /where/you/install/lib
sudo ldconfig
三、库的链接说明
上⾯简单演⽰了⼀遍库的⽣成过程,但是还有很多细节没有讲清楚。以下问题需要注意:
1. 链接过程中可能出现多种链接⽅式,需要使⽤⼀些参数来指定,下⾯只是⼀个演⽰,在测试时,⾃⼰填写具体的名称
g++ testmain.o -o testmain -WI,-Bstatic -lstaticlib -WI,-Bdynamic -ldynamiclib
2. 链接过程中同⼀个库(名称相同)的静态和动态两种链接库,在链接过程中,系统优先选择动态链接库
3. 动态链接库路径,系统默认在/usr/lib 和/usr/local/lib两个库⽬录搜索,⾃⼰定义的库需要格外指定路径(设定变量
LD_LIABRARY_PATH)或者将其拷贝到这两个⽬录下,在上⾯的例⼦的测试过程,已经有说明。当然也可以将当前路径添加
到/etc/f⽂件中或者/etc/f.d⽬录下的⼀个⽂件中。
4. 查看动态链接库。 有时候可能需要查看⼀个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多,常见的有三种:
⼀种是在库中被调⽤,但并没有在库中定义(表明需要其他库⽀持),⽤U表⽰;
⼀种是在库中定义的函数,⽤T表⽰,这是最常见的;
另⼀种所谓的“弱态”符号,它们虽然在库中定义,但可能被其他库中的同名符号覆盖,⽤W表⽰。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。