【Linux】Linux下静态库(.a)和动态库(.so)的制作和使用
如有错误,欢迎大家指正,感谢!
目录
一、程序工作过程简单介绍
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下静态库的制作过程:
- gcc命令获得.o文件:gcc -c xx.c xx.c xx.c
- 使用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下制作动态库的过程:
- gcc得到.o文件,得到和位置无关的代码:gcc -c -fpic/fPIC xx.c xx.c
- 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)的制作和使用相关推荐
- [转]Linux下g++编译与使用静态库(.a)和动态库(.os) (+修正与解释)
在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库 ...
- Linux下CMake简明教程(六)动态库和静态库的编译控制
代码在git 有时只需要编译出动态库和静态库,然后等着让其它程序去使用.让我们看下这种情况该如何使用cmake.首先按照如下重新组织文件,只留下testFunc.h和TestFunc.c ├── CM ...
- 在Linux中创建静态库.a和动态库.so
转自:http://www.cnblogs.com/laojie4321/archive/2012/03/28/2421056.html 在Linux中创建静态库.a和动态库.so 我们通常把一些公用 ...
- linux系统应用学习(三)--- 动态库静态库
动态库静态库 库文件:一般指第三方提供的可调用的库函数文件,库文件封存的是函数体,即.c文件里面的内容. 动态库 静态库 Windows下: xx.dll ...
- Linux静态库.a与动态库.so的生成与区别、以及.so库文件的封装与使用
#一.前言 如果有公司需要使用你们产品的一部分功能(通过代码调用这些功能),如果不想提供源代码,那么就可以通过封装成库文件的形式提供给对方使用.本文主要介绍了生成动态库与静态库文件的过程.以及封装和使 ...
- linux库引入之动态库静态库(生成和使用)
库: 库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.就是将源代码转化为二进制格式的源代码,相当于进行了加密,别人可以使用库,但是看不到库中的内容. 如何使用 用户需要同时具有头文件和库. ...
- 【linux】程序找不到动态库.so的解决办法|查看.so动态库信息|.so动态库加载顺序
目录 找不到.so解决方法 方法一:添加环境变量 方法二:复制so文件到lib路径 方法三:(推荐)添加ldconfig寻找路径 方法四:在编译目标代码时指定该程序的动态库搜索路径 让程序在本目录找到 ...
- linux平台 使用dlopen接口调用HelloWorld动态库简单实例
动态库(libxxx.so)一种调用方式是在编译的时候的时候指定库名 -lxxx,另一种调用方式是通过dlopen在程序里加载动态库,然后调用相关接口.相关接口比较简单,包括打开动态库,解析库里提供的 ...
- linux 编译查看链接库详情,Linux环境下的编译,链接与库的使用
链接参数控制 链接器中提供了-dn -dy 参数来控制使用的是动态库还是静态库,-dn表示后面使用的是静态库,-dy表示使用的是动态库 例: g++ -Lpath -Wl,-dn -lx -Wl,-d ...
- gcc生成静态库.a和动态库.a以及Ubuntu18.04下opencv3.4.11安装及示例
目录 一.用gcc生成静态库和动态库 (一)hello示例使用库 1.准备过程 2.静态库使用 3.动态库的使用 4.静态库与动态库比较 (二)示例1使用库 二.opencv安装以及使用 (一)认识o ...
最新文章
- python读取excel写入数据库_python实现读取excel写入mysql的小工具详解
- 科大星云诗社动态20211212
- IE6下margin-left双倍bug问题
- 算法 笔试的时候 如何输入元素?
- 日常问题———安装新版zookeeper 出现Starting zookeeper ... FAILED TO START
- 信息学奥赛一本通(1077:统计满足条件的4位数)
- 【Matplotlib】【Python】如何使用matplotlib绘制各种图形
- 列出最少8种开源软件_您的公司可以支持和维持开源的8种方式
- Jenkins:项目配置
- 云服务器学习linux_云服务器怎么选linux系统
- python pip工具安装教程
- linux使用tar命令,Linux的tar命令使用简介
- Python selenium 实现大麦网自动购票过程
- 小白新手web开发简单总结(三)-一个简单的Web开发项目
- 前端推荐的书籍学习(必看)
- 深度学习方法(十五):知识蒸馏(Distilling the Knowledge in a Neural Network),在线蒸馏
- LDUOJ spj 修改
- 什么是Galil(加利尔)运动控制卡,它是用来干嘛的呢?galil开发文件dmc32.dll,动态链接库,API
- Computer Vision笔记01:图像处理
- MAC下虚拟机PD转换成win上可以用的vmware