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

目录
相关文章
|
13天前
|
Web App开发 搜索推荐 Unix
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
【10月更文挑战第21天】Linux系统之MobaXterm远程连接centos的GNOME桌面环境
121 4
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
|
10天前
|
Linux UED iOS开发
|
15天前
|
Ubuntu 应用服务中间件 Linux
Linux下搭建Nginx环境的搭建
Linux下搭建Nginx环境的搭建
|
19天前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
22 3
|
21天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
67 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
25天前
|
Linux 编译器 C语言
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
|
8天前
|
Linux
Linux - 如何编译源码安装软件
源码编译安装通常包括三个步骤:1) `./configure` 检测平台特征和依赖项,生成 Makefile;2) `make` 编译源码,生成可执行文件;3) `make install` 将可执行文件安装到指定目录并配置环境变量。
23 0
|
25天前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
|
16天前
|
Linux
Linux系统之expr命令的基本使用
【10月更文挑战第18天】Linux系统之expr命令的基本使用
51 4