专栏首页编程珠玑如何制作属于自己的静态库?

如何制作属于自己的静态库?

前言

在《一文带你了解静态库和动态库》一文中介绍了静态库的特点以及与动态库的区别。那么你有没有想过如何把自己写好的函数接口制作成静态库给别人用呢?本文教你如何制作属于自己的静态库。

编译成可重定位文件

在《一文带你了解静态库和动态库》简单介绍了可重定位文件。其中也有一位非常细心的读者发现,在ubuntu18.04的系统,使用gcc7.4编译出来的可执行文件的type是DYN,这是编译器生成了一种位置无关的可执行文件(PIE),它类似于动态库,其地址在加载时确定,从而更加安全。本文不再展开介绍。

本文实例代码test1.c代码如下:

//来源:公众号【编程珠玑】 网站:https://www.yanbinghu.com
#include"test1.h"
void test1()
{
    printf("I am test1\n");
}

编译成可重定位文件,即生成.o文件:

$ gcc -c test1.c
$ readelf -h test1.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
(省略部分内容)

关于编译的几个阶段,可以参考《代码是如何变成可执行文件的》。

制作成静态库

为了制作成静态库,我们需要使用ar命令。

$ ar -rcs libtest1.a test1.o   #库名一般以.a为扩展名,以lib开头
$ ar -t libtest1.a  #查看内容
test1.o

通常来说,静态库以.a作为后缀,且以lib开头。至此就将我们提供的test1函数做成了静态库,但是为了方便其他人使用,我们再提供一个头文件test1.h,代码如下:

#include<stdio.h>
void test1();

这个时候就可以将我们做好的静态库给其他人使用啦。

使用静态库

我们写一个main.c来调用test1():

//来源:公众号【编程珠玑】 网站:https://www.yanbinghu.com
#include"test1.h"
int main(void)
{
    test1();
    return 0;
}

编译运行:

$ gcc -o main main.c -L ./  -ltest1
$ ./main
I am test1

其中-L用于指定链接库的路径,由于我们要链接的库名为libtest1.a,在链接的时候,去掉开头的lib和后缀.a,前面再加l,就变成了-ltest1,其他库也是类似。例如,你如果看到程序链接使用-lm,说明它使用了名为libm.a的库。

再看静态库使用

如果这时候还有一个库libtest0.a,库中调用了test1.c的函数,而main函数调用了libtest0.a中的函数呢?即,假设有test0.c中调用test1(),且两者位于不同的库中,test0.c代码如下:

#include"test0.h"
void test0()
{
    printf("I am test0,I will call test1\n");
    test1();
    printf("test0 call test1 end\n");
}

头文件test0.h:

#include"test1.h"
void test0();

还是以类似的方法制作静态库libtest0.a:

$ gcc -c test0.c
$ ar -rcs libtest0.a test0.o

改写main.c:

//来源:公众号【编程珠玑】 网站:https://www.yanbinghu.com
#include"test0.h"
int main(void)
{
    test0();
    return 0;
}

重新编译链接:

$ gcc -o main main.c -L ./ -ltest1 -ltest0
.//libtest0.a(test0.o): In function `test0':
test0.c:(.text+0x14): undefined reference to `test1'
collect2: error: ld returned 1 exit status

这里我们发现编译出错了,提示test1未定义,很显然是由于test0中调用了test1。至于解决办法也很简单,调整链接库的顺序即可,更加详细的原因可以参考《一个奇怪的链接问题》和《静态库和动态库的区别》。

我们调整之后再次编译链接并运行:

$ gcc -o main main.c -L ./ -ltest0 -ltest1
$ ./main
I am test0,I will call test1
I am test1                
test0 call test1 end 

可以看到,在调整两个库的顺序之后,编译链接正常,并且程序也按照我们预期的结果运行。

因此,我们在链接时,应该尽量把被需要的库放在后面

本文作者:守望 来源:https://www.yanbinghu.com

ar命令详解

从前面的内容我们可以观察到,我们是通过ar命令来制作静态库(归档文件)的,它可以将多个按照一定的规则组织在一起。我们再来了解一下ar命令,ar命令常见参数如下:

  • r 向归档文件中添加内容,如原先已存在,则替换
  • c 创建归档文件
  • s 添加索引信息
  • d 从归档文件中删除
  • t 查看归档文件的内容
  • x 解压归档文件
  • a/b 向归档文件中添加内容
  • v 显示详细信息

rcs参数我们已经在前面用到了。-a(after)或者-b(before)参数可以向归档文件中添加文件,例如:

$ ar -ra test0.o libtest0.a test1.o

这里表示在libtest0.a中的test0.o之后,添加test1.o。 添加后内容如下:

$ ar -t libtest0.a
test0.o
test1.o

当然了,归档文件是可以解开的,比如:

$ ar -xv libtest0.a 
x - test0.o
x - test1.o

你要删除其中的某个文件,也是没人阻止的:

$ ar -d test1.o libtest0.a 
d - test1.o

-d参数后面跟着要移除的文件。

需要特别注意的是,这里ar归档的作用并不仅仅针对可重定位目标文件,而是几乎针对任何类型的普通文件

总结

制作静态库不过是利用ar命令把一些文件可重定位文件打包在一起,其他程序在使用时需要通过链接动态将自己需要的内容“拷贝”到最终的可执行文件中。现在知道如何制作属于自己的静态库了吗?赶紧自己试试吧!

本文分享自微信公众号 - 编程珠玑(shouwangxiansheng),作者:守望先生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 网络编程-再看TCP的四次挥手

    在《网络编程-从TCP连接的建立说起》中介绍了TCP的三次握手以及一些常见问题,那么四次挥手又有哪些需要特别关注的问题?四次挥手你真的懂了吗?

    编程珠玑
  • 拥抱智能指针,告别内存泄露

    我们都知道,当申请的内存在不用时忘记释放,导致内存泄漏。长期来看,内存泄漏的危害是巨大的,它导致可用内存越来越少,甚至拖慢系统,最终进程可能被OOM(out o...

    编程珠玑
  • Linux常用命令--文本查看篇

    Linux常用命令中,除了cat还有很多其他用于文本查看的命令。本文将简单介绍一下这些文本查看的命令。

    编程珠玑
  • 新人自学前端到什么程度才能找工作?

    这个问题打我记事起到现在,问过我的人,没有1000也有800了。足以见得这个问题是多么的不得人心。

    web前端教室
  • 我在谷歌大脑见习机器学习的一年:Node.js创始人的尝试笔记

    大数据文摘
  • 【选择题】Java基础测试二(15道)

    【选择题】Java基础测试二(15道) 11.对于构造方法,下列叙述正确的是:(AC) A. 构造方法的方法名必须与类名相同; B. 构造方法必须用void...

    奋斗蒙
  • 给 AI 换个“大动力小心脏”之通用 CNN 加速设计

    基于 FPGA 的通用 CNN 加速设计,可以大大缩短 FPGA 开发周期,支持业务深度学习算法快速迭代;提供与GPU相媲美的计算性能,但拥有相较于 GPU 数...

    腾讯架构师
  • Nginx+PHP php文件404错误的一个可能原因

    网站本来是nginx + php-fpm socket的方式跑的,nginx是自己编译安装了。昨天尝试把网站加上https,就根据https://certbot...

    俗可耐
  • 【爬虫】爬取简书某ID所有文章并保存为pdf

    现如今,我们处于一个信息碎片化的信息时代,遇到好的文章都有随手收藏的习惯。但过一段时间,当你想要重新查看这篇文章的时候,发现文章已经被移除或莫名其妙地消失了。

    昱良
  • SAP最佳业务实践:MM–交货与库存调拨(134)-3采购申请

    3、流程概览表 使用MRP 运行创建库存调拨 流程步骤外部流程参考业务条件业务角色事务代码预期结果运行单一项目的 MRPMRP 计划日常 MRP 运行生产计划员...

    SAP最佳业务实践

扫码关注云+社区

领取腾讯云代金券