linux中库文件的生成和使用

来源:互联网 发布:爱普生t50清零软件 编辑:程序博客网 时间:2024/06/05 06:43
1、linux库文件分为静态库和动态库两种。静态库习惯以.a 结尾,而动态库习惯以.so(shared object)结尾。而且必须以lib开头。
2、静态库
的原则是“以空间换时间”,增加程序体积,减少运行时间;
生成:在编译时候,先生成目标文件.o,然后用ar文件对目标文件归档,生成静态库文件。
例如:ar -rc libtest.a myalib.o (注意:ar -rc 目标 .o文件名),目标一定要以lib开头。
3、使用时候,在链接时候,加上选项 -l 后接库文件名,注意:必须是文件名去掉后缀和lib,
如:gcc -o main  main.o -ltest
而且-ltest必须放在main.o的后面,(规则是,越底层的库越要放在后面)。
4、gcc的其他常用的选项,
-c 编译成目标文件 如:gcc -c main.c 就是编译main.c成目标文件main.o
-I 头文件的查找路径,如:gcc -c main.c -I./inc 意思是:头文件的查找路径除了默认的之外,再加上./inc目录下的。
-L 库文件的查找路径,如:gcc -o main main.o -L./lib -ltest 说明:libtest.a 或者 libtest.so 库文件的查找路径除了默认之外,再加上./lib目录。
-MM 导出文件的依赖关系(用#include 中的内容)如:gcc -MM main.c找出main.c的所依赖的头文件
-o 生成最终目标
-D宏定义 相当于在C中些语句#define ... 如:-DPI=3.14 就相当于在文件里面写语句#define PI 3.14 
5、动态库
(1)、生成:在链接时,用如下选项:-shared -fpic 如: gcc -fpic -shared -o libtest.so myalib.c

(2)、使用:有隐式使用和显示使用,隐式使用就是共享方式,程序一开始运行就调进去。在链接时候用如下:

gcc -o main main.o -L./lib -ltest(像静态库的一样)
显示使用就是在程序中用语句把动态库调进来,用系统调用:dlopen、dlsym、dlerror、dlclose函数,那样在编译链接时候,不用加上:-L./lib -ltest了。不过要使用dl*系列函数在编译链接时要加上 -ldl
6、如果同一目录下,既有静态库也有动态库,比如libtest.a libtest.so都存在,那么dl程序(等一下介绍)就把动态库调进去,没有动态的,就找静态的。再没有,就报错。
7、动态库的搜索路径
dl对动态库的搜索路径如下(按顺序如下)
a.编译目标代码时指定的动态库搜索路径;(如果要指定程序行时在./lib目录下找库文件libtest.so,命令如下:gcc -o main main.c -L./lib -ltest -Wl,-rpath ./lib) ,其中,-Wl的意思是,后面的选项直接交给ld程序处理,-rpath选项是说更改搜索路径为后面的参数./lib
b.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
c.配置文件/etc/ld.so.conf中指定的动态库搜索路径;(修改完文件后,用ldconfig更新)
d.默认的动态库搜索路径/lib和/usr/lib;
8、一些常用的命令(与库有关的)
(1)、ld 是gcc的链接程序。
(2)、ldd是查看可执行文件中所依赖的库的程序,比如想查main程序用到了那些动态库,可以直接
ldd main
(3)、ldconfig用来更新文件/etc/ld.so.conf的修改生效。

(4)、nm用来查看.so库中的函数名字,标记是T的就是动态库里面生成的名字。如:nm /lib/libc*.so


动态链接库的生成:

代码上与写静态链接库没什么区别,主要是在编译时,以两个文件举例:

/*mylib.h*/
void Print();
/////////////////////
/*mylib.c*/
#include <stdio.h>
#include "mylib.h"
void Print()
{
    printf("This is in mylib\n");
}

生成动态库文件的编译方法如下:gcc -fpic -shared mylib.c -o mylib.so

此时将生成mylib.so动态链接库文件。

动态链接库在使用时,分为“隐式调用”和“显式调用”两种,如果是隐式调用,则与静态库的使用方法差不多,注意需要包含导出函数的头文件,即mylib.h:

#include <stdio.h>
#include "mylib.h"
int main()
{
    Print();
}

使用动态库文件的编译方法:gcc -o main main.c -L./  mylib.so

注意要加上动态链接库的搜索路径,否则编译器只会到系统路径中去寻找。

显式调用的方式,不必包含mylib.h,但是需要增加几个系统调用:

#include <stdio.h>
#include <dlfcn.h> // 显式加载需要用到的头文件
int  main()
{
    void *pdlHandle = dlopen("./mylib.so", RTLD_LAZY); // RTLD_LAZY 延迟加载
    char *pszErr = dlerror();
    if( !pdlHandle || pszErr )
    {
        printf("Load mylib failed!\n")
        return 1;
    }
    void (*Print)() = dlsym(pdlHandle, "Print"); // 定位动态链接库中的函数
    if( !Print )
    {
        pszErr = dlerror();
        printf("Find symbol failed!%s\n", pszErr);
        dlclose(pdlHandle);
        return 1;
    }
    Print(); // 调用动态链接库中的函数
    dlclose(pdlHandle); // 系统动态链接库引用数减1
    return 0;
}

可以看到,显式调用的代码看上去要复杂很多,但是却比隐式调用要灵活,我们不必在编译时就确定要加载哪个动态链接库,可以在运行时再确定,甚至重新加载。

看一下显式调用的编译方式:gcc -ldl -o main main.c

注意要添加-ldl选项,以使用显式调用相关的函数调用。



http://www.linuxidc.com/Linux/2012-03/57023.htm

http://blog.csdn.net/jiangnanyouzi/article/details/3321150

0 0
原创粉丝点击