函数库分两种:
1.静态函数库:库程序是直接注入目标程序的,不分彼此,库文件通常以.a结尾;
2.动态函数库:库程序是在运行目标程序时(中)加载的,库文件通常以.so结尾;
Linux中有个常用命令是tar,是用来打包一些文件到指定“文件包”中;
Java中有个常用的命令是jar,是将一些.class的字节码文件打包到指定的“文件包”(jar包)中;
可以这么理解,静态函数库.a就是一个文件包,里面就是一些.o的文件(.a是.o的集合,很多的.o合起来组成.a)。
可以使用命令ar来生成.a文件。注:ar是archiver的缩写。
静态函数库通常的优点是:
1.在生成目标程序时,只需要指定对应的静态库即可,不必重新编译静态库的相关源文件,可以节约时间;
2.当希望给别人用一些东西但是不想要对方知道我自己的源代码,可以弄个静态库给他用,别人拿到的只是一些.o文件,拿不到原始的代码;
实例:
描述:希望构建一个mymath.a的静态库,里面包含基本运算。
mymath.h
#ifndef _MYMATH_H
#define _MYMATH_H
int add(int, int);
int sub(int, int);
int mul(int, int);
int dev(int, int);
#endif
mymath.C
#include "mymath.h"
int add(int a, int b)
{ return a + b; }
int sub(int a, int b)
{ return a - b; }
int mul(int a, int b)
{ return a * b; }
int dev(int a, int b)
{ return a / b; }
main.C
#include
#include "mymath.h"
using namespace std;
int main()
{
cout<10, 22)<return 0;
}
编译mymath.C为mymath.o
[jiang@eb50 43]$ g++ -c mymath.C
生成静态库,只包含一个mymath.o文件
[jiang@eb50 43]$ ar rcs mymath.a mymath.o
编译生成目标文件main
[jiang@eb50 43]$ g++ -o main main.C mymath.a
[jiang@eb50 43]$ ll
总计 32
-rwxrwxr-x 1 jiang jiang 8912 10-16 19:00 main
-rw-rw-r-- 1 jiang jiang 115 10-16 18:43 main.C
-rw-rw-r-- 1 jiang jiang 1840 10-16 19:00 mymath.a
-rw-rw-r-- 1 jiang jiang 181 10-16 18:58 mymath.C
-rw-rw-r-- 1 jiang jiang 119 10-16 18:34 mymath.h
-rw-rw-r-- 1 jiang jiang 1656 10-16 19:00 mymath.o
[jiang@eb50 43]$ ./main
32
关于ar的选项(rcs)可以参见(man ar):
r:Insert the files member… into archive (with replacement).
c:Create the archive.
s:Write an object-file index into the archive, or update an existing one, even if no other change is made to the archive.
更多ar选项还请参见man手册.
.so动态函数库可以在程序启动时加载,也可以在程序中使用dlopen等操作动态地在程序运行中进行加载.
动态链接库与普通的程序相比而言,没有main函数,是一系列函数的实现.
动态函数库的名字:
通常约定,一个mymath的动态库的名字应当是:
libmymath.so[版本号]
lib+动态苦命+.so+版本信息
可以在/usr/lib中看到类似下面的很多软链接:
lrwxrwxrwx 1 root root 26 2013-03-13 libssl.so -> ../../lib/libssl.so.0.9.8e
我们倒着来:
我们要是用库ssl,应该在链接的时候加上-lssl;
链接器看到-lssl,就知道要找一个库叫做libssl.so的库文件(或软链接);
ssl库在哪里呢?通常编译时刻是由-L来决定查找的路径;
找到了libssl.so发现是个软链接,实际指向另一个库(../../lib/libssl.so.0.9.8e).
看到了吗?libssl.so指向的文件名叫做:libssl.so.0.9.8e.
对比下上面的格式:
0.9.8e就是版本信息.
也就是说,我们常用的是个软链接,叫做libxxx.so,然后实际指向一个带版本信息的真实的库文件.
怎样创建动态程序库?
实例:
描述:希望构建一个libmymath.so,包含基本运算.
mymath.h
#ifndef _MYMATH_H
#define _MYMATH_H
int add(int, int);
int sub(int, int);
int mul(int, int);
int dev(int, int);
#endif
mymath.C
#include "mymath.h"
int add(int a, int b)
{ return a + b; }
int sub(int a, int b)
{ return a - b; }
int mul(int a, int b)
{ return a * b; }
int dev(int a, int b)
{ return a / b; }
main.C
#include
#include "mymath.h"
using namespace std;
int main()
{
cout<10, 12)<return 0;
}
生成动态库:
[jiang@eb50 43]$ g++ -fPIC -g -c mymath.C
[jiang@eb50 43]$ g++ -shared -g mymath.o -o libmymath.so.1
[jiang@eb50 43]$ ln -s libmymath.so.1 $PWD/libmymath.so
[jiang@eb50 43]$ ll
总计 32
lrwxrwxrwx 1 jiang jiang 14 10-16 19:40 libmymath.so -> libmymath.so.1
-rwxrwxr-x 1 jiang jiang 8231 10-16 19:40 libmymath.so.1
-rw-rw-r-- 1 jiang jiang 115 10-16 19:39 main.C
-rw-rw-r-- 1 jiang jiang 181 10-16 18:58 mymath.C
-rw-rw-r-- 1 jiang jiang 119 10-16 18:34 mymath.h
-rw-rw-r-- 1 jiang jiang 4856 10-16 19:40 mymath.o
使用动态库(编译时):
[jiang@eb50 43]$ g++ -o main main.C -L $PWD -lmymath
运行目标程序:
[jiang@eb50 43]$ ll
总计 44
lrwxrwxrwx 1 jiang jiang 14 10-16 19:40 libmymath.so -> libmymath.so.1
-rwxrwxr-x 1 jiang jiang 8231 10-16 19:40 libmymath.so.1
-rwxrwxr-x 1 jiang jiang 8804 10-16 19:42 main
-rw-rw-r-- 1 jiang jiang 115 10-16 19:39 main.C
-rw-rw-r-- 1 jiang jiang 181 10-16 18:58 mymath.C
-rw-rw-r-- 1 jiang jiang 119 10-16 18:34 mymath.h
-rw-rw-r-- 1 jiang jiang 4856 10-16 19:40 mymath.o
[jiang@eb50 43]$ ./main
./main: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
出错了.
先暂时放下最后的错误,这里有几个需要注意的地方:
1.编译生成.o文件时使用了-fPIC选项,指代:Position Independent Code;
2.由众多.o文件构建成.so是使用-shared;
3.ln -s其实不是必要的,准确的说,你可以由步骤2生成一个libmymath.so不带版本号,也就不用软链接再次链接了;
4.编译目标程序时,-L指明在哪些目录中查找,-l指明要寻找的库;
注:如果-lxxx,则要在-L指明的库中查找libxxx.so这个文件,它可能是个软链接,也可能是个实际的库文件;
好了,现在解决最后的运行出的问题。
我们可以先用ldd查看main这个可执行文件与哪些动态库有关系:
[jiang@eb50 43]$ ldd main
linux-vdso.so.1 => (0x00007fff077fd000)
libmymath.so => not found
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003a53600000)
libm.so.6 => /lib64/libm.so.6 (0x0000003a41800000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003a51a00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003a41000000)
/lib64/ld-linux-x86-64.so.2 (0x0000003a40800000)
(ldd prints the shared libraries required by each program or shared library specified on the command line.)
我们发现libmymath.so没找到,这是为啥呢?
原来在ldd/运行时,并不是从-L(实际上也没有这个-L)中查找:
-L是gcc/g++在编译时刻的选项,指明从哪些目录中查找动态库文件;
运行时刻的库加载(搜索)由当前shell的环境变量LD_LIBRARY_PATH决定;
[jiang@eb50 43]$ export LD_LIBRARY_PATH=.
[jiang@eb50 43]$ ldd main
linux-vdso.so.1 => (0x00007fff912a6000)
libmymath.so => ./libmymath.so (0x00002b0ad452b000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x0000003a53600000)
libm.so.6 => /lib64/libm.so.6 (0x0000003a41800000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x0000003a51a00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003a41000000)
/lib64/ld-linux-x86-64.so.2 (0x0000003a40800000)
[jiang@eb50 43]$ ./main
22
当然,你可以给LD_LIBRARY_PATH一个绝对路径,而不是一个”.”(相对路径).
还有一种动态程序库使用的方式是使用dlopen系列函数来操作,这个后续再进行介绍.
参考:
1.http://blog.csdn.net/ithomer/article/details/7346146
2.http://www.cnblogs.com/Anker/p/3527677.html