linux库文件撰写入门一、为什么要用于库文件我们在实际编程工作中认同不会遇上这种情况:有几个项目里有一些函数模块的功能完全相同,构建代码也完全相同,也是我们所说的反复代码。比如,很多项目里都有一个用户检验的功能。代码段如下://UserLogin.h文件,获取函数声明intIsValidUser(char*username,intnamelen);//UserLogin.c文件,构建对用户信息的检验intIsValidUser(char*username,intnamelen){intIsValid=0;/*下面是明确的处置代码,省略*/returnIsValid}如果每个项目都留存着这两个UserLogin.h和UserLogin.c文件,不会有以下几个弊端:1、每个项目里都有反复的模块,导致代码反复。
2、代码的器重性很差,一旦IsValidUser的代码再次发生了变化,为了维持设计的一致性,我们还要手工改动其他项目里的UserLogin.c文件,既费时又费力,还更容易错误。库文件就是对公共代码的一种的组织形式。
为了解决问题上面两个弊端,就明确提出了用库文件存放在公共代码的解决方案,其要点就是把公共的(也就是可以被多次适配的)目标代码从项目中分离出来,统一存放在到库文件中,项目要中用这些代码的时候,在编译器或者运营的时候从库文件中获得目标代码才可。库文件又分两种:静态库和动态库。二、静态库与动态库如果程序是在编译器时读取库文件的,就是用于了静态库。如果是在运营时读取目标代码,就沦为动态库。
换句话说,如果是用于静态库,则静态库代码在编译器时就拷贝到了程序的代码段,程序的体积不会收缩。如果用于动态库,则程序中只保有库文件的名字和函数名,在运营时去查询库文件和函数体,程序的体积基本变化并不大。
静态库的原则是以空间换时间,减少程序体积,增加运行时间;动态库则是以时间换空间,减少了运行时间,但增加了程序本身的体积。下面我们就以实际例子来想到如何用于这两种库.三、静态库的撰写和用于1、阐述静态库文件的扩展名一般为.a,其撰写步骤很非常简单。⑴撰写函数代码⑵编译器分解各目标文件⑶用ar文件对目标文件文档,分解静态库文件。
留意归档文件名必需以lib打头。用于要点:⑴在gcc的-I参数后再加静态库头文件的路径。
⑵在gcc的-L参数后再加库文件所在目录⑶在gcc的-l参数后再加库文件名,但是要去除lib和.a扩展名。比如库文件名是libtest.a那么参数就是-ltest2、撰写最简单的静态库文件撰写如下两个文件,留意放到同一目录中myalib.h//静态库头文件myalib.c//静态库构建文件//myalib.h文件的内容voidtest();//myalib.c文件的内容#inlcudestdio.hvoidtest(){printf(test\n);}3、制作库文件⑴分解目标文件gcc-cmyalib.c继续执行完了后不会分解一个myalib.o文件⑵用ar命令文档,格式为ar-rc分解的档案文件名.o文件名列表再度警告,归档文件名一定要以lib打头,.a结尾。
ar-rclibtest.amyalib.o继续执行完了后不会分解一个libtest.a文件4、用于库文件⑴撰写一个测试程序main.c,内容为//main.c测试静态库调用的程序#includemyalib.h//要把函数的头文件包括进去,否则编译器时会报错intmain(intargc,char*argv[]){test();return0;}⑵编译器目标文件,留意要把静态库头文件的路径特到-I参数里面gcc-I/root/exercise-omain.o-cmain.c现在分解了一个main.o文件⑶分解可执行文件,留意要把静态库文件的路径特到-L参数里面,把库文件名(去除打头的lib和结尾的.a)特到-l参数后面。如下面右图gcc-omain-L/root/exercisemain.o-ltest此时就不会分解一个取名为main的可执行文件另外,留意-l参数好象应当特到输出文件名的后面,否则不会报错。
比如gcc-omain-L/root/exercise-ltestmain.o就不会提醒main.o(.text+0x11):In`main''''::undefinedreferenceto`test''''collect2:ldreturned1exitstatus原因我还不确切:-)⑷继续执行可执行文件查阅效果继续执行./main,输入test解释继续执行顺利。四、动态库的撰写1、阐述动态库一般以.so结尾,就是sharedobject的意思.其基本分解步骤为⑴撰写函数代码⑵编译器分解动态库文件,要再加-shared和-fpic选项,库文件名以lib结尾,以.so结尾。
用于方式分成两种:隐式调用和表明调用隐式调用类似于静态库的用于,但须要改动动态链接库的配置文件/etc/ld.so.conf;表明调用则是在主程序里用于dlopen、dlsym、dlerror、dlclose等系统函数。明确的调用方式不会在五、动态库的调用中详尽解释.2、撰写最简单的动态库文件为了便于对照,我们依然使用静态库中的文件做到例子.撰写如下两个文件,留意放到同一目录中myalib.h//静态库头文件myalib.c//静态库构建文件//myalib.h文件的内容voidtest();//myalib.c文件的内容#inlcudestdio.hvoidtest(){printf(test\n);}3、编译器分解动态库,库文件名以lib结尾,以.so结尾。gcc-fpic-shared-olibtest.somyalib.c此时就分解一个libtest.so文件五、动态库的隐式调用隐式调用的含义是代码里不经常出现库文件名,就是说这个代码和调用静态库的代码是类似于的。1、撰写测试文件//main.c测试动态库隐式调用的程序#includemyalib.h//要把函数的头文件包括进去,否则编译器时会报错intmain(intargc,char*argv[]){test();return0;}2、编译器测试程序,与静态库类似于,要脖子文件的路径特到-I参数里面gcc-I/root/exercise-omain.o-cmain.c现在分解了一个main.o文件3、相连分解测试程序gcc-omain-L/root/exercisemain.o-ltest现在分解了一个main文件4、继续执行测试程序./main此时经常出现提醒./main:errorwhileloadingsharedlibraries:libtest.so:cannotopensharedobjectNosuchfileordirectory。
这个原因就是程序运行时并不知道动态库所在的路径,因此大自然去找将近。解决问题这个问题的办法有三种。闻下节六、使动态库被系统分享的三种办法(再度解释:本节参照了计算机世界网雨亦奇的文章LINUX动态链接库高级应用于地址http://.cn/htm/center/prog/02_3_13_3_2.asp)(1)拷贝动态链接库到系统分享目录下,或在系统分享目录下有该动态链接库创建相连(软相连或符号相连均可,常用符号相连).这里说道的系统分享目录,所指的是LINUX动态链接库存放在的目录,还包括/lib,/usr/lib以及/etc/ld.so.conf文件内所列的一系列目录.实例:继续执行#cplibtest.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命令把动态库文件所在路径重新加入到系统库列表中,(前两种永久,第三种临时)七、动态库的显式调用显式调用的含义是代码经常出现库文件名,用户必须自己去关上和管理库文件。
其要点为:⑴把dlfcn.h系统头文件包括进去⑵用dlopen函数关上库文件,并登录打开方式dllope的的第一个参数为分享库的名称,将不会在下面方位查询登录的分享库。①环境变量LD_LIBRARY_PATH所列的用分号间隔的所有目录。
②文件/etc/ld.so.cache中寻找的库的列表,由ldconfig命令创下。③目录usr/lib。
④目录/lib。⑤当前目录。第二个参数为关上分享库的方式。
有两个给定①RTLD_NOW:将分享库中的所有函数读取到内存②RTLD_LAZY:不会推迟分享库中的函数的读取操作者,直到调用dlsym()时方读取某函数⑶用dlerror()函数测试否关上顺利,并展开错误处理;⑷用dlsym取得函数地址,存放在一个函数指针中⑸用取得的函数指针展开函数调用。⑹程序完结时用dlclose重开关上的动态库,避免资源泄漏。⑺用ldconfig工具把动态库的路径特到系统库列表中1、撰写测试文件//main.c测试动态库显式调用的程序#includedlfcn.h//用作动态库管理的系统头文件#includemyalib.h//要把函数的头文件包括进去,否则编译器时会报错intmain(intargc,char*argv[]){//声明对应的函数的函数指针void(*pTest)();//读取动态库void*pdlHandle=dlopen(libtest.so,RTLD_LAZY);//错误处理if(pdlHandle==NULL){printf(Failedloadlibrary\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);return0;}2、编译器测试文件用于-ldl选项说明分解的对象模块必须用于分享库gcc-omain-ldlmain.c继续执行完了后就分解了一个main文件3、继续执行测试程序继续执行./main输入test解释顺利。
六、用于动态库时应留意的其他问题1、无论是动态库的显式调用还是隐式调用,都必须用ldconfig工具将动态库的路径特到系统库列表中,否则运营时会错误。2、可以用ldd命令检查程序都用于到哪些分享库ldd命令行用法如下:ldd[--version][-v|--verbose][-d|--data-relocs][-r|---relocs][--help]FILE...各选项解释如下:(1)--version:此选项用作打印机出有ldd的版本号.(2)-v或--verbose:此选项命令ldd输入关于所倚赖的动态链接库的尽量详尽的信息.(3)-d或--data-relocs:此选项继续执行重定位,并且表明不不存在的函数.(4)-r或---relocs:此选项继续执行数据对象与函数的重定位,同时报告不不存在的对象.(5)--help:此选项用作打印机出有ldd的协助信息.我们一般用-v选项.现在看几个实例⑴用静态库相连时的结果#lddmainlibc.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)可见隐式用于动态库时,所有中用的动态库(还包括系统和用户的)都会被表明出来。
⑶动态库显式相连时的结果lddmainlibdl.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)可见显式用于动态库时,程序中仍然留存运营时关上动态库的信息,只保有中用的系统库的信息.这个与用于静态库时的输入是类似于的.。
本文关键词:E体育客户端下载,E体育客户端下载最新版V7.24.568,E体育客户端下载(中国)官方网站·IOS/手机版APP下载/APP
本文来源:E体育客户端下载-www.lsbdh.com