化妆品商城网站建设,wordpress php注释,wordpress 全屏,电商网站怎么做的gcc生成静态库和动态库一、库文件简介简单地说#xff0c;库#xff08;Library#xff09;就是一组已经写好了的函数和变量、经过编译代码#xff0c;是为了能够提高开发效率和运行效率而设计的。库分为静态库#xff08;Static Library#xff09;和共享库#xff08;…gcc生成静态库和动态库一、库文件简介简单地说库Library就是一组已经写好了的函数和变量、经过编译代码是为了能够提高开发效率和运行效率而设计的。库分为静态库Static Library和共享库Shared library两类。静态库文件的扩展名是.a共享库文件的扩展名是.so在CYGWIN环境下分别叫做.o和.dll。共享库现在常常被叫做动态库是由于很多人借用了MS Windows的DLLDynamic Linked Library这个词。1静态库静态是指每个用到该库的应用程序都拥有一份自己的库拷贝应用程序运行的时候即使将库删除也没有问题因为应用程序自己已经有了自己的拷贝。2共享库一个共享库有可能被多个所有应用程序共享。因此对每个应用程序来说即使不再使用某个共享库也不应将其删除。此外应用程序需要正确的环境变量设置LD_LIBRARY_PATH从而找到共享库所在的位置否则应用程序运行时会报告找不到这个库。二、关于使用库的问题如果库是已经编译好的那么如何在开发、运行应用程序时使用呢头文件和库文件所在的路径必须通过适当的方式通知给编译器、链接器和相关的应用程序。对于静态库来说主要涉及开发工具如gcc。例如用gcc编译、链接时需要通过适当的路径找到头文件和静态库文件实现的方法有两种gcc的命令行参数-I, -Lshell的环境变量C_INCLUDE_PATH, LIBRARY_PATH对于共享库来说程序在运行时如果用到了动态库也需要找到对应的动态库文件实现的方法shell的环境变量LD_LIBRARY_PATH1 gcc命令行参数-I, -L默认情况下gcc会自动搜索下面的路径对头文件/usr/local/include//usr/include/对库文件/usr/local/lib//usr/lib/但是由于系统管理员对系统安装路径有不同的配置或者对于如64位系统等情况上述路径对于一台具体的计算机来说可能不同。如果开发者还有自己工程所需的头文件和库文件就要用gcc的-I和-L来指定对应的路径。如果需要链接库还要用-l选项。例如如果工程涉及到GDBMGNU DataBase Management包需要libgdbm库而系统中安装GDBM的路径是头文件/opt/gdbm-1.8.3/include库文件/opt/gdbm-1.8.3/lib/那么gcc的命令参数是$gcc … -I/opt/gdbm-1.8.3/include -L/opt/gdbm-1.8.3/lib –lgdbm注意为保证兼容性必须坚决杜绝在C/C源文件的#include语句中或者其他相关语句中使用上述路径。2 shell环境变量Environmental Variable除了用命令行参数还可以用环境变量来指示gcc搜索适当的路径。而由于Shell的不同环境变量的设置方法也不同。常用的Shell有Bash, Csh和Tcsh。1Bash对于Bash来说除了由系统管理员配置的内容以外每个用户的用户目录$HOME下有个.bash_profile文件。可在该文件内增加下面的两个语句来设置GDBM头文件路径的环境变量C_INCLUDE_PATH/opt/gdbm-1.8.3/includeexport C_INCLUDE_PATH类似地在该文件内用下面的两个语句来设置库文件路径的环境变量LIBRARY_PATH/opt/gdbm-1.8.3/libexport LIBRARY_PATH在.bash_profile中有了上述语句以后就不用再使用-I和-L来搜索特定包的路径了。但是链接库的时候还是要用-l选项。$gcc … –lgdbm在Bash下要检查有什么样的环境变量可用env命令。$env2Csh和Tcsh如果是Csh或Tcsh对环境变量的设置方法就不同了。在用户的$HOME目录下相关的一些文件如下.cshrc 每次进入Csh时的启动(Startup)文件.tcshrc 每次进入Tcsh时的启动(Startup)文件在Tcsh下如果没有这个文件系统会用.cshrc文件代替.login 每次登录Shell时的启动(Startup)文件在Csh和Tcsh下分为Shell变量和环境变量前者是用来设置Shell本身的而后者则是供其他程序使用的。一般习惯是Shell变量在.cshrc中定义而环境变量则在.login文件中定义。定义Shell变量的方法是在.cshrc或.tcshrc中用set语句set history 20定义环境变量的方法是在.login文件中用setenv语句。对于上面关于GDBM的例子setenv C_INCLUDE_PATH /opt/gdbm-1.8.3/includesetenv LIBRARY_PATH /opt/gdbm-1.8.3/lib在Csh和Tcsh下可以用setenv命令来查看设置了哪些环境变量如果要看Shell变量要用set命令。注意- 设置Shell变量时要用“”号- 设置环境变量时变量名与实际值这里是真实路径之间没有“”号;- 不需要export。3 使用共享库使用共享库的应用程序要通过环境变量LD_LIBRARY_PATH找到对应的共享库文件。与其他环境变量一样对LD_LIBRARY_PATH也要根据shell的种类和库文件的实际路径进行设置。但是必须注意的是与一般的环境变量不同LD_LIBRARY_PATH的值是已经安装了的所有共享库的路径因此在Bash下不能简单地用下面的办法LD_LIBRARY_PATH/opt/gdbm-1.8.3/lib 错误export LD_LIBRARY_PATH而必须用LD_LIBRARY_PATH/opt/gdbm-1.8.3/lib:$LD_LIBRARY_PATHexport LD_LIBRARY_PATH这样就把其他共享库的路径也一起加入进来了。同样地在Csh和Tcsh下setenv LD_LIBRARY_PATH /opt/gdbm-1.8.3/lib:$LD_LIBRARY_PATH三、关于库生成的问题我们通常把一些公用函数制作成函数库供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中而是在程序运行是才被载入因此在程序运行时还需要动态库存在。1
静态库简单地说静态库是一个目标文件的简单集合。因此首先要解决目标文件。第一步将各函数代码所在的源文件编译成目录文件。例如对于myfunc.c, myproc.cgcc -c myfunc.c myproc.c将得到myfunc.o和myproc.o。第二步由ararchive归档的意思把多个目标文件集合起来。$ar -r libmyjob.a myfunc.o myproc.o通常静态库的命名方式应遵守libXXXXX.a格式。应用程序在使用静态库的时候通常只需要把命名中的XXXXX部分传递给gcc即可。例如$gcc –o mywork –lmyjob …意为让gcc实际上是gcc调用ld去连接一个名字为libmyjob.a或者libmyjob.so的库。如果库的命名不遵循libXXXXX.a的格式就找不到相应文件。例子创建静态库hello.h为该函数库的头文件。hello.c是函数库的源程序其中包含公用函数hello该函数将在屏幕上输出hello XXX!。main.c为测试库文件的主程序在主程序中调用了公用函数hello。程序1//hello.h#ifndef HELLO_H#define HELLO_Hvoid hello(const char *name);#endif程序2//hello.c#include stdio.hvoid hello(const char *name){printf(hello %s! /n,name);}程序3//main.c#include hello.hint main(){hello(everyone);return 0;}实现步骤第一步必须将源程序hello.c通过gcc先编译成.o文件生成hello.o静态库/动态库都是由.o文件创建的第二步由.o文件创建静态库,生成libmyhello.a静态库文件名的命名规范是以lib为前缀紧接着跟静态库名扩展名为.a创建静态库用ar命令第三步在程序中使用静态库只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明然后在用gcc命令生成目标文件时指明静态库名gcc将会从静态库中将公用函数连接到目标文件中。注意gcc会在静态库名前加上前缀lib然后追加扩展名.a得到的静态库文件名来查找静态库文件第四步删除静态库文件程序照常运行静态库中的公用函数hello已经连接到目标文件main中了。运行[rootlocalhost moduletest]# lshello.c hello.h main.c [rootlocalhost moduletest]# gcc -c hello.c[rootlocalhost moduletest]# lshello.c hello.h hello.o main.c[rootlocalhost moduletest]# ar crv libmyhello.a hello.oa - hello.o[rootlocalhost moduletest]# lshello.c hello.h hello.o libmyhello.a main.c[rootlocalhost moduletest]# gcc main.c libmyhello.a -o main [rootlocalhost moduletest]# ./main hello everyone! [rootlocalhost moduletest]# rm -f libmyhello.a [rootlocalhost moduletest]# lshello.c hello.h hello.o main main.c[rootlocalhost moduletest]# ./main hello everyone! [rootlocalhost moduletest]# 2
共享库共享库的构造复杂一些通常是一个ELF格式的文件。可以有三种方法生成$ld -G$gcc -shared$libtool用ld最复杂用gcc -share就简单的多但是-share并非在任何平台都可以使用。GNU提供了一个更好的工具libtool专门用来在各种平台上生成各种库。用gcc的-shared参数gcc –shared –o libmyjob.so myjob.o这样就通过myjob.o生成了共享库文件libmyjob.so。特别地在CYGWIN环境下仍需要输出符合Windows命名的共享库动态库即libXXXXX.dll。如gcc –shared –o libmyjob.dll myjob.o例子创建动态库延用上面的程序123实现步骤第五步由.o文件创建动态库文件命令gcc -shared -fPCI -o libmyhello.so hello.o第六步在程序中使用动态库在程序中使用动态库和使用静态库完全一样也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明然后在用gcc命令生成目标文件时指明动态库名进行编译。程序在运行时会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到则载入动态库否则将提示错误信息而终止程序运行。要将文件libmyhello.so复制到目录/usr/lib中运行[rootlocalhost moduletest]# lshello.c hello.h hello.o main.c[rootlocalhost moduletest]# gcc -shared -fPIC -o libmyhello.so hello.o[rootlocalhost moduletest]# lshello.c hello.h hello.o libmyhello.so main.c[rootlocalhost moduletest]# gcc main.c libmyhello.so -o main[rootlocalhost moduletest]# lshello.c hello.h hello.o libmyhello.so main main.c[rootlocalhost moduletest]# ./main./main: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory[rootlocalhost moduletest]# mv libmyhello.so /usr/lib可以[rootlocalhost moduletest]# lshello.c hello.h hello.o main main.c[rootlocalhost moduletest]# ./mainhello everyone! [rootlocalhost moduletest]# 或者[rootlocalhost moduletest]# rm -f main[rootlocalhost moduletest]# lshello.c hello.h hello.o main.c[rootlocalhost moduletest]# gcc -Wall -g main.c -lmyhello -o main[rootlocalhost moduletest]# lshello.c hello.h hello.o main main.c[rootlocalhost moduletest]# ./main hello everyone! [rootlocalhost moduletest]#注意 当静态库和动态库同名时 gcc命令将优先使用动态库。3库生成以后的配置如果要把自己开发的库文件安装到操作系统中需要有管理员权限(a) 把库文件复制到适当的目录可以把自己开发的动态连接库放到/usr/local/lib或者/usr/lib或放到其他目录但不论放在那里都必须与LIBRARY_PATH的值、LD_LIBRARY_PATH的值相一致。(b) 修改相关的系统配置文件修改/etc/ld.so.conf然后利用/sbin/ldconfig来完成。 Note:编译参数解析最主要的是GCC命令行的一个选项:-shared 该选项指定生成动态连接库让连接器生成T类型的导出符号表有时候也生成弱连接W类型的导出符号不用该标志外部程序无法连接。相当于一个可执行文件l -fPIC表示编译为位置独立的代码不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要而不能达到真正代码段共享的目的。l -L.表示要连接的库在当前目录中l -ltest编译器查找动态连接库时有隐含的命名规则即在给出的名字前面加上lib后面加上.so来确定库的名称l LD_LIBRARY_PATH这个环境变量指示动态连接器可以装载动态库的路径。l 当然如果有root权限的话可以修改/etc/ld.so.conf文件然后调用 /sbin/ldconfig来达到同样的目的不过如果没有root权限那么只能采用输出LD_LIBRARY_PATH的方法了。调用动态库的时候有几个问题会经常碰到有时明明已经将库的头文件所在目录 通过 “-I” include进来了库所在文件通过 “-L”参数引导并指定了“-l”的库名但通过ldd命令察看时就是死活找不到你指定链接的so文件这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。