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' 。

目录
相关文章
|
2月前
|
存储 Linux 开发工具
Linux环境下使用Buildroot配置软件包
使用Buildroot可以大大简化嵌入式Linux系统的开发和维护工作,但它需要对Linux系统和交叉编译有深入的理解。通过上述步骤,可以有效地配置和定制软件包,为特定的嵌入式应用构建高效、稳定的系统。
233 11
|
4月前
|
存储 监控 Linux
Linux环境锁定关键文件防止误删操作流程。
总结以上内容,在Linux环境下锁定重要文档避免误删涉及到多种技术手段与策略组合运作, 包括但不限于利用chatter指挥官固化文档状态至只读模式、运作ACL精准调整访问权利列表、编排自动化流程简
155 20
|
4月前
|
Linux
Linux环境下的UDEV机制及其与守护进程的关联
实际使用时管理员需要熟悉编写合适udev rules去满足特殊需求;同时也需要注意避免编写过度复杂导致无法预料结果rules.UDEVD虽然稳健但错误配置可能导致无法预料问题因此需谨慎处理相关配置工作.
159 16
|
4月前
|
存储 Linux
Linux环境下删除大文件后磁盘空间未释放问题诊断流程。
以上诊断流程涉及Linux底层机制与高级管理技能结合之处,并需要管理员根据实际环境灵活调整诊断策略与解决方案。
280 8
|
4月前
|
Ubuntu 安全 Linux
Ubuntu 24.10 发行版登场:Linux 6.11 内核、GNOME 47 桌面环境
Ubuntu 24.10 还带来了 GNOME 47,增强了性能和稳定性,并引入了新功能。此版本的 Ubuntu 还默认在采用 Nvidia 显卡的硬件上切换到 Wayland,并在支持的硬件上默认使用开源的 Nvidia 560 内核模块。 另外需要注意的是,Ubuntu 24.10 是稳定版本,但作为非 LTS 版本,仅支持 9 个月。
|
4月前
|
安全 Linux 网络安全
Linux系统初步设置本地Git环境和生成SSH密钥的步骤。
现在您的Linux系统已经配置好了Git环境,并创建并添加了SSH密钥,可以安全地与远端仓库进行交互,无论是克隆、推送还是拉取操作。此过程确保了数据传输的安全并使版本控制流程更为顺畅。使用Git时应考虑定期更新并管理您的凭据,以确保安全性。
505 0
|
Linux 编译器 vr&ar
|
Linux vr&ar C语言
|
Linux 编译器 vr&ar
【Linux】静态库和动态库
本文详细介绍了Linux系统中静态库和动态库的概念、区别、制作与使用方法,包括它们在链接时的区别、加载机制以及优缺点。
255 0