zoukankan      html  css  js  c++  java
  • linux下库文件的编程

      编程到了一定的时候,总喜欢追求新的东西。将代码尽量模块化就是我的追求之一,原来只是满足于将代码从单文件中分离,通过头文件和实现文件实现模块化,后来发现最好的方法是打包成库文件,使用更加方便。尽管在linux和windows下都有大量的库文件,由于二者的工具不同,加上笔者主要是在linux下编程和教学,因此本文主要介绍Linux下的库文件的制作。

      库文件在linux中主要有两种:静态库和动态库(共享库),二者的不同主要有:

      1、载入时机不同:静态库是在编译时进行载入到代码中;共享库在运行时载入到代码中;

      2、对生成的可执行文件的影响不同:静态库的缺失不会影响后期可执行文件的运行;共享库的缺失会影响可执行文件的执行;

      3、对可执行文件大小改变不同:静态库在编译过程中将所有文件添加到可执行文件中,生成可执行文件偏大;共享库在编译过程中将所有文件链接到可执行文件中,生成的可执行文件几乎没有增大;

      4、后期维护的影响不同:静态库可能会重复应用,浪费空间;共享库更容易引用使用,只需要一份库实现多个文件的共享使用;

      5、后缀名称不同:静态库的后缀名是.a; 动态库的后缀名是.so;

      6、生成方式不同:静态库主要是gcc将*.c文件形成*.o文件,使用ar命令打包成.a文件即可;动态库文件主要由gcc加上特定参数编译生成

      7、形成的可执行文件的执行方式不同:静态库生成的可执行文件直接执行即可;动态库生成的可执行文件执行时须保证动态库文件能够被找到:可以将动态库文件链接或复制到/usr/lib或/lib目录,一般不这样做;设置环境变量LD_LIBRARY_PATH,使用命令export  LD_LIBRARY_PATH=$(pwd);使用命令ldconfig目录,将制定目录下的动态链接库被系统共享起来sudo ldconfig /home/munication/WORKM/libDemo/;

      作为现成的库文件,一般都具有成熟可靠、能够复用、接口明确等特点。因此,善于利用库文件,会让初学者很容易站在巨人的肩膀上。

      下面为了更好的说明问题,通过三种方式来形成一个可执行文件testCal,功能很简单。

      一、不是用库的方式,代码add.c、sub.c、mul.c、div.c、mod.c、cal.h testCal.c都是一样的:

    add.c  

     1 int add(int var1, int var2){                                                
     2     return var1 + var2;
     3 }

    sub.c

     1 int sub(int var1, int var2){                                                
     2     return var1 - var2;
     3 }

    mul.c

     1 int mul(int var1, int var2){                                                
     2     return var1 * var2;
     3 }

    div.c

     1 int div(int var1, int var2){                                                
     2     if(0==var2){
     3         return -1;
     4     }else{
     5         return var1 / var2;
     6     }
     7 }

    mod.c

     1 int mod(int var1, int var2){                                                
     2     return var1 % var2;
     3 } 

    cal.h

     1 #ifndef cal_h
     2 #define cal_h
     3                                                                             
     4 int add(int, int);
     5 int sub(int, int);
     6 int mul(int, int);
     7 int div(int, int);
     8 int mod(int, int);
     9 
    10 #endif

    testCal.c

     1 #include <stdio.h>
     2 
     3 #include "cal.h"
     4 
     5 int main(int argc, char **argv)
     6 {
     7     int var1;
     8     int var2;
     9     printf("please input the var1: ");
    10     scanf("%d", &var1);
    11     printf("please input the var2: ");
    12     scanf("%d", &var2);
    13     printf("%d add %d is %d
    ", var1, var2, add(var1, var2));
    14     printf("%d sub %d is %d
    ", var1, var2, sub(var1, var2));
    15     printf("%d mul %d is %d
    ", var1, var2, mul(var1, var2));
    16     printf("%d div %d is %d
    ", var1, var2, div(var1, var2));
    17     printf("%d mod %d is %d
    ", var1, var2, mod(var1, var2));               
    18 
    19     return 0;
    20 }

      这个是附加的文件makefile,文件名称为makefile

     1 OBJ=testCal.o add.o sub.o mul.o div.o mod.o
     2 testCal:$(OBJ) cal.h
     3     gcc -o testCal $(OBJ)
     4 testCal.o:testCal.c
     5 add.o:add.c
     6 sub.o:sub.c
     7 mul.o:mul.c
     8 div.o:div.c
     9 mod.o:mod.c
    10
    11 .PHONY:cleanA clean
    12 cleanA:
    13     rm testCal $(OBJ)                                                       
    14 clean:
    15     rm $(OBJ)

      如果有上边的makefile文件,下面的操作都是假设上边所有的文件:add.c  cal.h  div.c  makefile  mod.c  mul.c  sub.c  testCal.c都在/home/munication/WORKM/libDemo/目录下

      终端下到/home/munication/WORKM/libDemo/目录下,

      使用下面的目录生成可执行文件,并有下面的提示信息: 

    make
    cc    -c -o testCal.o testCal.c
    cc    -c -o add.o add.c
    cc    -c -o sub.o sub.c
    cc    -c -o mul.o mul.c
    cc    -c -o div.o div.c
    cc    -c -o mod.o mod.c
    gcc -o testCal testCal.o add.o sub.o mul.o div.o mod.o 

      如果其中的文件更改,可以使用同一个命令make即可重新编译生成新的执行文件,make会自动判断那些文件需要编译,如果需要把中间文件删除,使用命令make clean,提示信息为;

    make clean                                             #删除中间文件*.o,保留testCal可执行文件
    make cleanA   #删除所有生成文件,包括中间文件*.o,最终testCal可执行文件
    rm testCal.o add.o sub.o mul.o div.o mod.o          #删除中间文件*.o,保留testCal可执行文件
    rm testCal testCal.o add.o sub.o mul.o div.o mod.o   #删除所有生成文件,包括中间文件*.o,最终testCal可执行文件

      如果不用makefile文件,可以使用手工命令:

    gcc -c add.c sub.c mul.c div.c mod.c testCal.c      #形成目标文件
    gcc -o testCal testCal.o add.o sub.o mul.o div.o mod.o #生成可执行文件
    rm testCal.o add.o sub.o mul.o div.o mod.o         #删除中间文件*.o,保留testCal可执行文件
    rm testCal testCal.o add.o sub.o mul.o div.o mod.o    #删除所有生成文件,包括中间文件*.o,最终testCal可执行文件
        

      查看文件大小:

    [munication@develop libDemo]$ ls -l
    总用量 40
    -rw-r--r-- 1 munication munication   52 7月   9 12:39 add.c
    -rw-r--r-- 1 munication munication  132 7月   9 12:55 cal.h
    -rw-r--r-- 1 munication munication   91 7月   9 12:41 div.c
    -rw-r--r-- 1 munication munication  235 7月   9 14:55 makefile
    -rw-r--r-- 1 munication munication   52 7月   9 12:42 mod.c
    -rw-r--r-- 1 munication munication   52 7月   9 12:40 mul.c
    -rw-r--r-- 1 munication munication   52 7月   9 12:40 sub.c
    -rwxr-xr-x 1 munication munication 7388 7月   9 14:53 testCal
    -rw-r--r-- 1 munication munication  517 7月   9 13:02 testCal.c

      很明显,可以看出形成的可执行文件的大小是7388字节,7k字节的大小。

      执行可执行文件,使用命令:

    [munication@develop libDemo]$ testCal 
    please input the var1: 14
    please input the var2: 3
    14 add 3 is 17
    14 sub 3 is 11
    14 mul 3 is 42
    14 div 3 is 4
    14 mod 3 is 2

      二、使用静态库文件,生成静态库。库文件一般以lib为前缀,紧接着是库的名称,扩展名为.a,例如我们这里要创建库名libcal.a的库,使用命令ar,具体如下:

    ar rcs libcal.a add.o sub.o mul.o div.o mod.o

      使用静态库,创建库文件的接口文件头文件,本文中是cal.h文件,使用库文件的文件testCal.c包含头文件cal.h文件即可,使用如下命令编译:

    gcc -o testCal testCal.c -static -L. -lcal

      其中上边命令的说明:

      (1)、gcc -o testCal:使用gcc编译,-o指定文件名,后边的testCal就是最终生成的文件名

      (2)、-static:指明使用静态库

      (3)、-L.:-L指明使用库,后面的.表明库文件在当前目录

      (4)、-lcal:表明是库文件的名称,其中-表明是选项,l是lib的简写,后边的cal才是真正的库文件名称,后缀名是不需要的

      查看文件的大小:

    [munication@develop libDemo]$ ls -l
    总用量 764
    -rw-r--r-- 1 munication munication     52 7月   9 12:39 add.c
    -rw-r--r-- 1 munication munication    132 7月   9 12:55 cal.h
    -rw-r--r-- 1 munication munication     91 7月   9 12:41 div.c
    -rw-r--r-- 1 munication munication   4608 7月   9 15:10 libcal.a
    -rw-r--r-- 1 munication munication    235 7月   9 14:55 makefile
    -rw-r--r-- 1 munication munication     52 7月   9 12:42 mod.c
    -rw-r--r-- 1 munication munication     52 7月   9 12:40 mul.c
    -rw-r--r-- 1 munication munication     52 7月   9 12:40 sub.c
    -rwxr-xr-x 1 munication munication 740140 7月   9 15:16 testCal
    -rw-r--r-- 1 munication munication    517 7月   9 13:02 testCal.c

      可以很明显看出:使用静态库文件的可执行文件的大小为740140字节,超过700k字节

      执行可执行文件,使用命令:

    [munication@develop libDemo]$ testCal 
    please input the var1: 14
    please input the var2: 3
    14 add 3 is 17
    14 sub 3 is 11
    14 mul 3 is 42
    14 div 3 is 4
    14 mod 3 is 2

      三、使用动态库文件:生成动态库文件。库文件一般以lib为前缀,紧接着是库的名称,扩展名为.so,例如我们这里要创建库名libcal.so的库,具体如下: 

    [munication@develop libDemo]$ make
    cc    -c -o testCal.o testCal.c
    cc    -c -o add.o add.c
    cc    -c -o sub.o sub.c
    cc    -c -o mul.o mul.c
    cc    -c -o div.o div.c
    cc    -c -o mod.o mod.c
    gcc -o testCal testCal.o add.o sub.o mul.o div.o mod.o 

      以上,先运行make命令,通过makefile文件生成目标文件testCal.o add.o sub.o mul.o div.o mod.o,接着使用下面命令:

    gcc -shared -fPIC -o libcal.so add.o sub.o mul.o div.o mod.o

      其中上边命令的说明:

      (1)、gcc -o libcal.so:使用gcc编译,-o指定文件名,后边的libcal.so就是最终生成的动态库名

      (2)、-shared:指明生成动态库

      (3)、-fPIC.:该选项告诉gcc产生的代码不要包含对函数和变量具体内存位置的引用,运行时进行地址链接

    gcc -o testCal testCal.c -L. -lcal

      其中上边命令的说明:

      (1)、gcc -o testCal:使用gcc编译,-o指定文件名,后边的libcal.so就是最终生成可执行文件名称

      (2)、没有使用-static:指明使用动态库

      (3)、-L.:-L指明使用库,后面的.表明库文件在当前目录

      (4)、-lcal:表明是库文件的名称,其中-表明是选项,l是lib的简写,后边的cal才是真正的库文件名称,后缀名是不需要的

      查看文件大小:

    [munication@develop libDemo]$ ls -l
    总用量 56
    -rw-r--r-- 1 munication munication   52 7月   9 12:39 add.c
    -rw-r--r-- 1 munication munication  132 7月   9 12:55 cal.h
    -rw-r--r-- 1 munication munication   91 7月   9 12:41 div.c
    -rw-r--r-- 1 munication munication 4608 7月   9 15:10 libcal.a
    -rwxr-xr-x 1 munication munication 6832 7月   9 15:51 libcal.so
    -rw-r--r-- 1 munication munication  235 7月   9 14:55 makefile
    -rw-r--r-- 1 munication munication   52 7月   9 12:42 mod.c
    -rw-r--r-- 1 munication munication   52 7月   9 12:40 mul.c
    -rw-r--r-- 1 munication munication   52 7月   9 12:40 sub.c
    -rwxr-xr-x 1 munication munication 7296 7月   9 16:01 testCal
    -rw-r--r-- 1 munication munication  517 7月   9 13:02 testCal.c

      可以很明显看出:使用动态库文件的可执行文件的大小为7296字节,超过7k字节,比不打包成库大了一点,多了链接信息,比静态库小了很多,差不多只有静态库的1%大小。

      执行可执行文件时,可能会出现错误,提示找不到动态库文件libcal.so文件,解决方案主要有如下几种:

      (1)、将生成的库文件libcal.so文件复制到目录/usr/lib或者/lib目录中,这种方式容易污染系统的库文件,也可以将自己作的库文件libcal.so链接到/usr/lib或/lib中,再次执行可执行文件就正常了;

      (2)、连接器会搜索LD_LIBRARY_PATH指定的目录,将该环境变量设置为当前目录,具体命令为:

    export  LD_LIBRARY_PATH=$(pwd)

      (3)、使用命令ldconfig目录,将制定目录下的动态链接库被系统共享起来,具体命令为:

    sudo ldconfig /home/munication/WORKM/libDemo/

       最后的附加:可以使用命令ldd查看可执行文件执行时调用的动态库,具体命令为:

    [munication@develop libDemo]$ ldd testCal
            linux-gate.so.1 (0xb777d000)
            libcal.so => /home/munication/WORKM/libDemo/libcal.so (0xb7745000)
            libc.so.6 => /usr/lib/libc.so.6 (0xb7585000)
            /lib/ld-linux.so.2 (0xb777f000)

      gcc编译时搜索库文件的顺序,可以通过一定的手段覆盖系统的库文件,一般不要这么做,后果可能会很严重。

      静态库链接时搜索路径顺序:
      (1). ld 会去找 GCC 命令中的参数-L
      (2). 再找 gcc 的环境变量 LIBRARY_PATH
      (3). 再找内定目录 /lib /usr/lib /usr/local/lib 这是当初 compile gcc 时写在程序内的
      动态链接时、执行时搜索路径顺序:
      (1). 编译目标代码时指定的动态库搜索路径;
      (2). 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径;
      (3). 配置文件/etc/ld.so.conf 中指定的动态库搜索路径;
      (4). 默认的动态库搜索路径/lib;
      (5). 默认的动态库搜索路径/usr/lib。
      有关环境变量:
      (1).LIBRARY_PATH 环境变量:指定程序静态链接库文件搜索路径
      (2).LD_LIBRARY_PATH 环境变量:指定程序动态链接库文件搜索路径

      

  • 相关阅读:
    javascript 3秒钟后自动跳转到前一页面
    meta
    HTML 5 label
    WCF的ABC
    由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面。
    ECMASCRIPT5新特性(转载)
    bin目录正.pdb是什么文件?
    PS切图的相关技巧
    MongoVUE破解方法
    ASP.NET MVC Area操作
  • 原文地址:https://www.cnblogs.com/guochaoxxl/p/7141447.html
Copyright © 2011-2022 走看看