- 浏览: 149413 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
lanhaitun1991:
亲,其实你这里介绍的方法有一个最大的问题:如果放入队列之后,但 ...
分布式事务 -
lp385267935:
不错 很好用~3Q
jsonlib json-->object,忽略object中没有的属性 -
xiebo1983:
http://www.sqkoo.com/show/detai ...
mysql latin1乱码 -
envy2002:
当然可以了,tomcat中源码你可以看看,只要“欺骗”过去to ...
tomcat中的长连接 -
newSaa:
问一下,可以在 tomcat 建立tcp 长连接吗?
tomcat中的长连接
一、为什么要使用库文件
我们在实际编程工作中肯定会遇到这种情况:有几个项目里有一些函数模块的功能相同,
实现代码也相同,也是我们所说的重复代码。比如,很多项目里都有一个用户验证的功能。
代码段如下:
//UserLogin.h文件,提供函数声明
int IsValidUser(char* username, int namelen);
//UserLogin.c文件,实现对用户信息的验证
int IsValidUser(char* username, int namelen)
{
int IsValid = 0;
/*下面是具体的处理代码,略去*/
return IsValid
}
如果每个项目都保存着这两个UserLogin.h和UserLogin.c文件,会有以下几个
弊端:
1、每个项目里都有重复的模块,造成代码重复。
2、代码的重用性不好,一旦IsValidUser的代码发生了变化,为了保持设计的一致性,
我们还要手工修改其他项目里的UserLogin.c文件,既费时又费力,还容易出错。
库文件就是对公共代码的一种组织形式。
为了解决上面两个弊端,就提出了用库文件存放公共代码的解决方案,其要点就是
把公共的(也就是可以被多次复用的)目标代码从项目中分离出来,统一存放到库文件中,
项目要用到这些代码的时候,在编译或者运行的时候从库文件中取得目标代码即可。库文件
又分两种:静态库和动态库。
二、静态库与动态库
如果程序是在编译时加载库文件的,就是使用了静态库。如果是在运行时加载目标代码,
就成为动态库。换句话说,如果是使用静态库,则静态库代码在编译时就拷贝到了程序的代码段,
程序的体积会膨胀。如果使用动态库,则程序中只保留库文件的名字和函数名,在运行时去查找
库文件和函数体,程序的体积基本变化不大。
静态库的原则是“以空间换时间”,增加程序体积,减少运行时间;
动态库则是“以时间换空间”,增加了运行时间,但减少了程序本身的体积。
下面我们就以实际例子来看看如何使用这两种库.
三、静态库的编写和使用
1、概述
静态库文件的扩展名一般为.a,其编写步骤很简单。
⑴编写函数代码
⑵编译生成各目标文件
⑶用ar文件对目标文件归档,生成静态库文件。
注意归档文件名必须以lib打头。
使用要点:
⑴在gcc 的-I参数后加上静态库头文件的路径。
⑵在gcc 的-L参数后加上库文件所在目录
⑶在gcc 的-l参数后加上库文件名,但是要去掉lib和.a扩展名。
比如库文件名是libtest.a 那么参数就是 -l test
2、编写最简单的静态库文件
编写如下两个文件,注意放在同一目录中
myalib.h //静态库头文件
myalib.c //静态库实现文件
//myalib.h 文件的内容
void test();
//myalib.c 文件的内容
#inlcude
void test()
{
printf("test\n");
}
3、制作库文件
⑴生成目标文件
gcc -c myalib.c
执行完后会生成一个myalib.o文件
⑵用ar命令归档,格式为ar -rc <生成的档案文件名> <.o文件名列表>
再次提醒,归档文件名一定要以lib打头, .a结尾。
ar -rc libtest.a myalib.o
执行完后会生成一个libtest.a文件
4、使用库文件
⑴编写一个测试程序main.c,内容为
//main.c 测试静态库调用的程序
#include "myalib.h" //要把函数的头文件包含进来,否则编译时会报错
int main(int argc,char* argv[])
{
test();
return 0;
}
⑵编译目标文件,注意要把静态库头文件的路径加到-I参数里面
gcc -I /root/exercise -o main.o -c main.c
现在生成了一个main.o文件
⑶生成可执行文件,注意要把静态库文件的路径加到-L参数里面,
把库文件名(去掉打头的lib和结尾的.a)加到-l参数后面。如下面所示
gcc -o main -L/root/exercise main.o -ltest
此时就会生成一个名为main的可执行文件
另外,注意- l参数好象应该加到输入文件名的后面,否则会报错。
比如gcc -o main -L/root/exercise -ltest main.o就会提示
main.o(.text+0x11): In function `main'':
: undefined reference to `test''
collect2: ld returned 1 exit status
原因我还不清楚:-)
⑷执行可执行文件查看效果
执行./main, 输出
test
说明执行成功。
四、动态库的编写
1、概述
动态库一般以.so结尾,就是shared object的意思.
其基本生成步骤为
⑴编写函数代码
⑵编译生成动态库文件,要加上 -shared 和 -fpic 选项 ,
库文件名以lib开头, 以.so 结尾。
使用方式分为两种: 隐式调用和显示调用
隐式调用类似于静态库的使用,但需修改动态链接库的配置文件/etc/ld.so.conf;
显示调用则是在主程序里使用dlopen、dlsym、dlerror、dlclose等系统函数。
具体的调用方式会在 "五、动态库的调用" 中详细说明.
2、编写最简单的动态库文件
为了便于对照, 我们仍然采用静态库中的文件做例子.
编写如下两个文件,注意放在同一目录中
myalib.h //静态库头文件
myalib.c //静态库实现文件
//myalib.h 文件的内容
void test();
//myalib.c 文件的内容
#inlcude
void test()
{
printf("test\n");
}
3、编译生成动态库 ,库文件名以lib开头, 以.so 结尾。
gcc -fpic -shared -o libtest.so myalib.c
此时就生成一个libtest.so文件
五、动态库的隐式调用
隐式调用的含义是代码里不出现库文件名,就是说这个代码和
调用静态库的代码是类似的。
1、编写测试文件
//main.c 测试动态库隐式调用的程序
#include "myalib.h" //要把函数的头文件包含进来,否则编译时会报错
int main(int argc,char* argv[])
{
test();
return 0;
}
2、 编译测试程序,与静态库类似,要把头文件的路径加到-I参数里面
gcc -I /root/exercise -o main.o -c main.c
现在生成了一个main.o文件
3、连接生成测试程序
gcc -o main -L/root/exercise main.o -ltest
现在生成了一个main文件
4、执行测试程序
./main
此时出现提示
./main: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory。
这个原因就是程序运行时并不知道动态库所在的路径,因此自然找不到。
解决这个问题的办法有三种。见下节
六、使动态库被系统共享的三种办法
(再次说明: 本节参考了计算机世界网雨亦奇的文章"LINUX动态链接库高级应用"
地址http://www.ccw.com.cn/htm/center/prog/02_3_13_3_2.asp)
(1)拷贝动态链接库到系统共享目录下,或在系统共享目录下为该动态链接库
建立连接(硬连接或符号连接均可,常用符号连接).这里说的系统共享目录,
指的是LINUX动态链接库存放的目录,包括
/lib,/usr/lib以及/etc/ld.so.conf文件内所列的一系列目录.
实例:执行
# cp libtest.so /lib
# ldconfig
或:
# ln -s `pwd`/libtest.so /lib
# ldconfig
注意pwd前后有两个反引号`,其目的是取得pwd命令的输出,即当前目录.
此时再执行main,即可成功.
(2)将动态链接库所在目录名追加到动态链接库配置文件/etc/ld.so.conf中.
# pwd >> /etc/ld.so.conf
# ldconfig
此时再执行main,即可成功.
(3)利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入.
# ldconfig `pwd`
此时再执行main,即可成功.
要注意,第三种方法虽然有效,但效果是暂时的,供程序测试还可以,一旦再度运行ldconfig,
则缓存文件内容可能改变,所需的动态链接库可能不被系统共享了.
而且无论哪种办法,其实质都是用ldconfig命令把动态库文件
所在路径加入到系统库列表中,(前两种永久,第三种临时)
补充:ldconfig命令的作用(见最后说明)
七、动态库的显式调用
显式调用的含义是代码出现库文件名,用户需要自己去
打开和管理库文件。其要点为:
⑴把dlfcn.h系统头文件包含进来
⑵用dlopen函数打开库文件,并指定打开方式
dlopen的的第一个参数为共享库的名称,将会在下面位置查找指定的共享库。
①环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录。
②文件/etc/ld.so.cache中找到的库的列表,由ldconfig命令刷新。
③目录usr/lib。
④目录/lib。
⑤当前目录。
第二个参数为打开共享库的方式。有两个取值
①RTLD_NOW:将共享库中的所有函数加载到内存
②RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数
⑶用dlerror()函数测试是否打开成功,并进行错误处理;
⑷用dlsym获得函数地址,存放在一个函数指针中
⑸用获得的函数指针进行函数调用。
⑹程序结束时用dlclose关闭打开的动态库,防止资源泄露。
⑺用ldconfig工具把动态库的路径加到系统库列表中
1、编写测试文件
//main.c 测试动态库显式调用的程序
#include //用于动态库管理的系统头文件
#include "myalib.h" //要把函数的头文件包含进来,否则编译时会报错
int main(int argc,char* argv[])
{
//声明对应的函数的函数指针
void (*pTest)();
//加载动态库
void *pdlHandle = dlopen("libtest.so", RTLD_LAZY);
//错误处理
if(pdlHandle == NULL ) {
printf("Failed load library\n");
return -1;
}
char* pszErr = dlerror();
if(pszErr != NULL)
{
printf("%s\n", pszErr);
return -1;
}
//获取函数的地址
pTest = dlsym(pdlHandle, "test");
pszErr = dlerror();
if(pszErr != NULL)
{
printf("%s\n", pszErr);
dlclose(pdlHandle);
return -1;
}
//实现函数调用
(*pTest)();
//程序结束时关闭动态库
dlclose(pdlHandle);
return 0;
}
2、编译测试文件 使用-ldl选项指明生成的对象模块需要使用共享库
gcc -o main -ldl main.c
执行完后就生成了一个main文件
3、执行测试程序
执行 ./main
输出
test
说明成功。
六、使用动态库时应注意的其他问题
1、无论是动态库的显式调用还是隐式调用,都需要用
ldconfig工具将动态库的路径加到系统库列表中,否则运行时会出错。
2、可以用ldd命令检查程序都使用到哪些共享库
ldd命令行用法如下:
ldd [--version] [-v|--verbose] [-d|--data-relocs] [-r|--function-relocs] [--help] FILE...
各选项说明如下:
(1) --version : 此选项用于打印出ldd的版本号.
(2) -v 或 --verbose : 此选项指示ldd输出关于所依赖的动态链接库的尽可能详细的信息.
(3) -d 或 --data-relocs : 此选项执行重定位,并且显示不存在的函数.
(4) -r 或 --function-relocs : 此选项执行数据对象与函数的重定位,同时报告不存在的对象.
(5) --help : 此选项用于打印出ldd的帮助信息.
我们一般用-v选项.
现在看几个实例
⑴用静态库连接时的结果
#ldd main
libc.so.6 => /lib/tls/libc.so.6 (0xb74ad000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)
可见使用静态库时,由于库已经被编译成程序的一部分,因此ldd的输出中就只有用到的
系统库。
⑵用动态库隐式连接时的结果
libtest.so => /root/exercise/libtest.so (0xb75e2000)
libc.so.6 => /lib/tls/libc.so.6 (0xb74ab000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)
可见隐式使用动态库时,所有用到的动态库(包括系统和用户的)都会被显示出来。
⑶动态库显式连接时的结果
ldd main
libdl.so.2 => /lib/libdl.so.2 (0xb75e1000)
libc.so.6 => /lib/tls/libc.so.6 (0xb74aa000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0xb75eb000)
可见显式使用动态库时,程序中不再保存运行时打开动态库的信息,只保留用到的系统库的信息.
这个与使用静态库时的输出是类似的.
七.补充 :
ldconfig是一个动态链接库管理命令
为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig
ldconfig 命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为 /etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.
ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.
ldconfig命令行用法如下:
ldconfig [-v|--verbose] [-n] [-N] [-X] [-f CONF] [-C CACHE] [-r ROOT] [-l] [-p|--print-cache]
[-c FORMAT] [--format=FORMAT] [-V] [-?|--help|--usage] path...
ldconfig可用的选项说明如下:
(1) -v或--verbose : 用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字.
(2) -n : 用此选项时,ldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib,/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录.
(3) -N : 此选项指示ldconfig不重建缓存文件(/etc/ld.so.cache).若未用-X选项,ldconfig照常更新文件的连接.
(4) -X : 此选项指示ldconfig不更新文件的连接.若未用-N选项,则缓存文件正常更新.
(5) -f CONF : 此选项指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf.
(6) -C CACHE : 此选项指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,此文件存放已排好序的可共享的动态链接库的列表.
(7) -r ROOT : 此选项改变应用程序的根目录为ROOT(是调用chroot函数实现的).选择此项时,系统默认的配置文件 /etc/ld.so.conf,实际对应的为 ROOT/etc/ld.so.conf.如用-r /usr/zzz时,打开配置文件 /etc/ld.so.conf时,实际打开的是/usr/zzz/etc/ld.so.conf文件.用此选项,可以大大增加动态链接库管理的灵活性.
(8) -l : 通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.
(9) -p或--print-cache : 此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字.
(10) -c FORMAT 或 --format=FORMAT : 此选项用于指定缓存文件所使用的格式,共有三种: ld(老格式),new(新格式)和compat(兼容格式,此为默认格式).
(11) -V : 此选项打印出ldconfig的版本信息,而后退出.
(12) -? 或 --help 或 --usage : 这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出.
linux下的共享库机制采用了类似于高速缓存的机制,将库信息保存在/etc/ld.so.cache里边。
程序连接的时候首先从这个文件里边查找,然后再到ld.so.conf的路径里边去详细找。
这就是为什么修改了ld.so.conf要重新运行一下ldconfig的原因
补充一点,ldconfig在/sbin里面。
发表评论
-
tomcat停止
2012-04-18 12:50 0#!/bin/sh #kill tomcat pid ... -
ubuntu 装mysql
2012-04-12 13:37 739最近项目好急,没时间整理,特做以下记录 去mysql网 ... -
red hat 安装svn
2012-03-23 16:34 1289素材: httpd-2.2.22.tar subve ... -
linux 当前shell指定java版本
2012-02-16 09:41 2874装了red hat 5.4,系统默认自带了Java 1.4, ... -
U盘安装red hat.
2012-02-09 10:50 1007没有DVD光盘和DVD光驱,悲剧啊,还好,网上有工具。 ... -
linux 下samba使用简介
2011-12-06 16:46 1086今天装了一台真正的linux主机(red hat),呵呵。安装 ... -
Shell学习
2011-11-30 17:32 732类unix操作系统中有b shell, k shell, c ... -
gdb调试linux0.11内核。
2011-11-26 16:13 15471. 下载bochs源码,配置,编译。 ./con ... -
red hat的远程桌面 xmanager
2011-11-04 14:49 2983用virtualbox装好red hat之后,我们可 ... -
virtual box中安装red hat并实现 ftp功能
2011-11-03 15:49 1701由于在公司上网,公司有个防火墙,安装虚拟主机需要虚 ... -
bochs调试linux 0.11内核
2011-07-01 15:24 6737学习操作系统,最难的就是 ... -
关于linux程序在内存中的分布管理
2011-05-27 10:54 1677这段时间,一直在看汇编,想学习一下li ... -
solaris mount细节
2011-04-11 14:33 9791. 首先确保 nfs server ... -
linux file open的实质
2011-03-30 17:36 2045linux open file的时候到底做了什么呢 ... -
linux-gcc 编译时头文件和库文件搜索路径(转)
2011-03-11 11:16 1684一、头文件 gcc 在编译时寻找所需要的头文件 : ※ ... -
linux extern关键字的作用2
2011-03-09 17:13 1468extern int O_RDONLY; #includ ... -
GCC 参数详解(转载)
2011-03-01 10:29 1098gcc and g++分别是gnu的c &am ... -
linux extern关键字的作用
2011-02-25 17:28 2893extern 的作用是起到一个 ... -
linux 可执行文件依赖库查看
2011-02-25 12:24 5641在多线程编程中,我们用gcc -Wall -g ... -
c语言编译全过程(转)
2011-02-25 10:46 1182C语言编译全 ...
相关推荐
Linux 库文件的介绍及制作 在windows平台和linux平台下都存在着大量的库。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。 由于windows和linux的本质不同,因此二者库的二进制是不兼容的...
第一章 移植内核 2 1.1 Linux内核基础知识 2 1.1.1 Linux版本 2 1.1.2 什么是标准内核 2 1.1.3 Linux操作系统的分类 3 1.1.4 linux内核的选择 4 ...2.2.5 制作根文件系统映像文件 26 第三章 启动系统 26 第四章 总结 34
第一章 移植内核... 2 1.1 Linux内核基础知识... 2 1.1.1 Linux版本...... 1.1.2 什么是标准内核......1.1.3 Linux操作系统的分类......1.1.4 linux内核的选择......1.2 Linux内核启动过程...2.2.5 制作根文件系统映像文件... 26
kafka C++ linux 编译后的动态库文件,含.h和so文件,编译环境:g++4.x, centos.
2.Linux库文件 静态库:在编译阶段加载(将库文件的代码加载到源文件) 动态库:在运行时加载 3.生成可执行文件存在的区别(优缺点) (1)使用静态库生成的可执行文件大于动态库生成的可执行文件(程序占用的内存较...
动态库的制作: 方法一: gcc -c -fPIC add.c sub.c div.c mul.c //-c表示生成.o目标文件,-f后加一些编译选项,PIC表示与位置无关 gcc -shared -o libmymath.so add.o sub.o mul.o div....
QCustomPlot的windows版本库和linux版本库。QCustomPlot是一个基于Qt C++的图形库,用于绘制和数据可视化 - 制作漂亮的2D图 - 曲线图、趋势图、坐标图、柱状图等,并为实时可视化应用程序提供高性能服务。它没有...
所需要的制作静态库以及动态库的代码文件
用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开、读取、写和关闭)提供用户接口。系统调用接口的作用就像是交换器,它将系统调用从用户空间发送到内核空间中...
第一章:Linux内核移植和根文件系统制作 第一章 移植内核..................................................................................................... 2 1.1 Linux 内核基础知识.........................
3.lvim工作方式、gcc、gdb用法、动态库和静态库的制作与使用、makefile的编写语法,以及makefile里面的模式匹配、函数、伪目标等知识,以及文件描述符、文件操作(open、close、lseek、stat、dup等语法) 3.进程:进程...
动态库*.so在linux下用c和c++编程时经常需要使用。 1、动态库的编译 下面通过一个例子来介绍如何生成一个动态库。这里有一个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将这几个文件...
第一节:tslib1.0移植 第二节:QT4.7.0 在ARM平台移植 第三节:boa web服务器在PC上移植 第四节:boa web服务器在S3C2440开发板上移植 第五节:boa移植过程中出现的...第十二节:使用 busybox 制作 Linux 根文件系统
4.2.4. yaffs文件系统制作 8 4.2.5. QT/E库使用 8 4.2.6. NFS挂载介绍 10 5. IP电话系统设计与实现 12 5.1. 系统实现的功能和特点 12 5.2. 通信功能的设计与实现 13 5.2.1. Linphone库的移植 13 5.2.2. 通信功能实现...
将该文件复制到安装目录的相应库下,可以解决Qt不能输入中文的问题,适用于最新版的Qt5.4以上
ar 档案文件和库文件管理程序 as 汇编器 asa 回车控制 at 在指定时间执行程序 awk 模式搜索和处理语言 banner 制作标题 basename 生成文件基本名(无前。后缀) batch 命令的延迟执行 bc 计算器 bdiff 大型...
一、内容概况 QGIS是一个开源的、跨平台的地理信息系统...包含有头文件include、库文件so等,提供了Debug、Release版本。 当前采用的版本为FreeType-2.12.1,如果下载者,需要其他版本的FreeType,请在评论区留言。
针对Linux平台编译了WebRTC的C++库文件,发现许多库都是经过压缩的不能直接使用,于是自己制作了一个库的打包小工具。 使用方法: 1.下载rearchive.sh 2.进入库目录 $ cd trunk/out/Debug/obj.target 3.执行小工具 $...
一、内容概况 QGIS是一个开源的、跨平台的地理信息系统(GIS...包含有头文件include、库文件so等,提供了Debug、Release版本。 当前采用的版本为OpenJpeg-2.5.0,如果下载者,需要其他版本的OpenJpeg,请在评论区留言。
一、内容概况 QGIS是一个开源的、跨平台的地理信息系统(GIS)软件...包含有头文件include、库文件so等,提供了Debug、Release版本。 当前采用的版本为curl-7.86.0,如果下载者,需要其他版本的curl,请在评论区留言。