大家好,继上节<Linux库详解>,这节我们继续讲解如何在Linux系统上创建我们需要的库文件
参数 | 含义 |
---|---|
-c | 激活预处理、编译和汇编,把程序做成目标文件(.o文件) |
-g | 在编译的时候产生调试信息 |
-Wall | 生成警告信息 |
-l | 指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称 |
-L | 表示要连接的库目录 |
-fPIC | 表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方 |
-shared | 生成动态链接库 |
我们编写两个函数并将文件制作成库文件,用下面相同的代码分别制作静态库和共享库
Test.h文件
#ifndef _TEST_H_
#define _TEST_H_
int add(int a, int b);
int sub(int a, int b);
#endif
Test.c文件
#include <stdio.h>
#include "Test.h"
int add(int a, int b)
{
return (a+b);
}
int sub(int a, int b)
{
return (a - b);
}
gcc -c Test.c
ar -cr libTest.a Test.o // 遵循静态库命名的规则 lib + 名字 + .a
-c create的意思 -r replace的意思,表示当插入的模块名已经在库中存在,则替换同名的模块。如果若干模块中有一个模块在库中不存在,ar显示一个错误消息,并不替换其他同名模块。默认的情况下,新的成员增加在库的结尾处,可以使用其他任选项来改变增加的位置。
#include <stdio.h>
#include "Test.h"
int main(int argc, char const *argv[])
{
int nAdd = add(1, 2);
printf("nAdd: %d\n", nAdd);
int nSub = sub(2, 1);
printf("nSub: %d\n", nSub);
return 0;
}
gcc -o main main.c -lTest -L.
-l 指定了静态函数库名,由于静态函数库的命名方式是lib***.a,其中的lib和.a忽略 -L 指定静态函数库的查找目录,L后面'.',表示静态函数库在本目录下查找
// 用下面两个命令
gcc -fPIC -o libTest.o -c Test.c
gcc -shared -o libTest.so libTest.o
// 或用下面一个命令
gcc -shared -fpic -o libTest.so Test.c
-fpic:产生位置无关代码 -shared:生成共享库
#include <stdio.h>
#include "Test.h"
int main(int argc, char const *argv[])
{
int nAdd = add(1, 2);
printf("nAdd: %d\n", nAdd);
int nSub = sub(2, 1);
printf("nSub: %d\n", nSub);
return 0;
}
gcc -o main-so main-so.c -lTest -L.
在执行可执行程序时,出现以下错误,说找不到库文件,在继续往下看之前大家想想这是为什么?
因为在动态函数库使用时,会查找/usr/lib、/lib目录下的动态函数库,而此时我们生成的库不在里边。我们可以通过以下方法解决此问题,其实这个问题在上一节中我们提到过,小伙伴可以回看一下。
1.最直接最简单的方法就是把libTest.so拷贝到/usr/lib或/lib中去。
2.设置环境变量,假设libTest.so在/home/ubuntu/workspace_ex/lib/static目录下
export LD_LIBRARY_PATH=/home/linux/addsub:$LD_LIBRARY_PATH
3.另外还可以在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig /etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是从/usr/lib /lib中读取的,所以想要顺利运行,我们也可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig
上面共享库的调用属于动态链接方法,此外我们还可以动态加载,在上一节中我们讲过二者的区别,此处不做过多讲解。动态加载需要用到系统API函数
接口 | 描述 |
---|---|
dlopen | 打开对象文件,可被程序访问 |
dlsym | 获取执行了dlopen函数的对象文件中的符号的地址 |
dlerror | 返回上一次出现的错误 |
dlclose | 关闭目标文件 |
调用过程
#include <stdio.h>
#include <dlfcn.h>
#include"Test.h"
int main(int argc, char const *argv[])
{
void *dlHandler = NULL;
int(*Func)(int,int);
char *Error;
int nAdd;
dlHandler = dlopen("libTest.so", RTLD_LAZY);
if(!dlHandler)
{
printf("dlopen:%s\n", dlerror());
return 0;
}
Func = dlsym(dlHandler, "add");
Error = dlerror();
if(Error != NULL)
{
printf("find:%s\n",Error);
return 0;
}
nAdd = (*Func)(1, 2);
printf("add = %d\n",nAdd);
dlclose(dlHandler);
return 0;
}
gcc -o main-dl main-dl.c -ldl
-ldl 表明将 dllib 链接于该程序,即可调用DL的API
共享库文件放置与共享库调用时操作一样
到目前为止,我们详细讲解了Linux下制作静态库、共享库、以及动态加载库,希望通过此文对你在Linux库的认识有所帮助,那么目的就达到了