GCC 指令详解及动态库、静态库的使用( 四 )

编译、链接、运行,一气呵成:

GCC 指令详解及动态库、静态库的使用

文章插图
2.2.5 ar 命令参数介绍制作静态库时所使用的指令$ ar rcs libcalc.a add.o sub.o mult.o div.o共有三个参数:
  • -c:创建一个库,不管库是否存在,都将创建 。这个很好理解,就不做过多的解释了 。
  • -r:在库中插入(替换)模块。默认新的成员添加在库的结尾处,如果模块名已经在库中存在,则替换同名的模块 。
  • -s:创建目标文件索引,这在创建较大的库时能加快时间 。
参数 -r 的详细解释
假设现在有了新的需求,需要静态库 libcalc.a 提供除法运算的功能模块 , 该怎么操作呢?
首先我们需要新建一个除法运算的源文件 div.c:
#include <stdio.h>double divide(int a, int b){return (double)a / b;}并通过汇编操作生成目标文件 div.o 。
接下来我们可以通过 -r 参数将除法运算的模块添加到静态库中:$ ar -r libcalc.a div.o
并且要在 head.h 中增加对除法运算的声明:
#ifndef _HEAD_H_#define _HEAD_H_// Otherdouble divide(int a, int b);#endif参数 -s 的详细解释
在获取一个静态库的时候,我们可以通过$ nm -s libcalc.a来显示库文件中的索引表:
GCC 指令详解及动态库、静态库的使用

文章插图
而索引的生成就要归功于 -s 参数了 。
如果不需要创建索引 , 可改成 -S 参数 。
如果 libcalc.a 缺少索引 , 可以使用$ ranlib libcalc.a 指令添加 。
2.2.6 其他命令介绍# 显示库文件中有哪些目标文件,只显示名称$ ar t libcalc.a# 显示库文件中有哪些目标文件,显示文件名、时间、大小等详细信息$ ar tv libcalc.a# 显示库文件中的索引表$ nm -s libcalc.a# 为库文件创建索引表$ ranlib libcalc.a2.3 动态库2.3.1 动态库简介在 Linux 中动态库以 lib 作为前缀、以 .so 作为后缀,形如 libxxx.so(其中的 xxx 是库的名字,自己指定即可) 。相比于静态库,使用动态库的程序,在程序编译时并不会链接到目标代码中,而是在运行时才被载入 。不同的应用程序如果调用相同的库,那么在内存中只需要有一份该共享库的实例,避免了空间浪费问题 。同时也解决了静态库对程序的更新的依赖,用户只需更新动态库即可 。
2.3.2 动态库的生成生成动态库是直接使用 gcc 命令,并且需要添加 -fpic 以及 -shared 参数:
  • -fpic 参数的作用是使得 gcc 生成的代码是与位置无关的 , 也就是使用相对位置 。
  • -shared 参数的作用是告诉编译器生成一个动态链接库 。

GCC 指令详解及动态库、静态库的使用

文章插图
2.3.3 动态库的制作举例还是以上述程序 add.c、sub.c、mult.c 为例:
# 第一步:将源文件 add.c、sub.c、mult.c 进行汇编,得到二进制目标文件 add.o、sub.o、mult.o$ gcc -c -fpic add.c sub.c mult.c# 第二步:将得到的 .o 文件打包成动态库$ gcc -shared add.o sub.o mult.o -o libcalc.so# 第三步:发布动态库和头文件1. 提供头文件 head.h2. 提供动态库 libcalc.so至于为什么需要提供头文件,在讲解静态库时已经做了说明,此处不再赘述 。
2.3.4 动态库的使用head.h
#ifndef _HEAD_H_#define _HEAD_H_int add(int a, int b);int subtract(int a, int b);int multiply(int a, int b);#endifmain.c
#include <stdio.h>#include "head.h"int main(){int a = 20;int b = 12;printf("a = %d, b = %d\n", a, b);printf("a + b = %d\n", add(a, b));printf("a - b = %d\n", subtract(a, b));printf("a * b = %d\n", multiply(a, b));return 0;}和静态库的链接方式一样,都是通过指令$ gcc main.c -o main -L ./ -l calc来进行链接库操作 。
gcc 通过指定的动态库信息生成了可执行程序 main , 但是可执行程序运行却提示无法加载到动态库:
./main: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory
这是怎么回事呢?
2.3.5 解决动态库加载失败的问题首先来看一下不同库的工作原理:
  1. 静态库如何被加载:
    • 在程序编译的最后一个阶段也就是链接阶段,提供的静态库会被打包到可执行程序中 。
    • 当可执行程序被执行,静态库中的代码也会一并被加载到内存中,因此不会出现静态库找不到无法被加载的问题 。
  2. 动态库如何被加载:

    推荐阅读