Linux环境编译静态库

简介: Linux环境编译静态库

还是以之前的 universe 项目为例,之前是 zeus.c (宙斯)可以操作 3 颗星球。现在来了一个新的大佬 poseidon.c (波塞冬),他也可以操作 3 颗星球。

Linux环境编译单个C程序文件

这种封装的方法 就是 静态库 跟 动态库,静态库 是可以链接进去 程序自身,动态库是共享库,可以由多个程序共享节省空间,动态库只有用到的时候才会加载。

本文只讲静态库封装,动态库下一篇文章再讲。

TODO:这里应该看完《Linker and Loader》再补充一下 具体的加载区别之类的。



封装静态库的命令如下:

ar -rcs libstar.a moon.o sun.o earth.o

上面的命令把 3 个 .o 封装打包进去 libstar.a 里面了,star 是星球的意思,这是星球静态库。

ar 实际上是一个打包封装命令,打包成静态库,静态库也叫归档文件,实际上是对已经编译好的字节码进行封装,封装过程不涉及到链接,以前那些 call 占位符还是 00 00 。

ar 不止可以打包 elf 的 .o 文件,还可以打包文本文件,如下命令:

ar -r text-all.arch a.txt b.txt

ar 甚至支持 Windows 的PE 格式,使用 ar --help 可以查看 ar 支持的所有打包格式。

ar: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex

回到 文本主题,静态库 libstar.a 是什么格式的呢?ELF格式吗?实际上,他不是一个纯正的 ELF 格式,因为用 xelfviewer 无法解析,但是 readelf 命令可以查看内容。这是因为 ar 命令把多个ELF文件合并在一起了。

我们用 objdump 查看 libstar.a 里面的字节码对应的汇编指令,如下:

objdump -d libstar.a > star-dump.txt

sun.o 里面是 调了 moon.o 里面的 moon_rotate() 函数的,即便我们把 moon.o 跟 sun.o 一起打包成静态库,这个地址还是没有被修正,所以编译成静态库并不会进行链接操作


现在 libstar.a 静态库已经生成了,如何引用这个静态库呢?之前说过,创建静态库 是为了给 zeus.c (宙斯) 跟 poseidon.c (波塞冬)使用。

先在 Document 里面创建一个 poseidon 文件夹,再创建一个 poseidon.c 文件,poseidon.c 内容如下:

#include "sun.h"
#include "moon.h"
#include "earth.h"
#include <stdio.h>
int main()
{
    printf("poseidon do something \r\n");
    sun_rotate();
    moon_rotate();
    earth_rotate();
    return 0;
}

把 相关的头文件 跟 libstar.a 复制过去,目录结构如下:

编译 poseidon.c 的命令如下:

gcc -c -o poseidon.o poseidon.c

第一种引用 libstar 静态库的 方式是 直接写 静态库文件的全称,会在当前目录找 libstar.a, 命令如下:

gcc -o poseidon poseidon.o libstar.a

第二种方式是是 -static 指定后面的库是静态库,然后使用 -l 参数 指定库名称,命令如下:

gcc -v -o poseidon poseidon.o -static -lstar

上面的命令,如果不指定 -static ,链接的时候会默认去搜索动态库,也就是搜索 libstar.so 文件。

使用 -l 链接的时候,需要去除库文件名的 lib 前缀 跟 .a 后缀,去掉就行,链接器会默认加上这些前缀后缀找到那个库文件的。运行结果如下:

上图使用了 -v 选项,所以打印了更详细的内容,包括 gcc 会在哪些目录搜索 库文件。

从上图可以看出,gcc 会在 上面 /usr/lib 等等 那些目录里面查找 libstar.a 文件。上图的命令是会报错的,因为那些目录都没有 libstar.a 。

我现在把 libstar.a 移动到 /usr/lib 目录,链接就能通过了,请看下图:

编译通过之后,即使把 libstar.a 文件删除,poseidon 程序运行也不会出问题,因为字节码已经拷贝过去了。

还有一种链接静态库的方式,直接把路径写全。

gcc -o poseidon poseidon.o /usr/lib/libstar.a

poseidon 项目已经编译完毕了,现在再在 Document 建立一个 zeus 文件夹,把文件复制过去,如下:

用以下命令开始编译。

gcc -c -o zeus.o zeus.c
gcc -o zeus zeus.o /usr/lib/libstar.a

这样,两位大佬 zeus 跟 poseidon 都能使用这个 libstar.a 静态库了。

总结:Linux 的静态库封装,实际上就是打包,把多个 .o 文件打包在一个 .ar 文件里面。这也是为什么静态库会被叫做归档文件的原因


扩展知识:

实际上,编译 跟 链接,是可以合成一步的,上面 zeus 的 两条命令,可以合成一条。如下:

gcc -o zeus zeus.c /usr/lib/libstar.a

这样不会生成 zeus.o 文件,但是实际上在内部,还是有一个编译步骤的。我不建议初学者这样用,因为这个命令很容易混淆 编译 跟 链接这两个过程。


上面已经讲解了,找不到静态库,gcc 会报如下错误。

但是编译大型 C/C++ 项目的时候,还会遇到 undefined reference to `xxx',如下:

这个错误的意思是,函数被引用了,但是具体的实现没有找到。为什么会报这个错误呢?是因为我编译的时候 故意不写上 -static -lstar

在实际项目中,通常是写漏了库引用,或者名称没写对了,例如写成 -lstarx ,多了个x,但是 libstarx.a 可能是存在的,所以就没有报找不到库,而是 undefined reference to `xxx' 。

目录
相关文章
|
1月前
|
Linux 编译器 开发工具
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
【Linux快速入门(三)】Linux与ROS学习之编译基础(Cmake编译)
|
1天前
|
Ubuntu Linux Shell
(已解决)Linux环境—bash: wget: command not found; Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
(已成功解决)Linux环境报错—bash: wget: command not found;常见Linux发行版本,Linux中yum、rpm、apt-get、wget的区别;Docker pull报错Error response from daemon: Get https://registry-1.docker.io/v2/: net/http: request canceled
|
9天前
|
存储 编译器 Linux
动态链接的魔法:Linux下动态链接库机制探讨
本文将深入探讨Linux系统中的动态链接库机制,这其中包括但不限于全局符号介入、延迟绑定以及地址无关代码等内容。
111 16
|
28天前
|
缓存 Ubuntu Linux
Linux环境下测试服务器的DDR5内存性能
通过使用 `memtester`和 `sysbench`等工具,可以有效地测试Linux环境下服务器的DDR5内存性能。这些工具不仅可以评估内存的读写速度,还可以检测内存中的潜在问题,帮助确保系统的稳定性和性能。通过合理配置和使用这些工具,系统管理员可以深入了解服务器内存的性能状况,为系统优化提供数据支持。
34 4
|
1月前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
95 3
|
1月前
|
监控 关系型数据库 MySQL
Linux环境下MySQL数据库自动定时备份策略
在Linux环境下,MySQL数据库的自动定时备份是确保数据安全和可靠性的重要措施。通过设置定时任务,我们可以每天自动执行数据库备份,从而减少人为错误和提高数据恢复的效率。本文将详细介绍如何在Linux下实现MySQL数据库的自动定时备份。
45 3
|
1月前
|
Linux UED iOS开发
|
1月前
|
Linux
Linux - 如何编译源码安装软件
源码编译安装通常包括三个步骤:1) `./configure` 检测平台特征和依赖项,生成 Makefile;2) `make` 编译源码,生成可执行文件;3) `make install` 将可执行文件安装到指定目录并配置环境变量。
49 0
|
5月前
|
Linux 编译器 vr&ar
【Linux】静态库和动态库
本文详细介绍了Linux系统中静态库和动态库的概念、区别、制作与使用方法,包括它们在链接时的区别、加载机制以及优缺点。
69 0
|
7月前
|
Linux vr&ar C语言
下一篇
DataWorks