在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考。

编译时和运行时

纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台相关目标文件这一层次)和链接(Linking,指目标文件到最终形成可执行文件这一层次),这个总的过程可称为编译时;就动态链接而言,还存在一个运行时,即程序在被操作系统加载的过程中,系统将该程序需要的动态库加载至内存到程序开始运行的这一段过程。明确这两个过程在一般linux开发中的地位,以及了解每个“时”所遇要的文件、所运行的工具对理解linux动态链接很重要。

Linux共享库命名规范

回顾linux对动态库的命名规则,在一般情况下,均命名为libname.so.x.y.z。各版本号意义与兼容性标准如下表所示,这些也是程序员进行库程序设计是应该尽量遵守的设计规范。

版本号

意义

x

主版本号,表示重大升级,不同主版本的库之间是不兼容的

y

次版本号,表示增量升级,高次版本向后兼容低次版本号的库

z

发布版本号,表示一些错误修正,性能改进,不同发布版本号之间完全兼容

这样的设计很容易带来一个问题,即动态库如何进行有效地升级,而不要求依赖它的应用程序重新编译?比如demo.out依赖libsmath.so.1.0.0(该名称在编译已指定,储存在ELF文件的DT_NEEDED段中),现对该库升级至1.1.0,但demo.out程序已经无法使用新版本的库。为解决这样的问题,Linux引入一种新的机制SO-NANE.

SO-NAME版本控制

由上可知,共享库的主版本和次版本决定该共享库的接口,则对于依赖某库的应用程序,最小限度上只需记录该库的主版本号,具体的版本即次版本和发布版本,可以交给动态链接器(一般为ld-linux.so)来选择,这样便可以在一定程度上解决上述的问题。

具体设计实现方面,对于libname.so.x.y.z,省略其y和z,只记录成libname.so.x即为该共享库的SO-NAME,在需要该库的应用程序的DT_NEEDED段中记录这个SO-NAME,同时在动态链接器的库搜索目录添加这个库的软链接,指定为libname.so.x(可通过设置/etc/ld.so.conf或设置环境变量LD_LIBRARY_PATH)。这样对于libname.so.x.y.z的次版本和发布版本的升级,只需更新该软链接就行,应用程序无须重新编译。

同时,SO-NAME也会被记录在该动态库内,供ldconfig工具自动更新软链接所用,这也就是每次安装新软件包后一般会运行该工具的原因。

以上这些均是对于运行时而言的,在编译时同样需要一些该库的信息,指定所需要的库,即gcc的-lname选项。该选项主要是传递给链接器(ld,而非运行时所用的ld-linux.so),链接器会在库搜索目录(可通过设置-rpath参数或LIBRARY_PATH环境变量)搜索libname.so文件,所以为了能使用该库进行开发,需要在以上目录设定指向libname.so.x或libname.so.x.y.z的软链接,名称为libname.so.这项工作一般需手动完成。

示例

(下述例子中,smath.h、libsmath.so为编译时需要文件;libsmath.so.1、libsmath.so.1.0.0为运行时所需文件)

假设需要自定义编写一套数学库,其中有Add和Sub等函数

 //smath.h

 int Add(int,int);

 int Sub(int,int);
 //smath.c

 int Add(int a,int b)

 {

     return a+b;

 }

 int Sub(int a,int b)

 {

     return a-b;

 }

①编译

按照gcc操作手册

执行

gcc -shared -fPIC -Wl, -soname,libsmath.so.1 -o libmath.so.1.0.0 smath.c

     (若不指定-soname,则该库没有SO-NAME,DT_NEEDED中记录为空)

②安装

复制头文件

cp smath.h ~/include

安装至自定义目录(非/lib、/usr/lib等),假设安装至~/lib下

cp libsmath.so.1.0.0 ~/lib

cd ~/lib

ln -s libsmath.so.1.0.0 libsmath.so.1

ln -s libsmath.so.1 libsmath.so

③使用

保证smath.h 、libsmath.so在相关搜索目录下(编译链接用)

export C_INCLUDE_PATH=$HOME/include

export LIBRARY_PATH=$HOME/include

(也可设置gcc相关参数设置)

则现在可使用gcc编译如下代码

main.c

#include <stdio.h>

#include <smath.h>

int main()

{

    int a=,b=;

    printf(“%d + %d = %d\n”,a,b,Add(a,b));

    return ;

}

编译

gcc -omain.out -lsmath main.c 

④运行

保证libsmath.so.1在相关搜索目录下(运行链接用)

export LD_LIBRARY_PATH=$HOME/lib

(也可设置/etc/ld.so.conf目录)

即可运行

参考

《程序员的自我修养——链接、装载与库》 第8章

Working with libraries and the linker  --  http://bottomupcs.sourceforge.net/csbu/x4012.htm

再探Linux动态链接 -- 关于动态库的基础知识(Dynamic Linking on Linux Revisited)的更多相关文章

  1. 再探Linux动态链接 -- 关于动态库的基础知识

      在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考. 编译时和运行时 纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台 ...

  2. mingw qt(可以去掉mingwm10.dll、libgcc_s_dw2-1.dll、libstdc++-6.dll的依赖,mingw默认都是动态链接gcc的库而TDM是静态链接gcc库,tdm版本更好用。用aspack压缩没有问题。qt本身不使用异常处理)good

    原文地址:mingw qt作者:孙1东 不使用Qt SDK,使用mingw编译qt源代码所遇问题及解决方法: configure -fast -release -no-exceptions -no-r ...

  3. Linux dts 设备树详解(一) 基础知识

    Linux dts 设备树详解(一) 基础知识 Linux dts 设备树详解(二) 动手编写设备树dts 文章目录 1 前言 2 概念 2.1 什么是设备树 dts(device tree)? 2. ...

  4. [转] linux操作系统下c语言编程入门--基础知识

    点击阅读原文 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容: 1. 源程序编译        2. Makefile的编写        3. 程序库 ...

  5. linux的基本操作(shell 脚本的基础知识)

    shell 脚本的基础知识 日常的linux系统管理工作中必不可少的就是shell脚本,如果不会写shell脚本,那么你就不算一个合格的管理员.目前很多单位在招聘linux系统管理员时,shell脚本 ...

  6. 【转】Linux编译链接问题----静态库和动态库

    Linux静态库和动态库的命名规则 静态函数库 静态库的名字一般是libxxx.a,利用静态库编译生成的文件比较大,因为整个静态库所有的数据都会被整合进目标代码中. a) 优点: 编译后,可执行文件不 ...

  7. C 语言与动态库相关基础知识

    1.导入文件<>和“”的区别 #include <xxx.h>导入的是标准目录下的.h文件,所谓的标准目录指的是:/use/local/include(一般是第三方头文件)以及 ...

  8. Linux学习总结(十七)-shell 基础知识

    一 先介绍几种常用字符: 1 * 匹配任意个任意字符2 ?匹配一个任意字符3 # 注释符号,符号后的语句不被执行4 \脱意字符,后面跟带含义字符时,照原字符输出5 []匹配包含在[]之中的任意一个字符 ...

  9. android开发学习---linux下开发环境的搭建&& android基础知识介绍

    一.配置所需开发环境 1.基本环境配置 JDK 5或以上版本(仅有JRE不够) (http://www.oracle.com/technetwork/java/javase/downloads/ind ...

随机推荐

  1. Redis学习笔记(五)- 数据类型之set类型

    Redis 的set是string类型的无序集合.set元素最大可以包含(2的32次方-1)个元素.set的是通过hash table实现的,所以添加,删除,查找的复杂度都是O(1).hash tab ...

  2. 编译带加密功能的sqlite

    以为编译wxsqlite是很难的事情,竟然这么顺利. 1.下载wxsqlite代码,解压(wxcode.sourceforge.net/components/wxsqlite3/) 2.下载Prema ...

  3. Morse理论:拓扑不变性特征匹配原理

    设计精美的宽基线双目相机镇文 Mo'ersi lilun莫尔斯理论(卷名:数学) Morse theory 微分拓扑的一个重要分支.通常是指两部分内容:一部分是微分流形上可微函数的莫尔斯理论,即临界点 ...

  4. BSGS-BabyStepGiantStep算法+拓展

    学习数学真是一件赛艇的事. BSGS名字听起来非常有意思,力拔山兮气盖世,北上广深,小步大步...算法其实更有意思,它是用来求解一个方程的 A^x ≡ B (mod P) 是不是特别眼熟,有几个式子长 ...

  5. node jsonwebtoken

     jsonwebtoken是node版本的JWT(JSON Web Tokens)的实现.1.什么是JWT?Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于J ...

  6. Django逻辑关系

    title: Django学习笔记 subtitle: 1. Django逻辑关系 date: 2018-12-14 10:17:28 --- Django逻辑关系 本文档主要基于Django2.2官 ...

  7. appium分层自动化的封装

    1.创建一个case包,start_app的python文件 #coding=utf-8from appium import webdriverfrom util.read_init import R ...

  8. 移动端自动化测试-WTF Appium

    手机App分为两大类,原生App(Native App)和混合APP(Hybrid App) 原生App(Native App) 原生App实际就是我们所常见的传统App开发模式,云端数据存储+App ...

  9. eas之添加表格列宽自动调整设置

    设置表格整体宽度自动调整为所在panel的宽度 KDTable table=new KDTable(); table. setAutoResize (boolean); 注意:该功能在冻结功能启用后, ...

  10. 05.Python高级编程

    1 ==,is的使用 is 是比较两个引用是否指向了同一个对象(地址引用比较). == 是比较两个对象是否相等.(比较的数值) 2 深拷贝.浅拷贝.copy.copy 2.1 浅拷贝 浅拷贝: 拷贝的 ...