动静态库的制作

文章目录


前言

我们通过C/C++语言写的代码是源代码,对任何人来说是可见的,没有安全性可言,但是,在实际开发中,出于技术保密或其它方面考虑,开发者并不希望提供公用函数库的源代码,所以C/C++提供了一个可以保证代码安全性的方法,把公共的程序文件编译成库文件。库有静态库、动态库。希望通过本文能够帮到你!


一、什么是动静态库

首先,一般能让机器运行的程序的是二进制文件,也叫机器码文件,但是,二进制文件如果没有经过链接(C语言编译原理)的过程的话,二进制文件不能能被系统运行。库是一种二进制文件,不能运行,它是没有被链接的,也没有main函数。库分为静态库、动态库。  

(1)编译原理

C语言编译分为四个步骤:

  1. 预处理(预编译):这一步主要就是对C源代码文件中的头文件导入和宏定义的替换。
  2. 编译:这一步是进行C语言语法的检测,如果没有错误,则生成汇编文件。                
  3. 汇编:这一步是对汇编文件进行语法检测,如果没有错误,则生成机器码,但此时的机械码是无法运行的(动静态库的制作也是从这一步开始的)。                                    
  4. 链接:由于上一步的汇编过程生成的机器码文件缺乏一些库,是无法运行的,通过链接才能生成一个真正运行的文件。                                                                                    

 所对应的命令如下:

gcc -E test.c -o test.i//预处理
gcc -S test.i -o test.s//编译
gcc -c test.s -o test.o//汇编
gcc test.o -o test//链接

(2)静态库

静态库一般表示为libxxx.a,其中lib是库的前缀,xxx是库的名字,.a是库的后缀。

静态库是经过ar编译器生成出来的。

使用静态库的时候,静态库是和调用者融合在一起编译生成程序的。

劣势:静态库由于将目标文件和静态库文件一起打包,当我们得程序比较复杂,功能比较多的时候,会让我们的程序文件会变大好多,这让我们的文件加载到内存中的时间就会边长。最直接的例子就是,当我们双击打开一个软件的时候,要很久才能看到界面,这就是弊端。

优势:生成的程序可以在任意主机上运行,因为库也被编译进去了,所以没有对应的库我们也能运行。

(3)动态库

动态库一般表示为libxxx.so,其中lib是库的前缀,xxx是库的名字,.so是库的后缀。

静态库是经过gcc编译器生成出来的。

使用动态库的时候,动态库没有和调用者融合在一起编译生成程序,只是链接让编译器自己去看库里面的代码而已。

劣势:动态库是在程序运行时完成加载的,库并没有编译到我们的二进制文件当中,所以在运行程序的时候需要通过动态库的环境变量来动态链接库才能运行。(拖家带口

优势:使用动态库的程序的体积要比使用静态库程序的体积小。


二、如何制作动静态库

(1)制作静态库

1、准备一些要制作静态库的C源文件 

add.c:用来制作静态库。

main.c: 调用静态库中的成员(函数或者变量)。

// add.c

int add(int a, int b)
{
    return a+b;
}
// main.c

#include <stdio.h>

int add(int a, int b);//调用的时候需要声明

int main()
{
    int a = 20, b = 10;
    int c = add(a,b);
    printf("a+b=%d\n",c);
    return 0;
}

2、将add.c编译成add.o文件,如下图

3、用ar工具将add.o文件编译成libadd.a文件,如下图

4、调用库的.c文件和.a库文件一起生成程序,最终运行程序,如下图

 至此,静态库的制作基本结束了,接下来对第三个步骤中出现的ar 命令之后的 rcs 的参数进行解析。

rcs参数的解析:

  • r:在库中加入成员文件,如果要加入的成员文件在库中已经存在,则替换之。
  • c:创建一个库。
  • s:这个参数理解起来相比前面两个有一点点抽象,我们在制作静态库的时候,会生成一个库符号索引表的东西,当我们需要用来库里面的成员的时候,它可以帮助我们快速链接到成员。加入这个s参数,在生成库的时候,就会将库里面的这个表重新生成最新的。其实感觉就是一个目录。

(2)制作动态库

1、准备一些要制作动态库的C源文件 main.c add.c add.h 这里文件有些改动,方便后面参数的说明。

//add.h
#ifndef __ADD_H_
#define __ADD_H_

#include <stdio.h>
int add(int a, int b);

#endif __ADD_H

// add.c
#include "add.h"

int add(int a, int b)
{
    return a+b;
}

// main.c
#include <stdio.h>
#include "add.h"

int main()
{
    int a = 20, b = 10;
    int c = add(a,b);
    printf("a+b=%d\n",c);
    return 0;
}

2、将add.c编译成add.o文件,如下图 

3、用gcc工具将add.o文件编译成libadd.so文件,如下图

 其实,第二步骤和第三步骤可以合并起来成为一步,具体命令如下

gcc -fPIC -shared add.c -o libadd.so

4、使用生成的动态库

 上图可以看出,我们在使用动态库的时候编译没有报错,但是我们在运行我们生成的二进制文件的时候,就报错了,一般来说,我们在运行需要链接动态库的程序的时候,往往都会失败,系统找不到这个动态库。具体解决措施如下:

第一种:将我们的动态库移动到系统的/lib(永久生效

即:mv ~/test1/a/libadd.so /lib   (具体路径根据自己实际情况而定)

第二种:配置系统的动态库环境变量,将自己生成的动态库的路径添加对应文件当中,具体命令如下:

  1. 生效一次:export LD_LIBRARY_PATH=/home/gec/test1/a/:$LD_LIBRARY_PATH
  2. 永久生效:export  LD_LIBRARY_PATH=/home/gec/test1/a/:$LD_LIBRARY_PATH将这条命令添加到~/.bashrc配置文件中的最后一行 (具体路径根据自己实际情况而定)

 可以看到,按照上面的操作之后,就可以运行我们得程序了。

至此,静态库的制作基本结束了,接下里对制作动态库过程出现的参数进行解析。

fPIC:动态链接代码,让代码与内存地址无关。可在任意内存地址中执行代码。(看不懂)

shared:创建动态库。

对第四步骤种命令gcc main.c -o demo -L. -ladd进行解析。

为了方便理解,将制作动态库的文件进行分类,如图。

如果要进行第四步骤的操作(使用生成的动态库),可以使用如下命令:

gcc main.c -o demo -Iinclude/ -Llib/ -ladd  

 其中的I(大写的i)、L、l(小写的L)。

I(大写的i):告诉编译器在哪里找头文件

L:告诉编译器在哪里找库

l(小写的L):要链接哪个动态库,写库名(本文例子就是add)

具体效果如下:

(3)静态库的动态编译、动态库的静态编译

  • 静态库
    • 静态编译:把库和调用的.c一起编译: gcc xxx.c libadd.a -o xxx
    • 动态编译:库和调用库的代码是一起融合编译生成程序的,也就是说程序中已经包含了整个静态库 gcc xxx.c -o xxx -L. -ladd libadd.so
  • 动态库
    • 动态编译:只是链接动态库的位置而已,并没有把动态库加到程序 gcc main.c -o demo -ladd -L./
    •  静态编译:只是链接动态库的位置而已,并没有把动态库加到程序 gcc main.c libadd.so -o demo

上面的命令具体路径要根据自己的实际情况而定。(其实静态库的动态编译、动态库的静态编译没什么作用


总结

有关动静态的基本制作到这里结束了,希望能够帮到你!(有用的话,帮哦点点赞,互相学习!)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值