有关Linux的.a、.so和.o文件(转)【原文章有些错误,自己已更改】
gcc 生成 .a静态库和 .so动态库
我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两
种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态
库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运
行时还需要动态库存在。本文主要通过举例来说明在Linux中如何创建静态库和动态库,以
及使用它们。
在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。
第1步:编辑得到举例的程序--hello.h、hello.c和main.c;
hello.c(见程序2)是函数库的源程序,其中包含公用函数hello,该函数将在屏幕上输出"
Hello XXX!"。hello.h(见程序1)为该函数库的头文件。main.c(见程序3)为测试库文件的
主程序,在主程序中调用了公用函数hello。
程序1: hello.h
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO_H
程序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;
}
第2步:将hello.c编译成.o文件;
无论静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过g
cc先编译成.o文件。
在系统提示符下键入以下命令得到hello.o文件。
# gcc -c hello.c
#
我们运行ls命令看看是否生存了hello.o文件。
# ls
hello.c hello.h hello.o main.c
#
在ls命令结果中,我们看到了hello.o文件,本步操作完成。
下面我们先来看看如何创建静态库,以及使用它。
第3步:由.o文件创建静态库;
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将
创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,
需要注意这点。创建静态库用ar命令。
在系统提示符下键入以下命令将创建静态库文件libmyhello.a。
# ar -crv libmyhello.a hello.o
#
我们同样运行ls命令查看结果:
# ls
hello.c hello.h hello.o libmyhello.a main.c
#
ls命令结果中有libmyhello.a。
第4步:在程序中使用静态库;
静态库制作完了,如何使用它内部的函数呢?只需要在使用到这些公用函数的源程序中包
含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从
静态库中将公用函数连接到目标文件中。注意,gcc会在静态库名前加上前缀lib,然后追
加扩展名.a得到的静态库文件名来查找静态库文件。
在程序3:main.c中,我们包含了静态库的头文件hello.h,然后在主程序main中直接调用公
用函数hello。下面先生成目标程序hello,然后运行hello程序看看结果如何。
法一 # gcc -o hello main.c -L. –lmyhello,自定义的库时,main.c还可放在-L.和 –lmyhello之间,但是不能放在它俩之后,否则会提示myhello没定义,但是是系统的库时,如g++ -o main(-L/usr/lib) -lpthread main.cpp就不出错。
法二 #gcc main.c libmyhello.a -o hello
法三:先生成main.o:gcc -c main.c ,再生成可执行文件:gcc -o hello main.o libmyhello.a,动态库连接时也可以这样做。
# ./hello
Hello everyone!
#
我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。
# rm libmyhello.a
rm: remove regular file `libmyhello.a'? y
# ./hello
Hello everyone!
#
程序照常运行,静态库中的公用函数已经连接到目标文件中了。
我们继续看看如何在Linux中创建动态库。我们还是从.o文件开始。
第5步:创建动态库文件;
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其
文件扩展名为.so。例如:我们将创建的动态库名为myhello,则动态库文件名就是libmyh
ello.so。用gcc来创建动态库。
在系统提示符下键入以下命令得到动态库文件libmyhello.so。
# gcc -shared -fPIC -o libmyhello.so hello.c
#
我们照样使用ls命令看看动态库文件是否生成。
# ls
hello.c hello.h hello.o libmyhello.so main.c
#
第6步:在程序中使用动态库;
在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含
这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们
先运行gcc命令生成目标文件,再运行它看看结果。
# gcc -o hello main.c -L. -lmyhello
(或 #gcc main.c libmyhello.so -o hello 不会出错(没有libmyhello.so的话,会出错),但是接下来./hello 会提示出错,因为虽然连接时用的是当前目录的动态库,但是运行时,是到/usr/lib中找库文件的,将文件libmyhello.so复制到目录/usr/lib中就OK了)
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory
#
哦!出错了。快看看错误提示,原来是找不到动态库文件libmyhello.so。程序在运行时,
会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提
示类似上述错误而终止程序运行。我们将文件libmyhello.so复制到目录/usr/lib中,再试
试。
# mv libmyhello.so /usr/lib
# ./hello
Hello everyone!
#
成功了。这也进一步说明了动态库在程序运行时是需要的。
我们回过头看看,发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,
那当静态库和动态库同名时,gcc命令会使用哪个库文件呢?抱着对问题必究到底的心情,
来试试看。
先删除除.c和.h外的所有文件,恢复成我们刚刚编辑完举例程序状态。
# rm -f hello hello.o /usr/lib/libmyhello.so
# ls
hello.c hello.h main.c
#
在来创建静态库文件libmyhello.a和动态库文件libmyhello.so。
# gcc -c hello.c
# ar -cr libmyhello.a hello.o (或-cvr )
# gcc -shared -fPCI -o libmyhello.so hello.o
# ls
hello.c hello.h hello.o libmyhello.a libmyhello.so main.c
#
通过上述最后一条ls命令,可以发现静态库文件libmyhello.a和动态库文件libmyhello.s
o都已经生成,并都在当前目录中。然后,我们运行gcc命令来使用函数库myhello生成目标
文件hello,并运行程序 hello。
# gcc -o hello main.c -L. –lmyhello (动态库和静态库同时存在时,优先使用动态库, 当然,直接#gcc main.c libmyhello.a -o hello的话,就是指定为静态库了)
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory
#
从程序hello运行的结果中很容易知道,当静态库和动态库同名时,gcc命令将优先使用动态库,默认去连/usr/lib和/lib等目录中的动态库,将文件libmyhello.so复制到目录/usr/lib中即可。
Note:
编译参数解析
最主要的是GCC命令行的一个选项:
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
-fPIC 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L. 表示要连接的库在当前目录中;(多个库:在编译命令行中,将使用的静态库文件放在源文件后面就可以了。比如:gcc -L/usr/lib myprop.c libtest.a libX11.a libpthread.a -o myprop
其中-L/usr/lib指定库文件的查找路径。编译器默认在当前目录下先查找指定的库文件,如前面的“法二 #gccmain.c libmyhello.a-o hello”)
-lmyhello 编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so或.a来确定库的名称libmyhello.so或libmyhello.a。
LD_LIBRARY_PATH这个环境变量指示动态连接器可以装载动态库的路径。
当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。
调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。
另:
从上述可知,如何找到生成的动态库有3种方式:
(1)把库拷贝到/usr/lib和/lib目录下。
(2)在LD_LIBRARY_PATH环境变量中加上库所在路径。
例如动态库libhello.so在/home/example/lib目录下:
$export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/example/lib
(3) 修改/etc/ld.so.conf文件,把库所在的路径加到文件末尾,并执行ldconfig刷新。这样,加入的目录下的所有库文件都可见。
附:像下面这样指定路径去连接系统的静态库,会报错说要连接的库找不到:
g++ -o main main.cpp -L/usr/lib libpthread.a
必须这样g++ -o main main.cpp -L/usr/lib -lpthread才正确 。
自定义的库考到/usr/lib 下时,
g++ -o main main.cpp -L/usr/lib libpthread.a libthread.a libclass.a会出错,但是这样g++ -o main main.cpp -L/usr/lib -lpthread -lthread -lclass就正确了。
有关Linux的.a、.so和.o文件(转)【原文章有些错误,自己已更改】的更多相关文章
- IIS7出现“HTTP 错误 404.17 - Not Found 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理。”错误-Windows-
Errore HTTP 404.2 - Not Found" IIS 7.5 请求的内容似乎是脚本,因而将无法由静态文件处理程序来处理 如果你用了安全狗,可能只看到404错误,请打开狗,资源 ...
- linux下shell脚本执行jar文件
最近在搞一个shell脚本启动jar文件个关闭jar文件的东东.搞得我都蛋疼了.今天晚上终于弄好了 话说,小弟的linux只是刚入门,经过各方查资料终于搞定了.话不多说,下面开始上小弟写的shell脚 ...
- linux下cp覆盖原so文件时引起的段错误原因确定
原创作品,转载请注明出处http://www.cnblogs.com/leo0000/p/5694416.html 最近因为一个很有意思的段错误学习了一些新的东西. 当时现象是这样的,程序正在运行,系 ...
- Linux学习笔记(6)-文件I/O
持续一个礼拜的出差终于结束了,本次出差真是收益良多,不仅品尝了正宗的大闸蟹,同时也是第一次体验了产品的现场实施流程. 明天开始继续学习Linux! ----------------------分割线- ...
- Linux 利用 locate 和 find 查找文件
Linux 利用 locate 和 find 查找文件 命令 locate 用于快速查找文件.文件夹.此命令并没有在磁盘上查找所有文件,而是在预先建立的数据库里进行搜索.可以使用 updatedb 命 ...
- 诠释Linux中『一切都是文件』概念和相应的文件类型
导读 在 Unix 和它衍生的比如 Linux 系统中,一切都可以看做文件.虽然它仅仅只是一个泛泛的概念,但这是事实.如果有不是文件的,那它一定是正运行的进程. 要理解这点,可以举个例子,您的根目录( ...
- 【Linux程序设计】之Linux库函数的使用,多文件程序开发,静态与共享函数
这个系列的博客贴的都是我大二的时候学习Linux系统高级编程时的一些实验程序,都挺简单的.贴出来纯粹是聊胜于无. 实验题目:Linux基础程序设计综合实验 实验目的:熟悉并掌握Linux库函数的使用, ...
- ubuntu Linux 测试PHP却提示下载文件的解决办法
ubuntu Linux 测试PHP却提示下载文件的解决办法 一般这种情况都是在刚刚开始配置环境时出现的, 输入 sudo a2enmod php5 看提示如果出现“$ This module ...
- Linux命令(1)-创建文件
版本:centos7 1.可以使用cat创建一个新的文件 命令:cat>>filename 使用cat创建文件时,以系统默认的文件属性作为新文件的属性,并接受键盘输入作为文件的内容.输入结 ...
随机推荐
- 美图美妆由Try Try接手运营
美图又把一个拖累营收的业务转让出去了. 美图的电商业务——美图美妆应用在向用户发布终止运营的公告后,宣布把业务交给了寺库旗下公司 Try Try 运营.Try Try 接手了美图美妆的所有管理运营权, ...
- python中字典和json的区别
python中,json和dict非常类似,都是key-value的形式,而且json.dict也可以非常方便的通过dumps.loads互转 定义 python中,json和dict非常类似,都是k ...
- Jquery_如何扩展方法
jQuery 别名 $ 一. 类级别扩展方法(比如$.ajax(...)) 1> 单个全局方法 $.testExtend = function (){ console.log("单个 ...
- HDU4296-ChengduOnling-贪心
某人要搬砖盖一栋楼,有m块砖,每块有两个值w和s,表示重量和强度.楼盖好后每块砖有一个危险值,表示为此砖之上的砖的重量和减此砖的强度,即Σ0(j-1)w - sj. 整体危险值是每块砖危险值的最大值. ...
- 自学Zabbix9.1 Network Discovery 网络发现原理
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix9.1 Network Discovery 网络发现原理 1. 网络发现简介 网络 ...
- 洛谷 P3313 [SDOI2014]旅行 解题报告
P3313 [SDOI2014]旅行 题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教 ...
- 2018 省选 D1T2 IIIDX
题目大意: 给出k.n个数选择一种字典序最大的排列,使得对于任意的i,di>=d[i/k](下取整 下同) 分析: 很容易想到的是建树,将i的父亲设为[i/k],之后建有向边. 60分贪心: 将 ...
- Vector 是线程安全的,是不是在多线程下操作Vector就可以不用加Synchronized
如标题一样,如果之前让我回答,我会说,是的,在多线程的环境下操作Vector,不需要加Synchronized. 但是我今天无意间看到一篇文章,我才发现我之前的想法是错误的,这篇文章的地址: http ...
- ASP:当 request.cookies 发生 Microsoft VBScript 运行时错误 (0x800A000D) 类型不匹配: '[string:
昨天当一个客户告诉我,登录后看不到图片的时候,我还不相信,因为我的浏览器测试发现一切正常. 通过QQ远程协助后,我才发现服务器端真的报错: Microsoft VBScript 运行时错误 (0x80 ...
- plink, vcftool计算等位基因频率(allele frequency,vcf)
计算等位基因频率有两种方式,第一种用vcftool计算: /path/to/vcftools --vcf file.vcf --freq --chr 1 --out filefreq 很简单的一个命令 ...