[转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结
来自http://blog.csdn.net/benpaobagzb/article/details/51364005
1 库的分类
根据链接时期的不同,库又有静态库和动态库之分。
静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。
有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。(TODO:链接动态库时链接阶段到底做了什么)
2 静态库和动态库的比较
链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。
首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。
再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。
而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。
那么,是不是静态库就一无是处了呢?
答曰:非也非也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。
所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。
动态链接库
1. 创建动态链接库
- #include<stdio.h>
- void hello()
- {
- printf("hello world/n");
- }
用命令gcc -shared hello.c -o libhello.so编译为动态库。可以看到,当前目录下多了一个文件libhello.so。
2. 再编辑一个测试文件test.c,内容如下
- #include<stdio.h>
- int main()
- {
- printf("call hello()");
- hello();
- }
编译 gcc test.c -lhello
-l 选项告诉编译器要使用hello这个库。奇怪的地方是动态库的名字是libhello.so,这里却使用hello.
但这样还不行,编译会出错。
In function `main':
test.c:(.text+0x1d): undefined reference to `hello'
collect2: ld returned 1 exit status
这是因为hello这个库在我们自己的路径中,编译器找不到。
需要使用-L选项,告诉hello库的位置
gcc test.c -lhello -L. -o test
-L .告诉编译器在当前目录中查找库文件
3. 编译成功后执行./test, 仍然出错
说找不到库
有两种方法:
一、可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。
二、把当前路径加入环境变量LD_LIBRARY_PATH中
当然,如果你觉得不会引起混乱的话,可以直接把该库拷入/lib,/usr/lib/等位置(无可避免,这样做也要有权限),这样链接器和加载器就都可以准确的找到该库了。
我们采用第二种方法:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
这样,再执行就成功了。
下面再讲讲静态链接库
仍使用刚才的hello.c和test.c。
1. gcc -c hello.c 注意这里没有使用-shared选项
2. 把目标文件归档 ar -r libhello.a hello.o
程序 ar 配合参数 -r 创建一个新库 libhello.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。
3. 在程序中链接静态库
gcc test.c -lhello -L. -static -o hello.static
或者 gcc test.c libhello.a -L. -o hello.static
生成的hello.static就不再依赖libhello.a了
file和ldd命令
file程序是用来判断文件类型的,在file命令下,所有文件都会原形毕露的。
顺便说一个技巧。有时在 windows下用浏览器下载tar.gz或tar.bz2文件,后缀名会变成奇怪的tar.tar,到Linux有些新手就不知怎么解压了。但 Linux下的文件类型并不受文件后缀名的影响,所以我们可以先用命令file xxx.tar.tar看一下文件类型,然后用tar加适当的参数解压。
另外,还可以借助程序ldd实用程序来判断。
ldd是用来打印目标程序(由命令行参数指定)所链接的所有动态库的信息的,如果目标程序没有链接动态库,则打印“not a dynamic executable”,ldd的用法请参考manpage。
gcc -lXXX 如何选择静态库还是动态库?
gcc 混合连接动态库和静态库
gcc优先链接动态库,找不到,才链接静态库
g++编译时, 用-labc 选项后, 编译器会自动按照命名规则去搜索 libabc.a 库文件, 但如果我想使用动态链接库链接应如何指定参数?
优先链接共享库。共享库找不到,才链接静态库。 |
可是如果我在 -l 选项后添加共享库, 则链接时报告库文件不存在, 共享库和静态库的命名规则是否一样? 例如我有一个名为 libabc.so, 我应采用什么格式的选项才可以在gcc命令中找到它? |
使用 -l 选项指定静态库和动态库的格式都是一样的,如果库文件名为libabc.so,那么就用 -labc 即可。 链接时会去搜索这个库文件,如果不是系统库,那么你需要告诉链接器它的路径。有两种方法:一种是在参数中用 -L 选项指定库文件搜索路径,可以并列多个。例如:gcc -L /home/ddd -L/home/ddd/lib。 另一种方法是在环境变量中设置LD_LIBRARY_PATH 包含有你的动态库文件所在的路径。这个环境变量用在Sorlarise和Linux,如果你是在HP-UX下,是SHLIB_PATH。 |
共享库文件在/usr/lib/目录下, 但是程序运行的时候还是找不到是为什么?
allen@xps:~/Downloads/N-GenIC$ mpiexec -np 8 ./N-GenIC ics.param
/usr/local/bin/hydra_pmi_proxy: error while loading shared libraries: libcr.so.0: cannot open shared object file: No such file or directory
allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5
已经尝试过ldconfig
和LD_LIBRARY_PATH="/usr/lib" && export LD_LIBRARY_PATH
但是都没用
现在通过google找到了一种解决方法,就是sudo apt-get install libcr-dev
,执行之后程序就正常运行了. 但是查找共享库libcr.so.0
的结果还是
allen@xps:~$ locate libcr.so.0
/usr/lib/libcr.so.0
/usr/lib/libcr.so.0.5.5
不知道这中间发生了什么? 请解释一下
2 个回答
执行locate
前先sudo updatedb
一下。。
你试试把LIBRARY_PATH
也设为那个目录,然后重新make
一下。
export LIBRARY_PATH=/usr/lib:$LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/lib:$LD_LIBRARY_PATH
Linux设置和查看环境变量的方法
1. 显示环境变量HOME
$ echo $HOME
/home/redbooks
2. 设置一个新的环境变量hello
$ export HELLO="Hello!"
$ echo $HELLO
Hello!
3. 使用env命令显示所有的环境变量
$ env
HOSTNAME=redbooks.safe.org
PVM_RSH=/usr/bin/rsh
Shell=/bin/bash
TERM=xterm
HISTSIZE=1000
...
4. 使用set命令显示所有本地定义的Shell变量
$ set
BASH=/bin/bash
BASH_VERSINFO=([0]="2"[1]="05b"[2]="0"[3]="1"[4]="release"[5]="i386-redhat-linux-gnu")
BASH_VERSION='2.05b.0(1)-release'
COLORS=/etc/DIR_COLORS.xterm
COLUMNS=80
DIRSTACK=()
DISPLAY=:0.0
...
5. 使用unset命令来清除环境变量
set可以设置某个环境变量的值。清除环境变量的值用unset命令。如果未指定值,则该变量值将被设为NULL。示例如下:
$ export TEST="Test..." #增加一个环境变量TEST
$ env|grep TEST #此命令有输入,证明环境变量TEST已经存在了
TEST=Test...
$ unset $TEST #删除环境变量TEST
$ env|grep TEST #此命令没有输出,证明环境变量TEST已经存在了
6. 使用readonly命令设置只读变量
如果使用了readonly命令的话,变量就不可以被修改或清除了。示例如下:
$ export TEST="Test..." #增加一个环境变量TEST
$ readonly TEST #将环境变量TEST设为只读
$ unset TEST #会发现此变量不能被删除
-bash: unset: TEST: cannot unset: readonly variable
$ TEST="New" #会发现此也变量不能被修改
-bash: TEST: readonly variable
环境变量的设置位于/etc/profile文件
如果需要增加新的环境变量可以添加下属行
export path=$path:/path1:/path2:/pahtN
-----------------------------------------------------------------------------------------------------------------------
1.Linux的变量种类
按变量的生存周期来划分,Linux变量可分为两类:
1.1 永久的:需要修改配置文件,变量永久生效。
1.2 临时的:使用export命令声明即可,变量在关闭shell时失效。
2.设置变量的三种方法
2.1 在/etc/profile文件中添加变量【对所有用户生效(永久的)】
用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久的”。
例如:编辑/etc/profile文件,添加CLASSPATH变量
# vi /etc/profile
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib
注:修改文件后要想马上生效还要运行# source /etc/profile不然只能在下次重进此用户时生效。
2.2 在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】
用VI在用户目录下的.bash_profile文件中增加变量,改变量仅会对当前用户有效,并且是“永久的”。
例如:编辑guok用户目录(/home/guok)下的.bash_profile
$ vi /home/guok/.bash.profile
添加如下内容:
export CLASSPATH=./JAVA_HOME/lib;$JAVA_HOME/jre/lib
注:修改文件后要想马上生效还要运行$ source /home/guok/.bash_profile不然只能在下次重进此用户时生效。
2.3 直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】
在shell的命令行下直接使用[export 变量名=变量值] 定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。
3.环境变量的查看
3.1 使用echo命令查看单个环境变量。例如:
echo $PATH
3.2 使用env查看所有环境变量。例如:
env
3.3 使用set查看所有本地定义的环境变量。
unset可以删除指定的环境变量。
4.常用的环境变量
PATH 决定了shell将到哪些目录中寻找命令或程序
HOME 当前用户主目录
HISTSIZE 历史记录数
LOGNAME 当前用户的登录名
HOSTNAME 指主机的名称
SHELL 当前用户Shell类型
LANGUGE 语言相关的环境变量,多语言可以修改此环境变量
MAIL 当前用户的邮件存放目录
PS1 基本提示符,对于root用户是#,对于普通用户是$
[转载]GCC 编译使用动态链接库和静态链接库--及先后顺序----及环境变量设置总结的更多相关文章
- GCC 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- GCC 编译使用动态链接库和静态链接库的方法
1 库的分类 依据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的.所以生成的可执行文件就不受库的影响了.即使库被删除了,程序依旧能够成功执行. 有别于静态库,动态库的链接是在程 ...
- 【转】gcc 编译使用动态链接库和静态链接库
1 库的分类 根据链接时期的不同,库又有静态库和动态库之分. 静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行. 有 ...
- 利用GCC编译器生成动态链接库和静态链接库
转载请标明:http://www.cnblogs.com/winifred-tang94/ 1.编译过程 gcc –fPIC –c xxx.c 其中-fPIC是通知gcc编译器产生位置独立的目标代码. ...
- Linux GCC编译使用动态、静态链接库 (转)
原文出处:http://blog.csdn.net/a600423444/article/details/7206015 在windows下动态链接库是以.dll后缀的文件,二在Linux中,是以.s ...
- Linux下动态链接库和静态链接库
第一部分:编译过程 先了解一下linux下C代码的编译过程,C代码的编译,一般分成四个阶段,包括:预编译,编译,汇编和链接,这四个阶段的分工是 预处理过程,负责头文件展开,宏替换,条件编译的选择,删除 ...
- Qt 共享库(动态链接库)和静态链接库的创建及调用
前言: 编译器 Qt Creator, 系统环境 win7 64 位 1.创建共享库: 新建文件或项目->选择 Library 和 c++ 库->选择共享库->下一步(工程名为 sh ...
- GCC编译过程与动态链接库和静态链接库
1. 库的介绍 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可 ...
- VS2010编译Boost 1.57 静态链接库
http://www.cnblogs.com/cuish/p/4175491.html 0.前提 Boost库版本 1.57.0 下载地址 http://www.boost.org/users/his ...
随机推荐
- URL中传递JSON数据
有关于JSON如何在前后之间进行传递,转换成对象等操作,请查看 C#Json数据交互 (这篇文章主要介绍了如何转化Json格式的数据,以及如何使用) 我们在URL中传递数据一般都是 XX.asp ...
- css权值问题
继承是没有权值的,比通配符的的权值0还要低. 选择器是不分上下级的.只管优先级. 第一等:代表内联样式,如: style=””,权值为1000. 第二等:代表ID选择器,如:#content,权值为0 ...
- JavaWeb-拦截器,过滤器,监听器的区别和执行顺序
一:拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,springmvc的aop中的前置通知和后置通知. 二: ...
- git和svn的混用
服务器上的项目是使用svn进行管理的. 本来本地的项目也是通过svn进行管理的,但是后来使用svn的分支功能进行项目的测试/新功能等等时,总是会出现各种各样的问题,遂转投git. 因为git的分支机制 ...
- Webpack4 学习笔记二 CSS模块转换
前言 此内容是个人学习笔记,以便日后翻阅.非教程,如有错误还请指出 webpack 打包css模块 webpack是js模块打包器, 如果在入口文件引入css文件或其它的less.sass等文件,需要 ...
- 深入浅出:了解JavaScript中的call,apply,bind的差别
在 javascript之 this 关键字详解文章中,谈及了如下内容,做一个简单的回顾: 1.this对象的涵义就是指向当前对象中的属性和方法. 2.this指向的可变 ...
- WebSeal单点登陆
WebSeal单点登陆 作为学习整理,部分内容来自网络和官方文档. LDAP LDAP可以看作一种数据库,分为客户端和服务端.服务端是用来存放资源,客户端用来操作资源.它是一种树形存储结构,遍历起来会 ...
- ReplaceChar
好吧,给个char的,替换单个字符.这样会快一些吧,这个是置换,连长度都不用了 bool ReplaceChar(char *str,const char src, const char dst){ ...
- JS中常犯错误
01.==与=== 释: 在JavaScript中使用三等号来判断两个条件是否相等.使用等于关系运算符时,只有两边的条件相等时,结果才为真,否则就是假.注意等于关系运算符并不只是判断 数字类型的数据, ...
- Spring Cloud 入门 Consul-Client服务提供
前面介绍了 Rureka Client服务提供, 只需要改pom.xml部分内容 1.pom.xml <?xml version="1.0" encoding="U ...