程序编译一般需要经预处理、编译、汇编和链接几个步骤。在实际应用中,有些公共代码需要反复使用,就把这些代码编译成为“库”文件。在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态(链接)库,其特点是可执行文件中包含了库代码的一份完整拷贝,缺点是被多次使用就会多份冗余拷贝。还有一种库,就是程序在开始运行后调用库函数时才被载入,这种库独立于现有的程序,其本身不可执行,但包含着程序需要调用的一些函数,这种库称为动态(链接)库(Dynamic Link Library)

在widows平台下,静态链接库是.lib文件,动态库文件是.dll文件。在linux平台下,静态链接库是.a文件,动态链接库是.so文件。这里主要讲在linux平台下的动态库和静态库的生成以及链接。本文主要参考【1】【2】【3】【4】

一、库的基本知识

首先说明要对库有一个比较直观的理解。库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。本质上说来库是一种可执行代码的二进制形式(注,其本身不可执行),可以被操作系统载入内存执行。

静态链接库,之所以称为“静态库”,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中,因此对应的链接方式为静态链接。其实一个静态链接库可以简单看成一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结:

1. 静态库对函数库的链接是放在编译时期完成

2. 程序在运行时对函数库再唔瓜葛,一直方便。

3. 浪费空间和资源,因为所有相关的目标文件和牵涉到的函数库被链接合成一个可执行文件。

linux下使用ar工具(windows下用lib.exe)(具体的用法参考【5】),可以将目标文件压缩到一起,并且对其进行编号和索引,一便于查找和索引。一般创建静态链接库的步骤如下:

静态链接库的命名规则,库的名称和库文件名称不同,有联系,假定库名称为"my_library_name",那么起库文件名为"lib[my_library_name].a"(方括号是为了区分,实际上没有)

动态链接库,在程序编译是并不会被连接到目标代码中,而是在程序运行时才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库的一些总结:

1. 动态库把对一些库函数的链接载入推迟到程序运行时期

2. 可以实现进程之间的资源共享,(动态库也成为共享库)

3. 将一些程序升级变得简单

4. 设置可以真正做到链接载入完全由程序员在程序代码中控制(显式调用)

Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。与windows系统下的格式不同。与创建静态库不同的是,不需要打包工具,直接使用编译器即可创建动态库。

        动态链接库的命名规则,与静态链接库的方式相同,不过其后缀名为.so,命名形式为"lib[my_library_name].so"   。但是在实际使用过程中libxxx.so 大多数情况只是一个链接,它链接到一个包含版本信息的库文件 libxxxx.so.xx,如下图。当然自己可以使用 ln 命令,制作链接 ln -s libxxxx.so.xx libxxxx.so。

二、库的编译和链接

下面使用一个例子来说明链接库是如何生成与链接的。这个例子的源代码参考【4】。这里有五个文件,头文件“SoDemoTest.h”,三个cpp文件“one.cpp”、"two.cpp"、"three.cpp",main函数实现文件“main.cpp”。

[cpp] view plaincopy
  1. #ifndef _SO_DEMO_TEST_HEADER_
  2. #define _SO_DEMO_TEST_HEADER_
  3. #include <iostream>
  4. using namespace std;
  5. void one();
  6. void two();
  7. void three();
  8. #endif
[cpp] view plaincopy
  1. /* one.cpp */
  2. #include "SoDemoTest.h"
  3. void one(){
  4. cout << "call one() function" << endl;
  5. }
[plain] view plaincopy
  1. /* two.cpp */
  2. #include "SoDemoTest.h"
  3. void two(){
  4. cout << "call two() function" << endl;
  5. }
[cpp] view plaincopy
  1. /* three.cpp */
  2. #include "SoDemoTest.h"
  3. void three(){
  4. cout << "call three() function" << endl;
  5. }
[cpp] view plaincopy
  1. /* main.cpp */
  2. #include "SoDemoTest.h"
  3. int main(){
  4. one();
  5. two();
  6. three();
  7. return 0;
  8. }

gcc/g++的编译参数,这里只介绍 -L 、-l、-include、-I、-shared、-fPIC

-L :表示要链接的库所在的目录。-L.  表示要链接的库在当前目录, -L/usr/lib 表示要连接的库在/usr/lib下。目录在/usr/lib时,系统会自动搜索这个目录,可以不用指明。

-l (L的小写):表示需要链接库的名称,注意不是库文件名称,比如库文件为 libtest.so,那么库名称为test

-include :包含头文件,这个很少用,因为一般情况下在源码中,都有指定头文件。

-I (i 的大写):指定头文件的所在的目录,可以使用相对路径。

-shared :指定生成动态链接库

-fPIC:  表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时事通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码共享的目的。

生成链接库

第1步,生成目标文件:g++ -c xxx.cpp

       第2步,创建静态链接库:  ar  cqs  libxxxx.a  xx1.o xx2.o xx3.o (参数选项请看【5】)
        第3步,程序中使用静态链接库
        第4步,创建动态链接库 g++ -fPIC -shared -o libxxx.so xx1.cpp xx2.cpp xx3.cpp
        第5步,动态链接库使用

 库的链接,上面简单演示了一遍库的生成过程,但是还有很多细节没有讲清楚。以下问题需要注意:

1. 链接过程中可能出现多种链接方式,需要使用一些参数来指定,下面只是一个演示,在测试时,自己填写具体的名称

[plain] view plaincopy
  1. g++ testmain.o -o testmain -WI,-Bstatic -lstaticlib -WI,-Bdynamic -ldynamiclib
     2. 链接过程中同一个库(名称相同)的静态和动态两种链接库,在链接过程中,系统优先选择动态链接库
     3. 动态链接库路径,系统默认在/usr/lib 和/usr/local/lib两个库目录搜索,自己定义的库需要格外指定路径(设定变量LD_LIABRARY_PATH)或者将其拷贝到这两个目录下,在上面的例子的测试过程,已经有说明。当然也可以将当前路径添加到/etc/ld.so.conf文件中或者/etc/ld.so.conf.d目录下的一个文件中。
      4. 查看动态链接库。有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多,常见的有三种:
        一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;
        一种是在库中定义的函数,用T表示,这是最常见的;
        另一种所谓的“弱态”符号,它们虽然在库中定义,但可能被其他库中的同名符号覆盖,用W表示。

使用ldd命令可以查看程序的库依赖:

         注:更多详细的信息请阅读下面的链接中的内容~

【1】博客园:C++静态库与动态库

【2】CSDN:Linux 静态库&动态库调用

【3】博客园:gcc/g++ 动态编译和链接问题

【4】Linux公社:用g++编译生成动态连接库*.so的方法及连接

【5】CSDN:linux ar命令

gcc/g++ 链接库的编译与链接相关推荐

  1. 【转】gcc/g++ 链接库的编译与链接

    转自:gcc/g++ 链接库的编译与链接_Surge-CSDN博客_g++ 链接 gcc/g++ 链接库的编译与链接 surgewong@gmail.com Surge_surgewong_CSDN博 ...

  2. linux下的动态链接库和静态链接库到底是个什么鬼?(一)静态链接库的编译与使用...

    知识不等于技术,这句话真的是越工作的时间长越深有体会,学习到的知识只有不断的实践,才成真正在自已的心里扎下根,成为自身的一部分,所以无论如何,我希望我的博客可以一直写下去,慢慢的沉淀,终会有回报,无聊 ...

  3. MFC模块的动态链接库DLL以及静态链接库LIB编译后的调用

    静态链接库LIB和动态链接库DLL的区别,创建和示例   1.什么是静态连接库,什么是动态链接库   静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都 ...

  4. gcc g++ 支持c++11编译的标准和区别

    g++ -g -Wall -std=c++11 main.cpp gcc -g -Wall -std=c11 main.cpp 如果不想每次写这个-std=C++11这个选项该怎么办呢? 方法出处:h ...

  5. linux 编译链接出错,Qt编译和链接错误

    为了演示 Qt Creator 的报错信息,我们刻意制造一个小 Bug.依然使用<Qt Creator使用教程(简明版)>一节中创建的项目和代码,双击 HelloWorld.pro,或者在 ...

  6. 【gcc/g++】1.编译器, 编译过程和基本参数

    "木叶飞舞之处" 一, gcc编译器 二, gcc的编译过程 1--完整版 1. 预处理 2. 编译 3. 汇编 4. 链接: 2--简化版 简化编译过程 3--编译完成 三, g ...

  7. linux静态链接库添加,c-静态链接库时,出现链接器错误:找不到-...

    使用g前端执行链接时,例如: g++ -o prog prog.o -Wl,-Bstatic -lcurl g调用链接器,将其传递给您的链接选项,并且也进行静默 向链接器命令行添加了大量样板选项,这些 ...

  8. Linux C++与Python混合编程(g++生成链接库与python调用)

    gcc/g++ 链接库的编译与链接 这一篇对动态链接库和静态链接库以及编译结果讲得很清楚,目前看到最好的. Linux下Python与C++混合编程

  9. UNIX环境高级编程(三)—— 静态链接库与动态链接库

    动态链接库一般不开放源码,需要建工程才能使用(其中提供的接口和 API): 0. .a/.o/.so What are .a and .so files? .o 就相当于 windows 里的 obj ...

最新文章

  1. C++ open 打开文件(含打开模式一览表)
  2. JMeter初探四-Fiddler录制与实战
  3. iphone闪退修复工具_升级 iOS 14.2 微信闪退?iPhone 12 维修贵
  4. jquery插件制作 -- 3.表单验证
  5. 读书笔记_中国期货市场量化交易(李尉)05
  6. 在HTML中取得请求中的参数
  7. LinkedHashMap/HashMap 介绍
  8. Ubuntu16下载tomcat8
  9. python如何识别文件中的空行?
  10. 国内外大数据经典案例研究
  11. 毕业设计3-BME280温湿度大气压传感器调试记录(STM32F103C8T6 + STM32CubeMX + BME280)
  12. 001-前端课程介绍
  13. 《吴忠与富平》之三:北地富平人物
  14. elementui中表格的表头设置背景颜色
  15. Redis由于目标计算机积极拒绝,无法连接。
  16. 增加虚拟android内存,怎么给安卓手机增加虚拟内存?
  17. 影响职场升迁的小动作
  18. 服务器协议失败,Chrome中的HTTPS服务器“不支持的协议错误”
  19. adbdriver的安装
  20. 亚马逊被人差评了怎么办?

热门文章

  1. iphone屏幕录制_iPhone怎么内录声音?怎么录制苹果手机内部声音?
  2. 单片机控制灯光亮度c语言程序,基于51单片机控制LED灯光亮度并报警
  3. php无法新数据类型,新手入门PHP必知的七种数据类型
  4. java writablesheet_jxl加边框,jxl合并单元格,单元格的设置,单元格居中
  5. 谷歌浏览器出现“远程计算机访问失败问题”
  6. 成都亿佰特物联网无线数传专家:lora无线传输模块网关技术的优缺点
  7. 物联网的下一步动作会是什么?
  8. android界面实现框架内页面跳转_KVM虚拟化管理平台的实现
  9. 2016年计算机网考,2016年电大:计算机网考(全)练习题.doc
  10. 计算机硬盘按不同接口,硬盘接口不同 速度差别竟然这么大