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下即可。

posted @ 2013-03-02 14:07  摩斯电码  阅读(410)  评论(0编辑  收藏  举报