Redian新闻
>
Linux 上静态链接库工作原理 | Linux 中国

Linux 上静态链接库工作原理 | Linux 中国

科技
 
导读:学习如何用静态链接库将多个 C 目标文件结合到一个单个的可执行文件之中。                   
本文字数:4023,阅读时长大约:5分钟

学习如何用静态链接库将多个 C 目标文件结合到一个单个的可执行文件之中。

使用 C 编写的应用程序时,通常有多个源码文件,但最终你需要编译成单个的可执行文件。

你可以通过两种方式来完成这项工作:通过创建一个 静态(static) 库 或 一个 动态(dynamic) 库(也被称为 共享(shared) 库)。从创建和链接的方式来看,它们是两种不同类型的库。选择使用哪种方式取决于你的的具体场景。

在 上一篇文章🔗 linux.cn 中,我演示了如何创建一个动态链接的可执行文件,这是一种更通用的方法。在这篇文章中,我将说明如何创建一个静态链接的可执行文件。

使用静态库链接器

链接器(linker)是一个命令,它将一个程序的多个部分结合在一起,并为它们重新组织内存分配。

链接器的功能包括:

◈ 整合一个程序的所有的部分
◈ 计算出一个新的内存组织结构,以便所有的部分组合在一起
◈ 恢复内存地址,以便程序可以在新的内存组织结构下运行
◈ 解析符号引用

链接器通过这些功能,创建了一个名称为可执行文件的一个可运行程序。

静态库是通过复制一个程序中的所有依赖库模块到最终的可执行镜像来创建的。链接器将链接静态库作为编译过程的最后一步。可执行文件是通过解析外部引用、将库例程与程序代码结合在一起来创建的。

创建目标文件

这里是一个静态库的示例以及其链接过程。首先,创建带有这些函数识别标志的头文件 mymath.h :

  1. int add(int a, int b);
  2. int sub(int a, int b);
  3. int mult(int a, int b);
  4. int divi(int a, int b);

使用这些函数定义来创建 add.c 、sub.c 、mult.c 和 divi.c 文件。我将把所有的代码都放置到一个代码块中,请将其分为四个文件,如注释所示:

  1. // add.c
  2. int add(int a, int b){
  3. return (a+b);
  4. }
  5. //sub.c
  6. int sub(int a, int b){
  7. return (a-b);
  8. }
  9. //mult.c
  10. int mult(int a, int b){
  11. return (a*b);
  12. }
  13. //divi.c
  14. int divi(int a, int b){
  15. return (a/b);
  16. }

现在,使用 GCC 来生成目标文件 add.o 、sub.o 、mult.o 和 divi.o

(LCTT 校注:关于“目标文件(object file)”,有时候也被称作“对象文件”,对此,存在一些译法混乱情形,称之为“目标文件”的译法比较流行,本文采用此译法。)

  1. $ gcc -c add.c sub.c mult.c divi.c

-c 选项跳过链接步骤,而只创建目标文件。

创建一个名称为 libmymath.a 的静态库,接下来,移除目标文件,因为它们不再被需要。(注意,使用一个 trash 命令比使用一个 rm 命令更安全。)

  1. $ ar rs libmymath.a add.o sub.o mult.o divi.o
  2. $ trash *.o
  3. $ ls
  4. add.c  divi.c  libmymath.a  mult.c  mymath.h  sub.c

现在,你已经创建了一个名称为 libmymath 的简单数学示例库,你可以在 C 代码中使用它。当然,也有非常复杂的 C 库,这就是他们这些开发者来生成最终产品的工艺流程,你和我可以安装这些库并在 C 代码中使用。

接下来,在一些自定义代码中使用你的数学库,然后链接它。

创建一个静态链接的应用程序

假设你已经为数学运算编写了一个命令。创建一个名称为 mathDemo.c 的文件,并将这些代码复制粘贴至其中:

  1. #include <mymath.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6.   int x, y;
  7.   printf("Enter two numbers\n");
  8.   scanf("%d%d",&x,&y);
  9.  
  10.   printf("\n%d + %d = %d", x, y, add(x, y));
  11.   printf("\n%d - %d = %d", x, y, sub(x, y));
  12.   printf("\n%d * %d = %d", x, y, mult(x, y));
  13.   if(y==0){
  14.     printf("\nDenominator is zero so can't perform division\n");
  15.       exit(0);
  16.   }else{
  17.       printf("\n%d / %d = %d\n", x, y, divi(x, y));
  18.       return 0;
  19.   }
  20. }

注意:第一行是一个 include 语句,通过名称来引用你自己的 libmymath 库。

针对 mathDemo.c 创建一个名称为 mathDemo.o 的对象文件:

  1. $ gcc -I . -c mathDemo.c

-I 选项告诉 GCC 搜索在其后列出的头文件。在这个实例中,你通过单个点(.)来指定当前目录。

链接 mathDemo.o 和 libmymath.a 来生成最终的可执行文件。这里有两种方法来向 GCC 告知这一点。

你可以指向文件:

  1. $ gcc -static -o mathDemo mathDemo.o libmymath.a

或者,你可以具体指定库的路径及名称:

  1. $ gcc -static -o mathDemo -L . mathDemo.o -lmymath

在后面的那个示例中,-lmymath 选项告诉链接器来链接对象文件 mathDemo.o 和对象文件 libmymath.a 来生成最终的可执行文件。-L 选项指示链接器在下面的参数中查找库(类似于你使用 -I 所做的工作)。

分析结果

使用 file 命令来验证它是静态链接的:

  1. $ file mathDemo
  2. mathDemo: ELF 64-bit LSB executable, x86-64...
  3. statically linked, with debug_info, not stripped

使用 ldd 命令,你将会看到该可执行文件不是动态链接的:

  1. $ ldd ./mathDemo
  2.         not a dynamic executable

你也可以查看 mathDemo 可执行文件的大小:

  1. $ du -h ./mathDemo
  2. 932K    ./mathDemo

在我 前一篇文章🔗 linux.cn 的示例中,动态链接的可执行文件只占有 24K 大小。

运行该命令来看看它的工作内容:

  1. $ ./mathDemo
  2. Enter two numbers
  3. 10
  4. 5
  5. 10 + 5 = 15
  6. 10 - 5 = 5
  7. 10 * 5 = 50
  8. 10 / 5 = 2

看起来令人满意!

何时使用静态链接

动态链接可执行文件通常优于静态链接可执行文件,因为动态链接会保持应用程序的组件模块化。假如一个库接收到一次关键安全更新,那么它可以很容易地修补,因为它存在于应用程序的外部。

当你使用静态链接时,库的代码会“隐藏”在你创建的可执行文件之中,意味着在库每次更新时(相信我,你会有更好的东西),仅有的一种修补方法是重新编译和发布一个新的可执行文件。

不过,如果一个库的代码,要么存在于它正在使用的具有相同代码的可执行文件中,要么存在于不会接收到任何更新的专用嵌入式设备中,那么静态连接将是一种可接受的选项。


via: https://opensource.com/article/22/6/static-linking-linux

作者:Jayashree Huttanagoudar 选题:lkxed 译者:robsean 校对:turbokernel

本文由 LCTT 原创编译,Linux中国 荣誉推出


LCTT 译者 :郑
🌟🌟🌟🌟🌟
翻译: 105.0 篇
|
贡献: 1315 天
2018-12-03
2022-07-09
https://linux.cn/lctt/robsean
欢迎遵照 CC-BY-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
Linux 中国开通播客频道:“开源朗读者”和“硬核观察” | Linux 中国你的 Linux 启动时有几只小企鹅? | Linux 中国小米生态链企业趣睡科技通过注册:年营收4.7亿 顺为京东是股东无意中看到这个,真不错!窦文涛与崔健谈话 -4月15号演唱会前因为工作原因要换城市生活,悉尼墨尔本成本差距大吗?编译代码时动态地链接库 | Linux 中国Linux 内核 5.18 版本正式发布,新增显卡驱动以及硬件支持 | Linux 中国7人因闯入政府中心车库工地而被捕;印第安纳州购物中心枪击事件造成 3 人死亡HydraPaper:一个支持多显示器的 Linux 壁纸管理器 | Linux 中国上一个说“丼”不读jǐng的人,已经被我骂哭了Plex 桌面播放器现已支持 Linux | Linux 中国我3岁时被人贩子从冰岛拐卖到了河南如何在 Linux 上动态链接模块库 | Linux 中国Linux Lite 6.0 发布:弃用 Firefox,默认浏览器使用 Chrome | Linux 中国Linux 内核 5.19 RC1 发布,完成了 ARM 通用内核的工作 | Linux 中国Linux 桌面刻薄版点评 | Linux 中国Fedora Linux 37 的内核 5.18 测试周到了,一起来做贡献吧! | Linux 中国如何在 Fedora Linux 中安装多媒体编码器 | Linux 中国最惨小米生态链上市公司?营收净利暴降,全屋智能“摊大饼”理想ONE高速撞上静止车辆,事关辅助驾驶功能,理想官方回应了......微软还有另一个 Linux 发行版,而且是基于 Debian 的 | Linux 中国System76 与惠普合作为开发者提供功能强大的 Linux 笔记本电脑 | Linux 中国RTMP的工作原理CentOS 的继承者 AlmaLinux 9 发布 | Linux 中国如何在 Linux 桌面中启用 “激活 Linux” 水印通知 | Linux 中国使用 Linux 上的开源财务工具 Skrooge 管理你的预算 | Linux 中国Collision:用于验证 ISO 和其他文件的 Linux 应用 | Linux 中国开源朗读者:我是如何帮助妈妈从 Windows 切换至 Linux 的 | Linux 中国坏人做的坏事坏到让胡锡进都觉得坏了Linux Mint 接管 Timeshift 备份工具的开发,并作为一款 XApp 来维护 | Linux 中国在 Linux 上使用 sudo 命令的 5 个理由 | Linux 中国Fudgie?令人惊叹的 Budgie 桌面即将登陆 Fedora Linux | Linux 中国值得尝试的六款 Linux 文字处理程序 | Linux 中国等它气消了我们就能吃饭了我们已经回不去了,我说的不仅仅是回国
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。