来自 服务器&运维 2020-03-02 00:39 的文章
当前位置: 澳门威尼斯人平台 > 服务器&运维 > 正文

Linux之静态库与动态库20160706

Linux库类型

Linux下能够创设三种类型的库:

  1. 静态库(.a): 在链接时期被应用程序直接链接进可试行文件
  2. 动态链接库(.so): 动态库还分为二种用法: a)应用程序运营时期链接动态库,可是在编写翻译时期证明动态库的留存,也便是说这种动态库必需在编写翻译时对编写翻译器可以看到,但编写翻译器却不将此种库编写翻译进可实行文件; bState of Qatar在运作时期,动态加载和卸载的库,使用动态加载方法加载。这种库的花样跟动态链接未有本质差异,差距是在调用时,是由顾客程序决定何时链接的,并非由系统链接器自动链接

正文同步发表于自己的民用网址:Linux静态库和动态库

所谓静态链接是指把要调用的函数或然经过链接到可施行文件中,成为可施行文件的一有的。当多少个程序都调用相似函数时,内部存储器中就能够存在这里个函数的三个拷贝,那样就浪费了宝贵的内部存款和储蓄器能源。.so文件是共享库文件(动态链接)。动态链接所调用的函数代码并未被拷贝到应用程序的可实践文件中去,而是唯有在里头参预了所调用函数的叙说音讯(往往是一些重定位音信),仅当应用程序棉被服装入内部存款和储蓄器开始运转时,在操作系统的军事拘留下,才在应用程序与相应的.so之间建构链接关系。

命名约定

库供给以lib作为早先,而在钦定链接命令行参数时,却不必要包括开始和扩展名,比如:

gcc src-file.c -lm -lpthread

本条例子中,链接了libmath.alibpthread.a


.a文件是多少个.o文件的重新整合。.o文件就是指标文件,里面包罗的内容正是01这么的机械可试行的指令,当程序要实践时还亟需张开链接(link卡塔尔.链接便是把四个.o文件链成二个可实行文件。
有关库生成的标题
作者们平淡无奇把一些公用函数制作成函数库,供别的程序行使。函数库分为静态库和动态库二种。静态库在前后相继编写翻译时会被接连到对象代码中,程序运维时将不再要求该静态库。动态库在先后编译时并不会被接连到对象代码中,而是在程序运维是才被载入,由此在程序运转时还亟需动态仓库储存在。
(1)静态库
大约地说,静态库是三个目的文件的简要集合。由此,首先要解决目的文件。
首先步:将各函数代码所在的源文件编写翻译成目录文件。
例如,对于myfunc.c, myproc.c
gcc -c myfunc.c myproc.c
将得到myfunc.o和myproc.o。
其次步:由ar(archive,归档的意味)把三个目的文件群集起来。
$ar -r libmyjob.a myfunc.o myproc.o
习感觉常,静态库的命名方式应遵从libXXXXX.a格式。应用程序在动用静态库的时候,常常只必要把命名中的XXXXX部分传递给gcc就能够。举个例子:
$gcc –o mywork –lmyjob …
意为让gcc(实际上是gcc调用ld)去老是多少个名称为libmyjob.a(只怕libmyjob.so)的库。若是库的命名不据守libXXXXX.a的格式就找不到对应文件。
事例:创制静态库
hello.h为该函数库的头文件。hello.c是函数库的源程序,当中富含公用函数hello,该函数将要荧屏上输出"
hello XXX!"。main.c为测量试验库文件的主程序,在主程序中调用了公用函数hello。
程序1:
//hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif
程序2:
//hello.c
#include <stdio.h>
void hello(const char *name)
{
printf("hello %s! n",name);
}
程序3:
//main.c
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
福寿绵绵步骤:
率先步:必得将源程序hello.c通过gcc先编写翻译成.o文件,生成hello.o(静态库/动态库,都以由.o文件创制的);
第二步:由.o文件创造静态库,生成libmyhello.a(静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名称叫.a)创立静态库用ar命令;
其三步:在前后相继中选拔静态库;(只须求在使用到这个公用函数的源程序中带有那一个公用函数的原型申明,然后在用gcc命令生成指标文件时指明静态库名,gcc将会从静态库元帅公用函数连接到对象文件中。注意,gcc会在静态库名前加上前缀lib,然后追加扩充名.a获得的静态库文件名来探求静态库文件)
第四步:删除静态库文件,程序照常运作,静态库中的公用函数hello已经再而三到对象文件main中了。
运行:
[root@localhost moduletest]# ls
hello.c hello.h main.c
[root@localhost moduletest]# gcc -c hello.c
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# ar crv libmyhello.a hello.o
a - hello.o
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.a main.c
[澳门威尼斯人平台,root@localhost moduletest]# gcc main.c libmyhello.a -o main
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]# rm -f libmyhello.a
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
(2)共享库
共享库的结构复杂一些,平时是三个ELF格式的公文。可以有几种方式生成:
$ld -G
$gcc -shared
$libtool
用ld最复杂,用gcc -share就大致的多,可是-share并不是在别的平台都能够利用。GNU提供了二个更加好的工具libtool,专门用来在各类平台上变化各类库。
用gcc的-shared参数:
gcc –shared –o libmyjob.so myjob.o
那样,就通过myjob.o生成了分享库文件libmyjob.so。
特意地,在CYGWIN情状下,仍急需输出符合Windows命名的分享库(动态库),即libXXXXX.dll。如:
gcc –shared –o libmyjob.dll myjob.o
事例:创设动态库(延用上边包车型客车先后1,2,3)
兑现步骤:
第五步:由.o文件成立动态库文件(命令:gcc -shared -fPCI -o libmyhello.so hello.o);
第六步:在程序中动用动态库;(在先后中选拔动态库和选择静态库完全等同,也是在使用到这个公用函数的源程序中带有这么些公用函数的原型表明,然后在用gcc命令生成目的文件时指明动态库名举行编写翻译。程序在运维时,会在/usr/lib和/lib等目录中查究必要的动态库文件。若找到,则载入动态库,不然将唤起错误音信而告一段落程序运营。要将文件libmyhello.so复制到目录/usr/lib中)
运行:
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# gcc -shared -fPIC -o libmyhello.so hello.o
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.so main.c
[root@localhost moduletest]# gcc main.c libmyhello.so -o main
[root@localhost moduletest]# ls
hello.c hello.h hello.o libmyhello.so main main.c
[root@localhost moduletest]# ./main
./main: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory
[root@localhost moduletest]# mv libmyhello.so /usr/lib
可以:
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
或者:
[root@localhost moduletest]# rm -f main
[root@localhost moduletest]# ls
hello.c hello.h hello.o main.c
[root@localhost moduletest]# gcc -Wall -g main.c -lmyhello -o main
[root@localhost moduletest]# ls
hello.c hello.h hello.o main main.c
[root@localhost moduletest]# ./main
hello everyone!
[root@localhost moduletest]#
注意:
当静态库和动态库同名时, gcc命令将先行利用动态库。
(3)库生成现在的配备
若是要把本人开支的库文件安装到操作系统中,必要有管理员权限:
(a卡塔尔(قطر‎ 把库文件复制到适当的目录:
能够把团结支付的动态连接库放到/usr/local/lib(大概/usr/lib),或放到任何目录,但无论放在那,都必得与LIBRATucsonY_PATH的值、LD_LIBRARY_PATH的值相平等。
(b卡塔尔(قطر‎ 修正相关的系统结构文件:
校勘/etc/ld.so.conf,然后利用/sbin/ldconfig来造成。
Note:
编写翻译参数解析
最根本的是GCC命令行的贰个增选:
-shared 该接受钦定生成动态连接库(让连接器生成T类型的导出符号表,不经常候也生成弱连接W类型的导出符号),不用该标识外界程序无法连接。相当于三个可推行文件
l -fPIC:表示编写翻译为地方独立的代码,不用此选项的话编写翻译后的代码是岗位相关的之所以动态载入时是经过代码拷贝的不二等秘书籍来满意分化进度的供给,而无法达到规定的标正确实代码段分享的指标。
l -L.:表示要连接的库在当前目录中
l -ltest:编译器查找动态连接库时有隐含的命名准绳,即在交付的名字前边加上lib,前边加上.so来明确库的名号
l LD_LIBRARY_PATH:那一个情况变量提示动态连接器能够装载动态库的门路。
l 当然假如有root权限的话,能够改善/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到相通的目标,然而固然未有root权限,那么只可以选取输出LD_LIBRARY_PATH的点子了。
调用动态库的时候有多少个难题会时不经常遇上,不经常,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数指引,并钦赐了“-l”的库名,但通过ldd命令察看时,便是板上钉钉找不到您内定链接的so文件,当时你要作的正是透过改造LD_LIBRARY_PATH只怕/etc/ld.so.conf文件来钦点动态库的目录。平常那样做就足以解决库不能链接的标题了。

静态库(.a)

变化静态库的主意如下:

  • 编译object文件。例如:cc -Wall -c ctest1.c ctest2.c,该命令会变动ctest1.octest2.o(其中-Wall表示编译时输出警示卡塔尔国。
  • 始建库文件。举例:ar -cvq libctest.a ctest1.o ctest2.o。该命令会得到叁个libctest.a文件
  • 能够通过ar -t查看.a文件中饱含怎么着.o。所以,实际上ar便是一个封装命令,相像tar
  • 营造符号表。ranlib libctest.a用于为.a创设符号表。有些ar命令实际莺时经集成了ranlib的功能

.a文件与windows下的.lib是相仿的定义。

Linux静态库和动态库

在windows平台和linux平台下都大量存在着库。本质上的话库是一种可实行的二进制代码(但不得以独立试行卡塔尔(قطر‎,能够被操作系统载入内部存款和储蓄器实施。

Linux下的库有三种:静态库和动态库(分享库)。

本文将介绍Linux下静态库和动态库的概念以致对应的创办与利用办法,小说内容为个体学习笔记,接待指正。

动态库(.so)

扭转动态库的章程如下:

编写翻译object文件时选取-fPIC选项:

gcc -Wall -fPIC -c *.c

那么些选项的目标是让编写翻译器生成地址无关(position independent卡塔尔的代码,那是因为,动态库是在运作时期链接的,变量和函数的偏移量是刚开始阶段不理解的,须求链接未来遵照offset进行地址重定向。

使用-shared链接

gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0 *.o

-shared筛选是让动态库得以在运维时期被动态链接;-Wl,options是安装传递给ld(链接器)的参数,在上面的事例中,当链接器在链接.o时会施行ld -soname ibctest.so.1

开创软链

上边的授命将最后输出几个动态库libctest.so.1.0,而鉴于习于旧贯,会创立四个软链:

mv libctest.so.1.0 /opt/lib
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so

libctest.so用于在编写翻译期间利用-lctest让编写翻译器找到动态库,而libctest.so.1用以在运作时期链接

gcc -Wall -I/path/to/include-files -L/path/to/libraries prog.c -lctest -o prog

1 对比

类型 特点
静态库 在编译时被链接到程序中,作为可执行程序的一部分。在程序运行时不再依赖静态库,占用内存大
动态库 在可执行程序运行时载入内存。动态库已经在内存中不需要再次载入

翻看信赖

使用ldd命令来查阅程序对动态库的凭仗。举例:

ldd prog

libctest.so.1 => /opt/lib/libctest.so.1 (0x00002aaaaaaac000)
libc.so.6 => /lib64/tls/libc.so.6 (0x0000003aa4e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003aa4c00000)

2 静态库

obj文件

obj文件的格式和构成可能是系统差距性的一大要现,比方windows下的PElinux和一些unix下的elfmacosmach-oaix下的xcoff

查阅obj文件的符号表音信,能够经过nm objdump readelf等方法。

2.1 概念

静态库指将全数相关的靶子文件打包成为叁个单独的文书,即静态库文件

静态库以.a末尾,链接器会将前后相继中选拔到的函数的代码从库文件中拷贝到程序中。

由于各类使用静态库的应用程序都亟需拷贝全数函数的代码,所以静态链接的文本会相比

在Unix系统中,静态库以一种叫做存档(archive)的异样文件格式存放在磁盘中。

存档文件是一组连接起来的可重定位指标文件的聚众,有一个头顶用来说述每一个成员目的文件的大大小小和职责。

运作时期查找动态库

运作时期,系统需求精晓到何地去找寻动态库,那是透过/etc/ld.so.conf配置的。ldconfig用于配置运维时动态库查找路线,实际是更新/etc/ld.so.cache。其它一些遭逢变量也足以影响查找:(Linux/Solaris: LD_LIBRARY_PATH, SGI: LD_LIBRARYN32_PATH, AIX:LIBPATH, Mac OS X: DYLD_LIBRARY_PATH, HP-UX: SHLIB_PATH)

2.2 静态库的创立和接受

动态加载和卸载的库

内需应用程序希望规划成插件化的结构,这就需求能够动态加载和卸载库的机制。与动态链接差别的是,动态加载的情致是,编写翻译时期能够对动态库的留存目不识丁,而是在运作期间通过客商程序尝试加载进来的。

通过dlfcn.h中的dlopendlsymdlclose等函数完毕此种功用。

另外,使用到dlfcn建制的可施行文件须要运用-rdynamic筛选,它将指令连接器把富有符号(而不只只是程序已利用到的表面符号,但不包蕴静态符号,比方被static修饰的函数)都增多到动态符号表(即.dynsym表)里。

2.2.1 情况准备

制造根文件夹staticDemo:

[root@VM_120_243_centos ~]# mkdir staticDemo

创制子文件夹include,用于存放全部头文件:

[root@VM_120_243_centos ~]# cd staticDemo/
[root@VM_120_243_centos staticDemo]# mkdir include

进入include文件夹,编写myLib.h文件,申明printInfo()函数:

[root@VM_120_243_centos staticDemo]# cd include/
[root@VM_120_243_centos include]# vim myLib.h
[root@VM_120_243_centos include]# cat myLib.h 
void printInfo();

进去上层目录,成立lib文本夹,用于贮存全数库文件,再个中编写print.c文件,使用了myLib.h中的printInfo()函数:

[root@VM_120_243_centos include]# cd ..
[root@VM_120_243_centos staticDemo]# mkdir lib
[root@VM_120_243_centos staticDemo]# cd lib/
[root@VM_120_243_centos lib]# vim print.c
[root@VM_120_243_centos lib]# cat print.c 
#include <stdio.h>
#include "myLib.h"

void printInfo()
{
    printf("print from print.c file...n");
}

进去上层目录,编写main.c文件,用于测量试验:

[root@VM_120_243_centos lib]# cd ..
[root@VM_120_243_centos staticDemo]# vim main.c
[root@VM_120_243_centos staticDemo]# cat main.c 
#include <stdio.h>
#include "myLib.h"

int main(void)
{
    printf("print from main.c file...n");
    printInfo();
    return 0;
}

筹算干活到此产生,整个目录布局如下:

[root@VM_120_243_centos staticDemo]# tree
.
├── include
│   └── myLib.h
├── lib
│   └── print.c
└── main.c

2 directories, 3 files

本文由澳门威尼斯人平台发布于服务器&运维,转载请注明出处:Linux之静态库与动态库20160706

关键词: