• linux环境下库的制作和升级


    库是一种可以执行代码的二进制形式。可以被操作系统载入内存执行。

    linux环境下的库分为静态库和动态库(又称为共享库)。

    使用静态库,将来目标的体积大,升级复杂(是对使用者说的),但是可移植性好,浪费磁盘空间和内存空间;

    使用动态库,将来目标的体积小,升级简单(是对使用者说的),但是可移植性不好,节约磁盘空间和内存空间,还有一个好处是,不同应用程序如果调用相同的库,那么在内存中只需要一份该共享库的实例。

    一、静态库的制作

    先看一下目录结构

    20130301_192905_thumb

     

     

     

     

     

    其中,libtest/main.c 用于测试静态库,可以看做库的使用者,main.c是测试程序。joseph/和list/目录下面是将要制作成库的文件。

    先看一下这些文件中的部分内容:

    main.c

    #include "joseph.h"   //注意:这里的头文件路径的具体写法要看测试时main.c和得到的头文件的具体放置位置,如果他们在同一级目录下,就是左边这种写法。
    
    int main(void)
    {
        joseph();
        return 0;
    }

    joseph.h

       1:  #ifndef __JOSEPH_H__
       2:  #define __JOSEPH_H__
       3:   
       4:  #define N 8
       5:  #define K 3
       6:  #define M 4
       7:  extern void joseph(void);
       8:   
       9:  #endif

    joseph.c

    #include "joseph.h"
    #include "../list/listlinkloop.h"      //注:这里的头文件路径不用改,因为是库的开发者,各个模块都有自己的目录,生成.o 文件时,会自动根据这个路径把相应的头文件拷贝过来
    #include <stdlib.h> 
    #include <stdio.h>
    
    
    void joseph(void)
    {
        listlinkloop *l = listcreate();
    
        listlinkloop *temp1, *temp2;
        int i;
    
        for(i=1; i<=N; i++)
        {
            listinserttail(l, i);
        }
    
        temp1 = listcuthead(l); 
    
        for(i=1; i<K; i++)
        {
            temp1 = temp1->next;
        }
    
        while(temp1->next != temp1)
        {
            for(i=2; i<M; i++)
            {
                temp1 = temp1->next;
            }
    
            temp2 = temp1->next;
            temp1->next = temp2->next;
            printf("%d ", temp2->data);
            free(temp2);
            temp1 = temp1->next;
        }
    
        printf("%d\n",temp1->data);
        free(temp1);
    }

    listlinkloop.h

       1:  #ifndef __LISTLINKLOOP_H__
       2:  #define __LISTLINKLOOP_H__
       3:   
       4:  typedef int listdata;
       5:   
       6:  typedef struct list
       7:  {
       8:      listdata data;
       9:      struct list *next;
      10:  }listlinkloop;
      11:   
      12:   
      13:  extern void listprintf(listlinkloop *l);
      14:  extern void listinserttail(listlinkloop *l, listdata data);
      15:  extern listlinkloop *listcreate(void);
      16:  extern void listinserthead(listlinkloop *l, listdata data);
      17:  extern listlinkloop *listcuthead(listlinkloop *l);
      18:  #endif

     

    listlinkloop.c

    #include "listlinkloop.h"
    #include <stdlib.h>
    #include <stdio.h>
    
    listlinkloop *listcreate(void)
    {
        listlinkloop *l = (listlinkloop *)malloc(sizeof(listlinkloop));
    
        l->next = l;
    
        return l;
    }
    
    void listinserthead(listlinkloop *l, listdata data)
    {
        
        listlinkloop *temp1 = (listlinkloop *)malloc(sizeof(listlinkloop));
    
        temp1->data = data;
        temp1->next = l->next;
    
        l->next = temp1;
    }
    
    listlinkloop *listcuthead(listlinkloop *l)
    {
        listlinkloop *temp = l;
    
        while(temp->next != l)
        {
            temp = temp->next;
        }
    
        temp->next = l->next;
    
        free(l);
        return (temp->next);
    }
    
    void listinserttail(listlinkloop *l, listdata data)
    {
        listlinkloop *temp1 = (listlinkloop *)malloc(sizeof(listlinkloop));
        listlinkloop *temp2 = l;
    
        temp1->data = data;
        temp1->next = l;
        while(temp2->next != l)
        {
            temp2 = temp2->next;
        }
        
        temp2->next = temp1;
    }
    
    void listprintf(listlinkloop *l)
    {
        listlinkloop *temp = l;
    
        while(temp->next != l)
        {
             printf("%d \n", temp->next->data);
             temp = temp->next;
        }
        printf("\n");
    }
    
    void listloopprintf(listlinkloop *l)
    {
        listlinkloop *temp = l;
    
        printf("%d ",temp->data);
    
        while(temp->next != l)
        {
            printf("%d ", temp->next->data);
            temp = temp->next;
        }
        printf("\n");
    }

     

    步骤:

    • 进入joseph/,然后执行命令

                  gcc –c joseph.c –o joseph.o         //-c 只激活预处理、编译和汇编,目的是生成目标文件

    • 在进入list/,执行命令:

                  gcc  -c listlinkloop.c –o listlinkloop.o         //-c 只激活预处理、编译和汇编,目的是生成目标文件

    • 然后就是生成库文件,后缀是 .a 。先进入tmp/,然后执行命令

                    ar crs libpeng.a joseph/joseph.o list/listlinkloop.o

    • 将生成的库文件libpeng.a 和 joseph.h 、listlinkloop.h 移动或者复制到测试目录下,即libtest/,进入libtest/目录,然后执行命令

                   gcc main.c –L . –l peng        //-L . 表示库在当前目录下,如果在其他目录下,如 /home/linux下,则 –L  /home/linux      -l是小写的L,peng是将libpeng.a去掉lib和后缀.a后的部分,编译器自动会在peng的前面加上lib,在peng的后面加上.so,从而构成库的名称。

    • 会生成可执行文件main
    • 最后执行命令  ./main  进行验证

    20130302_122559_thumb

     

    实际上,上面的一些列操作都可以通过Makefile来完成。

    在tmp/ 目录下,编写Makefile

    CFLAGS=-Wall
    CC=gcc
    
    export CC
    libpeng.a:joseph.o listlinkloop.o
        ar crs $@ $^ 
        mv libpeng.a ../libtest/
        cp joseph/joseph.h ../libtest/
        cp list/listlinkloop.h ../libtest/
        make -C ../libtest/
    joseph.o:joseph/joseph.c
        $(CC) $(CFLAGS) -c $^ -o $@ 
    listlinkloop.o:list/listlinkloop.c
        $(CC) $(CFLAGS) -c $^ -o $@ 
    clean:
        $(RM) ./*.o
        $(RM) ./*.a
        $(RM) ../libtest/*.a
        $(RM) ../libtest/*.out
        $(RM) ../libtest/*.h
        $(RM) ../libtest/main
    
    .PHONY:clean


    然后再在libtest/目录下编写Makefile如下:

    main:main.c 
        $(CC) $^ -L . -l peng -o $@


    最后在tmp/目录下输入 make 命令即可完成全部工作。

    静态库升级时,库的开发者需要重新生成新的静态库,库的使用者需要重新进行编译,过程比较麻烦。

     

    二、动态库的制作

    还是以上面的程序为例。

    20130301_192905_thumb[4]

     

     

     

     

     

    第一步、生成目标文件

       进入tmp/joseph/,执行命令:

                  gcc –fPIC  -Wall –c  joseph.c

            进入tmp/listlinkloop/,执行命令:

                  gcc –fPIC  -Wall –c listlinkloop.c

    第二步、程序动态库

              在tmp/下执行命令

                    gcc –shared –Wl,-soname,libpeng.so joseph/joseph.o list/listlinkloop.o –o libpeng.so.1

                    //其中,参数-shared 指定生成动态链接库。-Wl,-soname 将-soname 传递给链接器ld。其中libpeng.so是soname的名字,前者不带版本号。joseph/joseph.o list/listlinkloop.o 是用到的两个目标文件,就是将他们两个制作成动态库。libpeng.so.1 是最终生成的动态库的名字。

     

    第三步、测试

     将生成的动态库文件libpeng.so.1和joseph.h 、listlinkloop.h 移动或者复制到测试目录下,即libtest/,进入libtest/目录,然后执行命令

    1. ln –s /home/linux/jg/libtest/libpeng.so.1 libpeng.so   //目的:生成动态库libpeng.so 的软连接,注意:目标前面必须是绝对路径!
    2. gcc main.c –L . –l peng –o main        //生成可执行文件main,编译器会自动将peng补充完整,变成libpeng.so ,他就是刚才制作的动态库的软连接。-L . 表示动态库的软连接在当前目录下,也就是-L 后跟的是动态库软连接的路径,而非动态库的路径
    3. sudo cp –a libpeng.so /lib    //目的:将软连接本身复制到系统的/lib 目录下,应该以管理员权限完成此项操作。或者 sudo mv libpeng.so /lib。此时在执行时,动态载入器就可以找到动态库的软连接libpeng.so,进而就会找到动态库libpeng.so.1

              

    上面所完成的一些列操作可以通过Makefile来完成。

    进入tmp/目录下,编写Makefile:

    CFLAGS=-Wall -fPIC
    CC=gcc
    
    export CC
    libpeng.a:joseph.o listlinkloop.o
        $(CC) -shared -Wl,-soname,libpeng.so joseph.o listlinkloop.o -o libpeng.so.1
        mv libpeng.so.1 ../libtest/
        cp joseph/joseph.h ../libtest/
        cp list/listlinkloop.h ../libtest/
        make -C ../libtest/
    joseph.o:joseph/joseph.c
        $(CC) $(CFLAGS) -c $^ -o $@ 
    listlinkloop.o:list/listlinkloop.c
        $(CC) $(CFLAGS) -c $^ -o $@ 
    clean:
        $(RM) ./*.o
        $(RM) ./*.a
        $(RM) ../libtest/*.a
        $(RM) ../libtest/*.so
        $(RM) ../libtest/*.out
        $(RM) ../libtest/*.h
        $(RM) ../libtest/main
        sudo rm /lib/libpeng.so
    
    .PHONY:clean

    进入libtest/下,编写另一个Makefile:

    main:main.c 
        ln -s /home/linux/jg/libtest/libpeng.so.1 libpeng.so
        $(CC) $^ -L . -l peng -o $@
        sudo cp -a libpeng.so /lib

    然后再tmp/ 目录下执行 make 命令即可。

    20130302_133941_thumb

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     动态库的升级方法:

    对于库的开发人员需要重新生成新的动态库(按照前面的方法),如libpeng.so.2,对于库的使用者,拿到新的库之后,需要只需要在新库所在的目录下面执行:

              ln –s 新库所在的绝对路径/libpeng.so.2 libpeng.so ,然后把生成的新的链接文件libpeng.so放到/lib下即可。

  • 相关阅读:
    深入理解ThreadLocal
    JAVA守护线程
    JAVA THREAD.JOIN方法详解
    JAVA中断机制详解
    Socket中的异常和参数设置
    WebSocket实战
    程序里面的system.out.println()输出到其他位置,不输出到tomcat控制台。
    数据库连接未关闭,conn与rs未关闭
    Ajax简单应用-购物车
    1.链表和数组的区别在哪里?
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/2940017.html
Copyright © 2020-2023  润新知