zoukankan      html  css  js  c++  java
  • 使用gcc生成静态库和动态库

    盘古开天辟地。我们写了个程序,想要给终端输出一些内容,不可避免地我们需要使用系统库,在我们写程序的过程中我们经常会碰到需要使用库的过程,无论是系统库还是第三方库,我们统称为lib库。

    而库的链接分为两种,分别有静态库和动态库。

    1. 静态库

    静态库可以看作一堆的目标文件的集合,可能包含了很多函数的实现。在linux最常用的C语言静态库libc位于/usr/lib/libc.a,它由成百上千个C语言程序,比如输入输出有printf.o,scanf.o,文件操作有fread.o,fwrite.o等等。把这些零散的文件提供给使用者会造成不便,于是通常人们用ar压缩程序将这些目标文件压缩到一起,然后对这些文件进行编号和索引,最后形成了libc.a这个文件。

    运行命令查看其中包含的内容,然后过滤查看fread

    $  ar -t /usr/lib/x86_64-linux-gnu/libc.a | grep fread
    iofread.o
    __freading.o
    __freadable.o
    iofread_u.o
    fread_chk.o
    fread_u_chk.o
    

    如果我们要在其中寻找printf.o文件可以使用命令

    $ objdump -t /usr/lib/x86_64-linux-gnu/libc.a | grep printf.o
    vfprintf.o:     文件格式 elf64-x86-64
    vprintf.o:     文件格式 elf64-x86-64
    reg-printf.o:     文件格式 elf64-x86-64
    fprintf.o:     文件格式 elf64-x86-64
    printf.o:     文件格式 elf64-x86-64
    snprintf.o:     文件格式 elf64-x86-64
    sprintf.o:     文件格式 elf64-x86-64
    asprintf.o:     文件格式 elf64-x86-64
    dprintf.o:     文件格式 elf64-x86-64
    vfwprintf.o:     文件格式 elf64-x86-64
    fxprintf.o:     文件格式 elf64-x86-64
    iovsprintf.o:     文件格式 elf64-x86-64
    fwprintf.o:     文件格式 elf64-x86-64
    swprintf.o:     文件格式 elf64-x86-64
    vwprintf.o:     文件格式 elf64-x86-64
    wprintf.o:     文件格式 elf64-x86-64
    vswprintf.o:     文件格式 elf64-x86-64
    vasprintf.o:     文件格式 elf64-x86-64
    iovdprintf.o:     文件格式 elf64-x86-64
    vsnprintf.o:     文件格式 elf64-x86-64
    obprintf.o:     文件格式 elf64-x86-64
    

    可以看到printf.o文件就在其中。

    假如以我们写的helloworld.c程序为例

    #include <stdio.h>
    
    int main(int argc, char *argv[])
    {
    	printf("Hello,World!
    ");
    	return 0;
    }
    

    默认情况下直接运行

    $ gcc helloworld.c -o helloworld
    

    会进行动态链接,我们查看生成的文件大小

    $ ls -l helloworld
    -rwxr-xr-x 1 gnc gnc 8304 10月 11 15:06 helloworld
    

    可以看到大小为8303bytes,我们使用选项-static来使gcc进行静态链接:

    $ gcc -static helloworld.c -o helloworld
    

    查看大小

    $ ls -l helloworld
    -rwxr-xr-x 1 gnc gnc 844704 10月 11 15:09 helloworld
    

    可以看到大小显著变大。

    2. 动态库

    静态链接好处就是链接完成以后,运行程序不需要原来的支持库,但缺点是文件大小较大,并且更新困难。

    所以出现了动态链接,也就是不要静态地进行链接,而是等到动态运行时再进行链接。动态链接的符号定位是发生在运行时首先进行地址空间分配,然后再来运行程序。

    具体的链接过程也比较复杂,我们只需要知道如何来创建这种动态库即可。

    3. gcc创建静态和动态库

    源文件add.c

    /* add.h */
    void setSummand(int summand);
    int  add(int summand);
    
    /* add.c */
    #include <stdio.h>
    
    int gSummand;
    
    
    void setSummand(int summand) {
      gSummand = summand;
    }
    
    int add(int summand) {
      return gSummand + summand;
    }
    
    void __attribute__ ((constructor)) initLibrary(void) {
     //
     // Function that is called when the library is loaded
     //
        printf("Library is initialized
    "); 
        gSummand = 0;
    }
    void __attribute__ ((destructor)) cleanUpLibrary(void) {
     //
     // Function that is called when the library is »closed«.
     //
        printf("Library is exited
    "); 
    }
    

    源文件answer.c

    /* answer.h */
    int answer();
    
    /* answer.c */
    #include "add.h"
    
    int answer() {
    
      setSummand(20);
      return add(22);  // Will return 42 (=20+22)
    
    }
    
    
    

    源文件main.c

    #include <stdio.h>
    #include "add.h"
    #include "answer.h"
    
    int main(int argc, char* argv[]) {
    
      setSummand(5);
    
      printf("5 + 7 = %d
    ", add(7));
    
      printf("And the answer is: %d
    ", answer());
    
      return 0;
    }
    
    

    然后我们创建目录.bin/static./bin/shared

    完成以后的目录结构如下

    $ tree
    .
    ├── add.c
    ├── add.h
    ├── answer.c
    ├── answer.h
    ├── bin
    │   ├── shared
    │   └── static
    └── main.c
    
    3 directories, 5 files
    
    

    我们运行命令生成目标文件

    $ gcc -c       main.c        -o bin/main.o
    
    # 静态库
    $ gcc -c       add.c    -o bin/static/add.o
    $ gcc -c       answer.c -o bin/static/answer.o
    
    # 动态库
    gcc -c -fPIC add.c    -o bin/shared/add.o
    gcc -c -fPIC answer.c -o bin/shared/answer.o
    
    

    3.1 创建静态库

    运行命令

    $ ar rcs bin/static/libtq84.a bin/static/add.o bin/static/answer.o
    
    

    将两个目标文件打包压缩为一个静态库文件。

    静态链接

    $ gcc bin/main.o -Lbin/static -ltq84 -o bin/static-main
    
    

    运行

    $ ./bin/static-main 
    Library is initialized
    5 + 7 = 12
    And the answer is: 42
    Library is exited
    
    

    3.2 创建动态库

    运行命令

    $ gcc -shared bin/shared/add.o bin/shared/answer.o -o bin/shared/libtq84.so
    
    

    然后进行动态链接

    $ gcc  bin/main.o -Lbin/shared -ltq84 -o bin/use-shared-library
    
    

    运行

    $ ./bin/use-shared-library 
    ./bin/use-shared-library: error while loading shared libraries: libtq84.so: cannot open shared object file: No such file or directory
    
    

    会提示找不到动态链接库,我们需要修改LD_LIBRARY_PATH变量来指向我们的动态库路径

    export LD_LIBRARY_PATH=$(pwd)/bin/shared
    
    

    然后再运行

    ./bin/use-shared-library 
    Library is initialized
    5 + 7 = 12
    And the answer is: 42
    Library is exited
    
    

    就可以了,当然你也可以选择将该动态库放置到路径/usr/lib下,运行下面的命令

    sudo mv bin/shared/libtq84.so /usr/lib
    sudo chmod 755 /usr/lib/libtq84.so
    
    
  • 相关阅读:
    vue 使用echarts 柱状图使用图片显示
    Devexpress分组小计
    小写转大写
    预览打印
    LINQ
    结束任务管理器进程
    游标
    查看死锁
    sql 分页
    压缩解压缩传输的数据
  • 原文地址:https://www.cnblogs.com/cporoske/p/11654730.html
Copyright © 2011-2022 走看看