Linux:静态函数库(.a)与动态函数库(.so)

97 篇文章 7 订阅

Linux:静态函数库(.a)与动态函数库(.so)

函数库分两种:

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 <iostream>
#include "mymath.h"

using namespace std;

int main()
{
    cout<<add(10, 22)<<endl;
    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 <iostream>
#include "mymath.h"

using namespace std;

int main()
{
    cout<<add(10, 12)<<endl;
    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是使用-shared3.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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值