Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 Linux 版本下不兼容的问题; 2)在 Linux 静态库的制作过程中发现有别于 Windows 下静态库的制作方法;3)在 Linux 应用程序链接第三方库或者其他静态库的时候发现链接顺序的烦人问题。本文就这三个问题针对 Linux 下标准库链接和如何巧妙构建 achrive(*.a) 展开相关介绍。

两个要知道的基本知识

Linux 应用程序因为 Linux 版本的众多与各自独立性,在工程制作与使用中必须熟练掌握如下两点才能有效地工作和理想地运行。

Linux 下标准库链接的三种方式(全静态 , 半静态 (libgcc,libstdc++), 全动态)及其各自利弊。

Linux 下如何巧妙构建 achrive(*.a),并且如何设置链接选项来解决 gcc 比较特别的链接库的顺序问题。

三种标准库链接方式选项及对比

为了演示三种不同的标准库链接方式对最终应用程序产生的区别, 这里用了一个经典的示例应用程序 HelloWorld 做演示,见 清单 1 HelloWorld。

清单 1. HelloWorld

#include <stdio.h>
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char* argv[])
{
printf("HelloWorld!(Printed by printf)n");
cout<<"HelloWorld!(Printed by cout)"<<endl;
return 0;
}

三种标准库链接方式的选项及区别见 表 1

上述三种标准库链接方式中,比较特殊的是 半静态链接方式,主要在于其还需要在链接前增加额外的一个步骤:

ln -s g++ -print-file-name=libstdc++.a,作用是将 libstdc++.a(libstdc++ 的静态库)符号链接到本地工程链接目录。

-print-file-name 在 gcc 中的解释如下:

-print-file-name= Display the full path to library

为了区分三种不同的标准库链接方式对最终生成的可执行文件的影响,本文从两个不同的维度进行分析比较:

维度一:最终生成的可执行文件对标准库的依赖方式(使用 ldd 命令进行分析)

ldd 简介:该命令用于打印出某个应用程序或者动态库所依赖的动态库

涉及语法:ldd [OPTION]… FILE…

其他详细说明请参阅 man 说明。

三种标准库链接方式最终产生的应用程序的可执行文件对于标准库的依赖方式具体差异见 图 1、图 2、图 3所示:

图 1. 全静态标准库链接方式

图 2. 全动态标准库链接方式

图 3. 半静态(libgcc,libstdc++) 标准库链接方式

通过上述三图,可以清楚的看到,当用 全静态标准库的链接方式时,所生成的可执行文件最终不依赖任何的动态标准库,

全动态标准库的链接方式会导致最终应用程序可执行文件依赖于所有用到的标准动态库。

区别于上述两种方式的 半静态链接方式则有针对性的将 libgcc 和 libstdc++ 两个标准库非动态链接。

(对比 图 2与 图 3,可见在 图 3中这两个标准库的动态依赖不见了)

从实际应用当中发现,最理想的标准库链接方式就是半静态链接,通常会选择将 libgcc 与 libstdc++ 这两个标准库静态链接,

从而避免应用程序在不同 Linux 版本间标准库依赖不兼容的问题发生。

维度二 : 最终生成的可执行文件大小(使用 size 命令进行分析)

size 简介:该命令用于显示出可执行文件的大小

涉及语法:size objfile…

其他详细说明请参阅 man 说明。

三种标准库链接方式最终产生的应用程序的可执行文件的大小具体差异见 图 4、图 5、图 6所示:

图 4. 全静态标准库链接方式

图 5. 全动态标准库链接方式

图 6. 半静态(libgcc,libstdc++) 标准库链接方式

通过上述三图可以看出,最终可执行文件的大小随最终所依赖的标准动态库的数量增加而减小。

从实际应用当中发现,最理想的是 半静态链接方式,因为该方式能够在避免应用程序于

不同 Linux 版本间标准库依赖不兼容的问题发生的同时,使最终生成的可执行文件大小最小化。

示例链接选项中所涉及命令(引用 GCC 原文):

-llibrary

-l library:指定所需要的额外库

-Ldir:指定库搜索路径

-static:静态链接所有库

-static-libgcc:静态链接 gcc 库

-static-libstdc++:静态链接 c++ 库

关于上述命令的详细说明,请参阅 GCC 技术手册

Linux 下静态库(archive)的制作方式:

涉及命令:ar

ar 简介:处理创建、修改、提取静态库的操作

涉及选项:

t – 显示静态库的内容

r[ab][f][u] – 更新或增加新文件到静态库中

[s] – 创建文档索引

ar -M [

其他详细说明请参阅 man 说明。

示例情景:

假设现有如 图 7所示两个库文件

图 7. 示例静态库文件

从 图 7中可以得知,CdtLog.a 只包含 CdtLog.o 一个对象文件 , 而 xml.a 包含 TXmlParser.o 和 xmlparser.o 两个对象文件

现将 CdtLog.o 提取出来,然后通过 图 8方式创建一个新的静态库 demo.a,可以看出,demo.a 包含的是 CdtLog.o 以及 xml.a,

而不是我们所预期的 CdtLog.o,TXmlParser.o 和 xmlparser.o。这正是区别于 Windows 下静态库的制作。

图 8. 示例静态库制作方式 1

这样的 demo.a 当被链接入某个工程时,所有在 TXmlParser.o 和 xmlparser.o 定义的符号都不会被发现,从而会导致链接错误,

提示无法找到对应的符号。显然,通过图 8 方式创建 Linux 静态库是不正确的。

正确的方式有两种:

将所有静态库中包含的对象文件提取出来然后重新打包成新的静态库文件。

用一种更加灵活的方式创建新的静态库文件:ar 脚本

显然,方式 1 是比较麻烦的,因为涉及到太多的文件处理,可能还要通过不断创建临时目录用于保存中间文件。

推荐使用如 清单 2 createlib.sh所示的 ar 脚本方式进行创建:

清单 2 createlib.sh

rm demo.a
rm ar.mac
echo CREATE demo.a > ar.mac
echo SAVE >> ar.mac
echo END >> ar.mac
ar -M < ar.mac
ar -q demo.a CdtLog.o
echo OPEN demo.a > ar.mac
echo ADDLIB xml.a >> ar.mac
echo SAVE >> ar.mac
echo END >> ar.mac
ar -M < ar.mac
rm ar.mac

如果想在 Linux makefile 中使用 ar 脚本方式进行静态库的创建,可以编写如 清单 3 BUILD_LIBRARY所示的代码:

清单 3 BUILD_LIBRARY

define BUILD_LIBRARY
$(if $(wildcard $@),@$(RM) $@)
$(if $(wildcard ar.mac),@$(RM) ar.mac)
$(if $(filter %.a, $^),
@ echo CREATE $@ > ar.mac
@ echo SAVE >> ar.mac
@ echo echo END >> ar.mac
@$(AR) -M < ar.mac
)
$(if $(filter %.o,$^),@$(AR) -q $@ $(filter %.o, $^))
$(if $(filter %.a, $^),
@ echo OPEN $@ > ar.mac
$(foreach LIB, $(filter %.a, $^),
@ echo ADDLIB $(LIB) >> ar.mac
)
@ echo SAVE >> ar.mac
@ echo END >> ar.mac
@$(AR) -M < ar.mac
@$(RM) ar.mac
)
endef
$(TargetDir)/$(TargetFileName):$(OBJS)
$(BUILD_LIBRARY)

通过 图 9,我们可以看到,用这种方式产生的 demo.a 才是我们想要的结果。

图 9. 巧妙创建的静态库文件结果

Linux 静态库链接顺序问题及解决方法:

正如 GCC 手册中提到的那样:

It makes a difference where in the command you write this option; the linker
searches and processes libraries and object files in the order they are specified.
Thus, ‘ foo.o -lz bar.o ’ searches library ‘ z ’ after file ‘ foo.o ’ but before
‘ bar.o ’ . If ‘ bar.o ’ refers to functions in ‘ z ’ , those functions may not be loaded.

为了解决这种库链接顺序问题,我们需要增加一些链接选项 :

$(CXX) $(LINKFLAGS) $(OBJS) -Xlinker “-(” $(LIBS) -Xlinker “-)” -o $@

通过将所有需要被链接的静态库放入 -Xlinker “-(” 与 -Xlinker “-)” 之间,可以是 g++ 链接过程中, 自动循环链接所有静态库,从而解决了原本的链接顺序问题。

涉及链接选项:-Xlinker

-Xlinker option

Pass option as an option to the linker. You can use this to supply system-specific

linker options which GCC does not know how to recognize.

小结

本文介绍了 Linux 下三种标准库链接的方式及各自利弊,同时还介绍了 Linux 下静态库的制作及使用方法,希望能够给大多数需要部署 Linux 应用程序和编写 Linux Makefile 的工程师提供有用的帮助。

bazel 链接第三方动态库_Linux 动态库与静态库制作及使用详解相关推荐

  1. libcurl linux 静态链接库_Linux ubuntu OpenSSL + curl 静态库编译及使用

    下载源码 源码编译 解压之后,进入源码目录openssl-1.1.0f,执行如下命令.因为只需要编译静态库,也没有特殊要求,所以使用的编译选项配置很简单: ./config -fPIC no-shar ...

  2. 【C语言】标准库(头文件、静态库、动态库),windows与Linux平台下的常用C语言标准库

    一.Introduction 1.1 C语言标准库 1.2 历代C语言标准 1.3 主流C语言编译器 二.C语言标准库 2.1 常用标准头文件 2.2 常用标准静态库 三.windows平台 四.Li ...

  3. 技巧:Linux 动态库与静态库制作及使用详解

    http://www.ibm.com/developerworks/cn/linux/l-cn-linklib/ 技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用 ...

  4. linux 动态库建立,浅析linux下静态库和动态库的建立和使用

    在粤嵌学了很多知识,我们把常用的公用函数放在一起做成一个函数库,可以供其他程序共同使用,函数库本质上说,是一个可执行代码的二进制形式,可被操作系统载入内存执行.linux下的库分为两种:静态库,后缀名 ...

  5. linux编译ios动态库,[Linux] linux下生成静态库和动态库

    g++使用 用g++编译hello world 1. 编写hello world代码 2. 使用g++命令编译生成可执行文件hello.out 3. g++命令规则 预编译 g++ -E hello. ...

  6. 头文件和库文件区别,动态库和静态库的区别,动静态库的生成

    文章目录 一.什么是头文件?什么是库文件?有什么区别? 先说总结 目标文件 二.什么是静态库?什么是动态库?有什么区别? 三.为什么只用在程序头部写上包含的头文件,头文件中并没有实现内容就可以使用声明 ...

  7. linux系统中 库分为静态库和,你知道linux 静态库和共享库?

    1.静态库和共享库 静态库和共享库(动态库),二者的不同点在于代码被载入的时刻不同. 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大. 共享库的代码是在可执行程序运行时才载入内存的,在编译 ...

  8. cmake 编译 linux 库,使用CMake编译跨平台静态库

    在开始介绍如何使用CMake编译跨平台的静态库以前,先讲讲我在没有使用CMake以前所趟过的坑.由于不少开源的程序,好比png,都是自带编译脚本的.咱们可使用下列脚原本进行编译:linux . / c ...

  9. python爬豆瓣电视剧_python requests库爬取豆瓣电视剧数据并保存到本地详解

    首先要做的就是去豆瓣网找对应的接口,这里就不赘述了,谷歌浏览器抓包即可,然后要做的就是分析返回的json数据的结构: https://movie.douban.com/j/search_subject ...

最新文章

  1. python ggplot画等值线图,是否可以在Python ggplot上绘制多折线图?
  2. 吐槽知乎现任搜索引擎
  3. 当知识图谱遇上文本摘要:保留抽象式文本摘要的事实性知识
  4. mysql 5.5.23 winx64,win10下mysql 5.7.23 winx64安装配置方法图文教程
  5. python中的累乘积_Python中的连续元素最大乘积
  6. Spark创建临时视图
  7. 牛逼!用 MySQL 实现一个分布式锁,这也太强了。。。
  8. 3.2-点云配准原理概述
  9. 中国互联网发展状况报告:境内约 2.6 万网站被植入后门
  10. 手把手教你安装Xposed框架+JustTrustMe抓取手机APP数据
  11. ISE如何生成msc文件,并写入flash中
  12. Qt 之 自定义窗口标题栏
  13. 【线代】齐次方程组的解
  14. 如何越狱苹果TV2在iOS 4.2使用PwnageTool
  15. tinode客户端安卓版编译手账
  16. 机器人定位传感器之激光雷达
  17. 用格里高利公式求给定精度的PI值
  18. append()函数
  19. 一种有手就行的物联网平台的多终端接入方法
  20. 单片机编程:如何喂狗的灵魂拷问...

热门文章

  1. Android开发自定义的View
  2. 多DHCP服务器的作用域 及备用DHCP服务器(一)
  3. Partition分区及实例
  4. Linux操作oracle——关闭、停止、重启
  5. C语言strcpy,strncpy和strlcpy讲解
  6. 展讯camera去除尺寸相关缓存
  7. nginx主配置文件 在那找怎么打开
  8. 如何用计算机画立方体,画立方体-计算机图形学实验.doc
  9. stl clocklist 查找元素_C++|通俗理解STL
  10. nginx启动只有master没有worker_深入浅出Nginx