如有错误,欢迎大家指正,感谢!

​​​​​​​目录

一、程序工作过程简单介绍

1. 安装GCC

2. 源程序工作流程

3. 使用示例

4. gcc常用的编译参数选项

二、静态库的制作及使用

1. 库是什么

2. 静态库的制作及使用

2.1. 制作静态库

2.2. 使用静态库

2.3 静态库的制作和使用总结

三、 动态库的制作和使用

1 制作动态库

2. 使用动态库

2.1 动态库的工作原理

2.2 定位共享库

3.  动态库的制作和使用总结

四、 静态库和动态库的比较


本文讲解Linux下静态库和动态库的制作和使用,分如下部分:

  • 程序工作的过程;
  • 静态库的制作和使用;
  • 动态库的制作和使用;
  • 静态库和动态库的区别;

在介绍静态库和动态库的制作及使用之前,需要先了解程序的工作流程。

一、程序工作过程简单介绍

1. 安装GCC

Linux下使用GCC对.c或.cpp文件进行编译链接生成可执行的文件。
简单理解,GCC就是一个编译器,把程序源文件编译成可执行文件。

GCC支持C的不同标准,可以使用命令行参数 -std=c99 决定编译时使用哪一个标准,如: -std=c99表示编译器支持C99标准。
安装GCC的命令(g++表示C++):

sudo apt install gcc g++

查看安装的GCC/G++版本可以使用如下命令:

gcc -v
gcc --version
g++ -v
g++ --version

2. 源程序工作流程

源程序变成可执行程序的流程如下,高级语言经过编译生成汇编语言,汇编语言经过汇编变成计算机可以识别的机器语言,机器语言可以在计算机上直接运行。

GCC工作流程:

源代码进行预处理(-E)变成预处理后源代码(.i),再经过编译器编译(-S)生成汇编代码(.s),汇编代码经过汇编器汇编(-c)成为目标代码(.o),目标代码与库代码、其它目标代码等一起经过链接器链接成可执行程序。

3. 使用示例

在Linux/lesson3/文件夹下新建test.c文件,文件内容如下:

#include <stdio.h>int main()
{#ifdef DEBUGprintf("This is DEBUG info\n");#endif// This is one-line commentprintf("Hello Linux!\n");return 0;
}

1> 使用gcc命令【-E】进行预处理生成预处理文件(.i),并显示预处理后生成的文件。
                -E是预处理命令,-o指定生成的文件;
                ls 查看当前文件夹内的所有文件夹及文件;

~/Linux/lesson3$ gcc test.c -E -o test.i
~/Linux/lesson3$ ls
test.c  test.i

2> 使用gcc命令【-S】进行编译(只编译,不汇编)生成汇编代码(.s),并显示编译后的文件。
                -S 编译指定的源文件,不进行汇编,-o指定生成的文件;
                ls  查看当前文件夹内所有文件夹及文件

~/Linux/lesson3$ gcc test.i -S -o test.s
~/Linux/lesson3$ ls
test.c  test.i  test.s

3> 使用gcc命令【-c】进行编译、汇编,不进行链接,并显示编译、汇编后的文件。
                -c 编译、汇编指定的文件,但是不进行链接
                ls 查看当前文件夹内所有文件夹及文件

~/Linux/lesson3$ gcc test.s -c -o test.o
~/Linux/lesson3$ ls
test.c  test.i  test.o  test.s

4> 使用gcc命令【-o】链接指定的文件生成可执行文件,并运行可执行文件。
                -o [file1] [file2]或者 [file2] -o [file1] 把【文件file2】编译成【可执行文件file1】
                ls 查看当前文件夹内的所有文件夹及文件
                ./a.out 运行可执行文件

~/Linux/lesson3$ gcc test.o -o a.out
~/Linux/lesson3$ ls
a.out  test.c  test.i  test.o  test.s
~/Linux/lesson3$ ./a.out
Hello Linux!

4. gcc常用的编译参数选项

gcc编译选项 说明 示例
-E

预处理指定的源文件,不进行编译;

如果不指定生成的文件,会把预处理后的内容显示在终端;如果指定了生成的文件(如示例),会把预处理后的内容保存到指定的文件内

gcc test.c -E -o test.i
-S

编译指定的源文件,不进行汇编;

不指定生成的文件会把编译后的文件保存到【源文件名.s】中

gcc test.i -S

gcc test.i -S -o test.s

gcc test.c -S

gcc test.c -S -otest.s

-c

编译、汇编指定的源文件,不进行链接

不指定生成的文件会把编译后的文件保存到【源文件名.o】中

gcc test.i -c

gcc test.s -c -o test.o

gcc test.c -c

gcc test.c -c -o test.o

-o [file1] [file2]

[file2] -o [file1]

把文件file2编译成可执行文件file1

gcc test.c -o a.out

gcc -o a.out test.c

gcc test.o -o a.out

gcc -o a.out test.o

-I Directory 指定include包含文件的搜索目录 gcc test.c -I ./include/
-g 在编译时,生成调试信息,表示该程序可以被调试器调试
-D

程序编译时,指定一个宏,该宏内的代码会被执行;

-D后加宏的名字,如示例中【DEBUG】就是代码中宏名

gcc test.c -o a.out -DDEBUG
-w 不生成任何警告信息
-Wall 生成所有警告信息
-On 表示编译器的优化,n取值范围0~3,-O0表示没有优化,-O1默认,-O3优化级别最高
-l 程序编译时,指定使用的库
-L 指定编译的时候,搜索的库的路径

-fPIC

-fpic

生成与位置无关的代码
-shared 生成共享目标文件,通常在建立共享库时使用
-std 指定c标准,默认是GNU C -std=c99,表示使用c99标准

二、静态库的制作及使用

1. 库是什么

库文件是计算机上的一类文件,可以简单的把库文件看作是代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。

库是特殊的一种程序,编写库的程序和编写一般的程序区别不大,只不过库不能单独运行。

库文件有两种:静态库和动态库,动态库又称为共享库,二者区别:
        静态库在程序的链接阶段被复制到程序中;
        动态库/共享库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。

库当然是有优点的,使用库可以使代码保密,并且方柏霓部署和分发。

2. 静态库的制作及使用

静态库在不同平台下文件类型不同。

window下静态库为.lib文件,libxxx.lib;

linux下静态库为.a文件,libxxx.a;

lib是前缀,表示是库文件,是固定的;
xxx是库名;
.lib/.a是后缀名,是固定的;

2.1. 制作静态库

Linux下静态库的制作过程:

  1. gcc命令获得.o文件:gcc -c xx.c xx.c xx.c
  2. 使用ar工具(archive),将.o文件打包
             ar rcs libxxx.a xxx.o xxx.o
      r - 将文件插入到备存文件中
      c - 建立备存文件
      s - 索引

示例,有如下文件夹,包含calc和library两个文件夹,calc文件夹内包含
        add.c——加法计算、div.c——除法计算、mult.c——乘法计算、sub.c——减法计算
        head.h——加、减、乘、除的函数声明
        main.c——对加、减、乘、除函数的调用

各个文件的内容如下:

head.h:

#ifndef _HEAD_H
#define _HEAD_H// 加法
int add(int a, int b);
// 减法
int subtract(int a, int b);
// 乘法
int multiply(int a, int b);
// 除法
double divide(int a, int b);#endif

add.c:

#include <stdio.h>
#include "head.h"int add(int a, int b)
{return a+b;
}

div.c:

#include <stdio.h>
#include "head.h"double divide(int a, int b)
{return (double)a/b;
}

mult.c:

#include <stdio.h>
#include "head.h"int multiply(int a, int b)
{return a*b;
}

sub.c:

#include <stdio.h>
#include "head.h"int subtract(int a, int b)
{return a-b;
}

main.c:

#include <stdio.h>
#include "head.h"int main()
{int a = 20;int b = 12;printf("a = %d, b = %d\n", a, b);printf("a + b = %d\n", add(a, b));printf("a - b = %d\n", subtract(a, b));printf("a * b = %d\n", multiply(a, b));printf("a / b = %f\n", divide(a, b));return 0;
}

制作静态库的过程:

1>  进入calc文件夹

~/Linux/lesson4$ cd calc
~/Linux/lesson4/calc$ ls
add.c  div.c  head.h  main.c  mult.c  sub.c

2> 编译add.c、div.c、mult.c、sub.c文件,生成为.o文件

~/Linux/lesson4/calc$ gcc -c add.c div.c mult.c sub.c
~/Linux/lesson4/calc$ ls
add.c  add.o  div.c  div.o  head.h  main.c  mult.c  mult.o  sub.c  sub.o

3> 把生成的.o文件打包成静态库文件,假定库名为cacl,可以看到已经生成了libcacl.a库文件

~/Linux/lesson4/calc$ ar rcs libcacl.a add.o div.o mult.o sub.o
~/Linux/lesson4/calc$ ls
add.c  div.c  head.h     main.c  mult.o  sub.o
add.o  div.o  libcacl.a  mult.c  sub.c

2.2. 使用静态库

使用静态库时需要用
        -l命令指定使用的库名;
        -L命令指定库所在的路径。

如上在calc文件夹内,main.c文件生成可执行文件使用到库libcacl.a

~/Linux/lesson4/calc$ gcc main.c -o app -lcacl -L ./
~/Linux/lesson4/calc$ ls
add.c  app    div.o   libcacl.a  mult.c  sub.c
add.o  div.c  head.h  main.c     mult.o  sub.o
~/Linux/lesson4/calc$ ./app
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667

如果生成的库在library/lib文件夹内,如下。

在library文件夹中编译main.c生成可执行文件,那么还需要指明包含文件的路径

~/Linux/lesson4/library$ gcc main.c -o app -I ./include/ -lcacl -L ./lib/
~/Linux/lesson4/library$ ls
app  include  lib  main.c  src
~/Linux/lesson4/library$ ./app
a = 20, b = 12
a + b = 32
a - b = 8
a * b = 240
a / b = 1.666667

2.3 静态库的制作和使用总结

制作静态库:
        首先使用【gcc -c xxx.c xxx.c】编译为.o文件;然后使用【ar rcs libxxx.a *.o】命令把需要的.o文件打包为静态库文件。

使用静态库:
        使用【gcc main.c -o app -I [包含的头文件路径] -L [库文件路径] -l[库名]】命令编译生成可执行文件即可。

静态库制作完成后分发给别人使用时,需要把对应的头文件和静态库文件发出去。

三、 动态库的制作和使用

动态库在不同平台下的文件类型不同

windows平台下是 libxxx.dll;
linux平台下是libxxx.so;

lib是前缀,表明是库文件,固定的;
xxx是库名;
.dll/.so是后缀,固定的

1 制作动态库

linux下制作动态库的过程:

  1. gcc得到.o文件,得到和位置无关的代码:gcc -c -fpic/fPIC xx.c xx.c
  2. gcc得到动态库,使用-shared参数:gcc -shared xx.o xx.o -o libxx.so

针对上面的library文件夹,按照如下命令生成动态库

1> 生成.o文件

/library/src$ gcc -c -fpic *.c -I ../include/

2> 生成动态库

/library/src$ gcc -shared *.o -o libcalc.so

2. 使用动态库

2.1 动态库的工作原理

首先了解下库的工作原理。

静态库是GCC进行链接时,会把静态库中代码打包到可执行程序中;
动态库是GCC进行链接时,动态库的代码不会被打包到可执行程序中;

程序启动后,动态库会被动态加载到内存中,通过ldd 命令可以检查动态库的依赖关系,如下main.c调用动态库生成的可执行文件,使用ldd命令查看依赖关系。

如下用到的libcalc.so是因为执行程序没有找到该动态库的地址,所以显示【not found】。

2.2 定位共享库

动态库使用时需要先定位到它所在的位置。当系统加载可执行代码时,能够知道其所以来的库的名字,但是还需要知道绝对路劲。就需要系统的动态载入器获取绝对路径。对于elf格式的可执行程序,是由ld-linux.so完成的,它先后搜索elf文件的DT_RPATH段——>设置环境变量LD_LIBRARY_PATH——>/etc/ld.so.cache文件列表——>/lib/usr/lib目录找到库文件后将其载入内存。

具体定位共享库的方法有如下:

  • 第一种,配置环境变量,一次性的,只有一个终端可用。

在当前终端下输入如下命令,冒号后面是共享库所在的路径。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/usr/Linux/lesson4/library/lib

方便的获取动态库的路径,先定位到动态库所在路径下,然后使用【pwd】命令可以获取当前目录的完整路径。

然后可以输入以下命令查看环境配置是否成功:

echo $LD_LIBRARY_PATH

显示如下表示配置环境变量LD_LIBRARY_PATH成功:

这种配置只能用在当前终端,属于一次性的。

  • 第二种,用户级别的配置,只对当前用户有效。对.bashrc文件配置

首先【cd】命令进入home目录,【ll】命令查看home目录下的文件及文件夹

然后【vim .bashrc】命令对.bashrc文件编辑,最后一行加入如下内容,保存退出。

最后使用【. .bashrc】或【source .bahsrc】命令更新配置。

使用【echo $LD_LIBRARY_PTAH】命令查看是否添加成功:

  • 第三种,系统级别的环境变量配置,需要root权限。

首先,系统级别的环境配置需编辑【/etc/profile】文件

$ sudo vim /etc/profile

在文件最后添加:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/usr/Linux/lesson4/library/lib

然后,使用命令更新编辑后的文件

$ source /etc/profile

查看是否添加成功

$ echo $LD_LIBRARY_PATH

显示添加的路径表示添加成功。

  • 第四种,修改【/etc/ld.so.cache】文件

【/etc/ld.so.cache】文件是二进制文件,不能修改,那么通过修改/etc/ld.so.conf文件,把共享库的路径添加,最后更新配置,具体命令:

检查是否添加成功,转到可执行程序目录,使用【ldd xxx】命令查看依赖库能否找到。

  • 第五种,把共享库文件放到/lib和/use/li目录下,不建议使用该种方法。

3.  动态库的制作和使用总结

制作动态库

首先使用【gcc -c -fpic xx.c xx.c】或【gcc -c -fPIC xx.c xx.c】命令编译生成.o文件,然后使用【gcc -shared xx.o xx,o -o libxx.so】命令生成共享库。

使用动态库

需要先定位到共享库,可以配置环境变量:【LD_LIBRARY_PATH】或者修改【/etc/ld.so.conf】文件,使共享库能够被定位到。

动态库分发给别人使用时需要提供头文件和动态库文件。

以上参考:课程列表_牛客网 (nowcoder.com)https://www.nowcoder.com/study/live/504/1/8

四、 静态库和动态库的比较

静态库的优点:

  • 静态库被打包到应用程序中加载速度快;
  • 发布程序无需提供静态库,移植方便

静态库的缺点:

  • 消耗系统资源,浪费内存:
  • 更新、部署、发布麻烦;

动态库的优点:

  • 可以实现进程间资源共享;
  • 更新,部署,发布简单;
  • 可以控制何时加载动态库

动态库的缺点:

  • 加载速度相对静态库慢一些;
  • 发布程序时需要提供依赖的动态库;

全文参考:

课程列表_牛客网 (nowcoder.com)

【Linux】Linux下静态库(.a)和动态库(.so)的制作和使用相关推荐

  1. [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库 ...

  2. Linux下CMake简明教程(六)动态库和静态库的编译控制

    代码在git 有时只需要编译出动态库和静态库,然后等着让其它程序去使用.让我们看下这种情况该如何使用cmake.首先按照如下重新组织文件,只留下testFunc.h和TestFunc.c ├── CM ...

  3. 在Linux中创建静态库.a和动态库.so

    转自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html 在Linux中创建静态库.a和动态库.so 我们通常把一些公用 ...

  4. linux系统应用学习(三)--- 动态库静态库

    动态库静态库 库文件:一般指第三方提供的可调用的库函数文件,库文件封存的是函数体,即.c文件里面的内容. 动态库      静态库 Windows下:        xx.dll            ...

  5. Linux静态库.a与动态库.so的生成与区别、以及.so库文件的封装与使用

    #一.前言 如果有公司需要使用你们产品的一部分功能(通过代码调用这些功能),如果不想提供源代码,那么就可以通过封装成库文件的形式提供给对方使用.本文主要介绍了生成动态库与静态库文件的过程.以及封装和使 ...

  6. linux库引入之动态库静态库(生成和使用)

    库: 库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.就是将源代码转化为二进制格式的源代码,相当于进行了加密,别人可以使用库,但是看不到库中的内容. 如何使用 用户需要同时具有头文件和库. ...

  7. 【linux】程序找不到动态库.so的解决办法|查看.so动态库信息|.so动态库加载顺序

    目录 找不到.so解决方法 方法一:添加环境变量 方法二:复制so文件到lib路径 方法三:(推荐)添加ldconfig寻找路径 方法四:在编译目标代码时指定该程序的动态库搜索路径 让程序在本目录找到 ...

  8. linux平台 使用dlopen接口调用HelloWorld动态库简单实例

    动态库(libxxx.so)一种调用方式是在编译的时候的时候指定库名 -lxxx,另一种调用方式是通过dlopen在程序里加载动态库,然后调用相关接口.相关接口比较简单,包括打开动态库,解析库里提供的 ...

  9. linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用

    链接参数控制 链接器中提供了-dn -dy 参数来控制使用的是动态库还是静态库,-dn表示后面使用的是静态库,-dy表示使用的是动态库 例: g++ -Lpath -Wl,-dn -lx -Wl,-d ...

  10. gcc生成静态库.a和动态库.a以及Ubuntu18.04下opencv3.4.11安装及示例

    目录 一.用gcc生成静态库和动态库 (一)hello示例使用库 1.准备过程 2.静态库使用 3.动态库的使用 4.静态库与动态库比较 (二)示例1使用库 二.opencv安装以及使用 (一)认识o ...

最新文章

  1. python读取excel写入数据库_python实现读取excel写入mysql的小工具详解
  2. 科大星云诗社动态20211212
  3. IE6下margin-left双倍bug问题
  4. 算法 笔试的时候 如何输入元素?
  5. 日常问题———安装新版zookeeper 出现Starting zookeeper ... FAILED TO START
  6. 信息学奥赛一本通(1077:统计满足条件的4位数)
  7. 【Matplotlib】【Python】如何使用matplotlib绘制各种图形
  8. 列出最少8种开源软件_您的公司可以支持和维持开源的8种方式
  9. Jenkins:项目配置
  10. 云服务器学习linux_云服务器怎么选linux系统
  11. python pip工具安装教程
  12. linux使用tar命令,Linux的tar命令使用简介
  13. Python selenium 实现大麦网自动购票过程
  14. 小白新手web开发简单总结(三)-一个简单的Web开发项目
  15. 前端推荐的书籍学习(必看)
  16. 深度学习方法(十五):知识蒸馏(Distilling the Knowledge in a Neural Network),在线蒸馏
  17. LDUOJ spj 修改
  18. 什么是Galil(加利尔)运动控制卡,它是用来干嘛的呢?galil开发文件dmc32.dll,动态链接库,API
  19. Computer Vision笔记01:图像处理
  20. MAC下虚拟机PD转换成win上可以用的vmware

热门文章

  1. EDMA SEED 例程
  2. 123.买卖股票时机3_前后缀和
  3. vue2 打印二维码功能
  4. java 计算百分比值
  5. HBuilder 安装 vant
  6. 2010.09.28_ximo_纠正下VMP脱壳中的修复DLL的错误
  7. 大家看看这个vmp壳如何下手脱壳?
  8. 黑马视频学习笔记-FOUNDATION-Array集合
  9. C++的lib文件到底是什么
  10. Arduino学习篇记录1.1——安装Mixly(米思齐)及完成hello world