嵌入式学习③——编译器背后的故事

本文深入探讨了GCC在Linux环境下编译静态库与动态库的过程,包括创建静态库与动态库的步骤,以及如何在程序中使用这些库。通过实例展示了使用gcc创建静态库libmyhello.a和动态库libmyhello.so,并解释了静态库与动态库的链接和使用。同时,文章提到了GCC编译器背后的预处理、编译、汇编和链接过程,以及ELF文件格式的相关知识。此外,还介绍了nasm汇编器的使用以及curses库在Linux程序设计中的应用。
摘要由CSDN通过智能技术生成


前言

源文件经过编译器编译后才可生成二进制文件,编译过程包括预处理、编译、汇编和链接,日常交流中常用“编译”称呼此四个过程。编译器是一系列工具的集合,如arm平台使用的交叉编译器arm-linux-gcc包括arm-linux-cpp(compiler preprocessor预处理)、arm-linux-cc1(c compiler编译)、arm-linux-as(assembly 汇编)、arm-linux-ld(linker链接)等工具。常见的编译器种类如:GCC、VC等
我们这次就以GCC为例,学习编译器背后的故事


一、可执行程序的组装

1.用gcc生成静态库和动态库

我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。

本文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们。

1.1 用gcc生成静态库和动态库

1.1.1创建静态库

- 第 1 步:编辑生成例子程序 hello.h、hello.c 和 main.c

创建一个作业目录,保存本次练习的文件。

#mkdir test1
#cd test1

用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的 3 个文件
在这里插入图片描述

hello.c(见程序 2)是函数库的源程序,其中包含公用函数 hello,该函数将在屏幕上输出"HelloXXX!"。hello.h(见程序 1)为该函数库的头文件。main.c(见程序 3)为测试库文件的主程序,在主程序中调用了公用函数 hello。

程序 1: hello.h

#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO_H

程序 2: hello.c

#include <stdio.h>
void hello(const char *name)
{
   
printf("Hello %s!\n", name);
}

程序 3: main.c

#include "hello.h"
int main()
{
   
hello("everyone");
return 0;
}

- 第 2 步:将 hello.c 编译成.o 文件。

无论静态库,还是动态库,都是由.o 文件创建的。因此,我们必须将源程序 hello.c 通过 gcc 先编译成.o文件。在系统提示符下键入以下命令得到 hello.o 文件。

在这里插入图片描述
运行 ls 命令看看是否生存了 hello.o 文件。

在 ls 命令结果中,我们看到了 hello.o 文件,本步操作完成。

下面我们先来看看如何创建静态库,以及使用它。

- 第 3 步:由.o 文件创建静态库
静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。

例如:我们将创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用 ar 命令。在系统提示符下键入以下命令将创建静态库文件
libmyhello.a

# ar -crv libmyhello.a hello.o
#

我们同样运行 ls 命令查看结果:

在这里插入图片描述

ls 命令结果中有 libmyhello.a

- 第 4 步:在程序中使用静态库

静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用 gcc命令生成目标文件时指明静态库名,gcc 将会从静态库中将公用函数连接到目标文件中。

注意:gcc 会在静态库名前加上前缀 lib,然后追加扩展名.a 得到的静态库文件名来查找静态库文件。

我们删除静态库文件试试公用函数 hello 是否真的连接到目标文件 hello 中了。在这里插入图片描述
程序照常运行,静态库中的公用函数已经连接到目标文件中了。

1.1.2创建动态库

- 第 1 步:由.o 文件创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其文件扩展名为.so。例如:我们将创建的动态库名为 myhello,则动态库文件名就是 libmyhello.so。用 gcc 来创建动态库。
在这里插入图片描述

- 第 2 步:在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明动态库名进行编译。我们先运行 gcc 命令生成目标文件,再运行它看看结果。

在这里插入图片描述
系统找不到动态库文件 libmyhello.so。程序在运行时,会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。

在这里插入图片描述
这也进一步说明了动态库在程序运行时是需要的。

先删除除.c 和.h 外的所有文件,恢复成我们刚刚编辑完举例程序状态。
在这里插入图片描述
再来创建静态库文件 libmyhello.a 和动态库文件 libmyhello.so。
在这里插入图片描述

通过上述最后一条 ls 命令,可以发现静态库文件 libmyhello.a 和动态库文件 libmyhello.so都已经生成,并都在当前目录中。

然后,我们运行 gcc 命令来使用函数库 myhello 生成目标文件 hello,并运行程序 hello。

在这里插入图片描述
注意:动态库和静态库同时存在时,优先使用动态库,当然,如果直接#gcc main.c libmyhello.a -o hello 的话,就是指定为静态库了

1.2 静态库.a与.so库文件的生成与使用

先创建一个作业目录,保存本次练习的文件。

在这里插入图片描述
然后用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的四个文件 A1.c 、A2.c、 A.h、test.c 。

- 静态库.a 文件的生成与使用
1、生成目标文件(xxx.o) ---> gcc -c A1.c A2.c
2、生成静态库.a 文件---> ar crv libafile.a A1.o A2.o

在这里插入图片描述
3、使用.a 库文件,创建可执行程序(若采用此种方式,需保证生成的.a 文件与.c 文件保存在同一目录下,即都在当前目录下)
---> gcc -o test test.c libafile.a ---> ./test

在这里插入图片描述

- 共享库.so 文件的生成与使用
1、生成目标文件(xxx.o() 此处生成.o 文件必须添加"-fpic"(小模式,代码少),否则在生成.so文件时会出错)---> gcc -c -fpic A1.c A2.c
2、生成共享库.so 文件---> gcc -shared *.o -o libsofile.so

在这里插入图片描述
3、使用.so 库文件,创建可执行程序
---> gcc -o test test.c libsofile.so ---> ./test
在这里插入图片描述
发现出现错误:./test: error while loading shared libraries: libsofile.so: cannot open shared object file: No such file or directory

运行 ldd test,查看链接情况
ldd test
linux-vdso.so.1 => (0x00007fff0fd95000)
libsofile.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f937b5de000)
/lib64/ld-linux-x86-64.so.2 (0x0000563f7028c000)

发现确实是找不到对应的.so 文件

这是由于 linux 自身系统设定的相应的设置的原因,即其只在/lib and /usr/lib 下搜索对应的.so 文件,故需将对应 so 文件拷贝到对应路径。

注意:动态库和静态库同时存在时,优先使用动态库,当然,如果直接#gcc main.c libmyhello.a -o hello 的话,就是指定为静态库了

--->sudo cp libsofile.so /usr/lib

再次执行./test,即可成功运行

---> ./test

在这里插入图片描述
同时可直接使用 gcc -o test test.c -L. -lname,来使用相应库文件

其中:

-L.:表示在当前目录下,可自行定义路径 path,即使用-Lpath 即可。
-lname:name:即对应库文件的名字(除开 lib),即若使用 libafile.a,则 name 为 afile;
若要使用 libsofile.so,则 name 为 sofile)。

2.用 gcc进行静态库文件的链接

1.用vim创建main.c、sub1.c、sub2.c、main.h

在这里插入图片描述
在这里插入图片描述
2.生成sub1.o和sub2.c文件

在这里插入图片描述
3.生成静态库文件liba.a

在这里插入图片描述
4.编译运行得到结果

12
34
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值