现在的位置: 首页 > 综合 > 正文

linux静态库和动态库编译及使用

2018年03月30日 ⁄ 综合 ⁄ 共 4071字 ⁄ 字号 评论关闭
文章目录
/**************************************************************************/
/*add.c*/
int add(int x, int y)
{
return x + y;

return 0;
}
/*************************************************************************/
然后add.h代码为:
/*add.h*/
#ifndef _ADD_H_
#define _ADD_H_

int add(int, int);

#endif
/***************************************************************************/
main函数代码:
/*main.c*/
#include <stdio.h>

int main(void)
{
printf("2+3= %d\n", add(2,3));
return 0;
}
/**********************************************************************************/

1 静态库的编译流程

将add.c 单独的源文件编译成静态库libadd.a

gcc -c add.c  //生成 add.o

ar crv libadd.a add.o // 生成静态库libadd.a

2 静态库的使用

gcc -o main main.c  -I. -L. -ladd  (注: -I -L -l的意思在文章后面)

也可以: gcc -o main main.c -I ./libadd.a (注:这里 ./libadd.a 可以是相对地址或者绝对地址 如:./lib/libadd.a , /home/lisi/lib/lib.a)

3 动态库的编译流程

gcc -fPIC -c add.c // 生成add.o

gcc -shared -o libadd.so add.o // 或者使用 ar crv libadd.so add.o

上面可合并成一行: gcc -fPIC -shared -o libadd.so add.c

注: -fPIC 使输出的对象模块是按照可重定位地址方式生成的(即与位置无关).

-shared 指定把对应的源文件生成对应的动态链接库库文件libstr.so文件

4 动态库的使用

4.1 隐式调用

代码编写与静态库一样,不需要包含到处函数的头文件,若主函数是C++程序(即.cpp), 则需要在main.cpp中用extern "C"{} 包含被调用的函数(add.c)的头文件(这里需要包含头文件是与.cpp和.c混合编译有关,同静态\动态库无关),用g++或者用gcc(加上一个链接的参数 -lstdc++)编译.

1 )代码编写:与静态库一样

2 ) 编译main.c 生成可执行程序(动态库隐式调用的使用)

gcc -o main main.c ./libadd.so

或者 gcc -o main main.c -L. libadd.so 

(

注:以上两种情况执行./main时会出现
./main: error while loading shared libraries,cannot open shared object file: No such file or directory?

解决方案:

方法一: libadd.so放到/usr/lib 或 /lib 中去.

方法二: export LD_LIBRARY_PATH=$(pwd) 或者 export LD_LIBRARY_PATH=./ ,

可写入环境变量(http://blog.csdn.net/renwotao2009/article/details/40537161)来支持当前目录寻找动态链接库

方法三: 在/etc/ld.so.conf文件加入我们生成的库目录(只支持绝对路径),然后执行 #/sbin/ldconfig.

关于 /etc/ld.so.conf 可以参看:http://blog.csdn.net/renwotao2009/article/details/40109695第9条

)

或者将libadd.so 拷贝到目录 /user/lib 或者 /lib 中,然后执行 gcc -o main main.c libadd.so  //此时不需要指定搜索路径

4.2 显示调用

4.2.1 在main.c 中增加头文件 #include <dlfcn.h>引入dlopen , dlsym , dlclose , dlerror 几个系统调用

主要介绍dlopen()系统调用

第一个参数:指定共享库的名称,将会在下面位置查找指定的共享库.

-环境变量 LD_LIBARARY_PATH列出的用冒号间隔的所有目录

-文件/etc/ld.so.cache重找到库的列表,用 ldconfig 维护

-目录/usr/lib

-目录/lib

-当前目录

第二个参数:指定打开共享库.

-RTLD_NOW:将共享库重的所有函数加载到内存

-RTLD_LAZY:会退后共享库中的函数的加载操作,知道调用dlsym()时方加载某函数

返回值:返回动态库的句柄

#include <stdio.h>
#include <dlfcn.h>

int main()
{
    int (*func)(int , int );
    void *dl = dlopen("./libadd.so", RTLD_LAZY);
    if (dl == NULL)
            return -1;
    func = dlsym(dl, "add");
    if (func == NULL)
            return -1;
     printf("2+3=%d", func(2, 3));
     dlclose(dl);
return 0;
}

4.2.2 编译main.c生成可执行程序,动态库已创建

gcc -o main main.c -ldl // 注:使用libld.so库进行系统调用

5 动态库使用中遇到的问题

gcc编译文件时出现undefined reference to 'xxxx'的错误?

这是链接错误,不是编译错误,源程序代码本身没有问题,是你的编译时参数用的不对.你没有指定连接程序要用到的库,比如你的程序里用到了一些数学函数sqrt ,那么你就要在编译参数里指定程序要链接数学库,eg:gcc -o math math.c -lm.

6 gcc中一些参数的作用

6.1 -l 参数和 -L参数

-l 参数就是用来指定程序要链接的库, -l 参数紧接着就是库名, 那么库名跟真正的库文件名有什么关系呢?拿数学库来说,他的库名是m ,他的库文件名是 libm.so ,很容易看出,把库文件名的lib和尾.so 去掉就是库名了. 如第三方库名字叫做libtest.so 那么我们只需要把libtest.so 拷贝到 /usr/lib 或者 /usr/local/lib里,在编译时加上 -ltest 参数,我们就能用上libtest.so库了.

注意:要用libtest.so 库里的函数,我们还需要与libtest.so 配套的头文件.eg:gcc -o test  test.c -ltest(libtest.so 的隐式调用)

6.2 -include 和-I参数

-include 用来包含头文件,但是一般情况下包含头文件都在源码里用#include xxx 实现, -include 参数很少用. -I参数用来指定头文件目录.

/usr/include 目录一般是不用指定的,gcc 知道去那里找,但是如果头文件不在 /usr/include 里我们就要用 -I参数指定. 比如 头文件放在 /myinclude目录里,那么便以命令行就加上-I/myinclude 参数,如果不加就会得到 "xx.h: No such file or deirectory "的错误. (注-I参数也可以用相对路径,比如当前目录,可以用 -I. 来指定). 也可以通过设置环]境变量C_INCLUDE_PATH来指定头文件目录,怎样设置可参看http://blog.csdn.net/renwotao2009/article/details/40537161

参考文章1:http://blog.csdn.net/star_xiong/article/details/17301191

参考文章2:http://blog.csdn.net/casularm/article/details/316149

参考文章3:http://blog.csdn.net/zzxzzy/article/details/6013185

额外知识点:

1 Linux静态库的命名规则

static library filename = lib +<library name> + .a
静态库文件名中间那一部分是库的实际名称,链接器需要使用这个名称来进行链接。

2 Linux动态库命名规则

dynamic library filename = lib + <library name> + .so + <library version information>
动态库文件名中间那一部分是库的实际名称,链接器会在随后的构建时库文件搜索过程中使用这个名称,装在器也会在运行时库文件搜索过程中使用这个名称。

3 动态库的版本信息

dynamic library version information = <M>.<m>.<p>
其中,每个助记符可能使用一个或多个数字来表示
M:主版本号
m:次版本号
p:补丁(很小的代码改动)版本号

4 动态库的soname

library soname = lib + <library name> +
.so
+ <library major version digit(s)>
举例来说,库文件libz.so.1.2.3.4的soname则是libz.so.1
实际上只有主版本好的数字在库soname中起作用,这意味着即使库的次版本好是不同的,也可能使用同一个soname值来表示。
动态库的soname通产由链接器嵌入二进制库文件的专有ELF字段中。通常使用特定的链接器选项,将表示库soname的字符串传递给链接器。比如
$ gcc -shared <list of object files> -Wl, -soname, libfoo.so.1 -o libfoo.so.1.0.0

抱歉!评论已关闭.