函数库本质是一组函数的集合,具有相近的功能或操作。根据链接时期的不同,函数库分为静态库和动态库。
静态库是指链接时,把库文件链接到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。静态库后缀名一般为.a
。动态库与之相反,在链接时并没有把库文件链接到可执行文件中,而是仅简单地引用其函数声明,在程序执行时根据需要动态链接库文件,这样可以节省系统的开销。动态库后缀名一般为.so
静态库和动态库的最大区别在于,在静态情况下,把库直接加载到程序中;而动态库链接的时候,它只是保留接口声明,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。
Linux 系统下的 gcc 是 GNU 推出的功能强大、性能优越的多平台编译器。gcc 是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高 20%~30%。gcc 编译器能将 C、C++ 语言源程序、汇程式化序和目标程序编译、连接成可执行文件,如果没有给出可执行文件的名字,gcc 将生成一个名为 a.out 的可执行文件。
静态库是目标文件的一个集合,目标文件中通常仅解析了文件内部的变量和函数,对于引用的函数和变量还没有解析,这需要将其他已经编写好的目标文件引用进来,将没有解析的函数和变量进行解析,通常引用的目标是库。
gcc 编译源代码时,会依次经过预处理
-编译
-汇编
-链接
这 4 个流程。
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
gcc -c hello.s -o hello.o
gcc hello.o -o hello
参数 | 含义 |
---|---|
-E | 只预处理,不编译,生成编译代码.i |
-S | 只编译,不汇编,生成汇编代码.s |
-c | 只编译,不链接,生成目标文件.o |
-o file | 把输出文件输出到 file 里 |
-v | 打印 gcc 的版本 |
-I dir | 在头文件的搜索路径列表中加入 dir 目录 |
-L dir | 在库文件的搜索路径列表中加入 dir 目录 |
-static | 显式链接静态库(静态库也可以用动态库的方式链接) |
-lxxx | 链接名为 libxxx.so 的动态库 |
gcc 默认链接动态库。当有静态库与动态库同名时,默认链接动态库,如需指定静态库,需要加
-static
参数。
静态库的名字是libxxx.a
,其中 xxx 是该 lib 的名称。
在 UNIX 中,使用ar -rc libxxx.a xxx1.o xxx2.o
命令创建或者操作静态库。
参数 | 含义 |
---|---|
-r | 将目标文件插入静态库尾或者替换静态库中同名文件 |
-c | 创建静态库文件 |
// add.h
#ifndef _ADD_H
#define _ADD_H
int add(int a, int b);
#endif
// add.cpp
#include "add.h"
int add(int a, int b)
{
return a + b;
}
// sub.h
#ifndef _SUB_H
#define _SUB_H
int sub(int a, int b);
#endif
// sub.cpp
#include "sub.h"
int sub(int a, int b)
{
return a-b;
}
// main.cpp
#include "add.h"
#include "sub.h"
#include <iostream>
int main()
{
std::cout << add(1, 2) << std::endl;
std::cout << sub(1, 2) << std::endl;
}
g++ -c add.cpp, g++ -c sub.cpp
,将源代码编译成.o
文件。ar -cr libmymath.a add.o sub.o
,将.o
文件生成静态库。g++ main.cpp -L ./ -static -lmymath
,说明是静态库,默认是加载动态库的。g++ main.cpp libmymath.a
,此时不用指定静态库。动态库的名字是libxxx.so.major.minor
,xxx 是该 lib 的名称,major 是主版本号,minor 是副版本号。版本号也可以没有,一般都会建立个没有版本号的软连接文件链接到全名的库文件。
动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。
不同的 Linux 系统,链接动态库方法,实现细节不一样。编译 PIC 型.o
中间文件的方法一般是采用 C 语言编译器的-KPIC
或者-fPIC
选项,有的 Linux 版本 C 语言编译器默认带上了 PIC 标准。创建最终动态库的方法一般采用 C 语言编译器的-G 或者-shared 选项,g++ -fPIC -shared -o libmymath.so add.cpp sub.cpp
参数 | 含义 |
---|---|
-shared | 指定生成动态连接库 |
-fPIC | 编译为位置独立的代码,跨平台 |
源代码同静态库。
g++ -fPIC -shared -o libmymath.so add.cpp sub.cpp
,生成动态库g++ main.cpp -L ./ -lmymath
g++ main.cpp libmymath.so
系统默认的头文件的搜索路径一般为/usr/include, /usr/local/include, /usr/lib/gcc/i486-Linux-gun/4.1.2/include
系统默认的库文件的搜索路径一般为/lib, /usr/lib
,具体定义在文件/etc/ld.so.conf
或者环境变量LD_LIBRARY_PATH
中。
gcc main.cpp ../lib/libxxx1.a ../lib/libxxx2.so
gcc main.cpp -L ../lib/ -lxx1 -lxx2
-L ../lib/
:指定库的搜索路径。-lxx1 -lxx2
:指定库文件名。由于静态库在链接时已经写入可执行程序,故运行时不需要额外操作了。
但是动态库需要运行时动态地按需调用,与链接时指定的方法不同,运行时则需要系统自行搜索,搜索的路径一般有两种方式指定:
/etc/ld.so.conf
来指定,一般默认是/lib、/usr/lib
,所以要想让动态库顺利加载,可以将库文件拷贝到上面的两个目录下或者追加自己的动态库目录到/etc/ld.so.conf
文件后再ldconfig
刷新即可。LD_LIBRARY_PATH
环境变量,添加自己的动态库的目录后再source .bashrc
刷新即可。另外还有个文件需要了解/etc/ld.so.cache
,里面保存了常用的动态函数库,且会先把他们加载到内存中,因为内存的访问速度远远大于硬盘的访问速度,这样可以提高软件加载动态函数库的速度了。
原文:https://www.cnblogs.com/zghong/p/14149155.html