- 浏览: 4797860 次
- 性别:
- 来自: 上海
博客专栏
-
robbin谈管理
浏览量:135676
文章分类
最新评论
-
xly1981:
领导者是团队的灵魂。深入一线的过程,包括代码review,能帮 ...
robbin谈管理:改造团队的经验(2) -
jiehuangwei:
像这种总结比较性的ppt文档可以多发啊
Web并发模型粗浅探讨 -
linux1308:
看完学习到了很多东西,感谢推荐!
推荐一篇很好的RoR部署方案性能评测 -
zweite:
直接对搜索的结果进行缓存是不是会更快一点呢
漫谈应用缓存的命中率问题 -
kaogua:
现在已经是ruby2.0了, 不知道这个的效率是怎么样的, 是 ...
Ruby作为服务器端应用已经成熟了
对大多数不从事Linux平台C语言开发的人来说,GNU gcc的一套工具和Linux平台的共享库的使用还是十分陌生的,其实我也不太熟悉,姑且写点基础知识,权当做备忘吧。
一、GNU gcc的编译工具用法
我们先来写一个简单的C程序:hello.c
定义了一个print_hello函数,调用main函数打印Hello World。
如何编译它呢?
-o参数指定生成的可执行程序的文件名, -O2是优化级别。该命令会编译生成hello可执行程序,看看这个文件:ls -l hello
有11KB大小。
看看他链接了哪些系统动态链接库,用ldd命令:
输出信息为:
libc是C语言标准函数库,ld是动态链接器。
接着我们看看hello这个程序里面有哪些符号,用nm命令:
输出:
中间省略了一些,不过我们还是可以在符号表里面找到函数定义。
hello有11KB,体积偏大,去处符号表可以给它瘦身,我们用strip命令:
然后再ls -l hello,输出为:
只有4.4KB了,瘦身效果明显! 不过这次符号表再也看不到了,nm hello,输出为:nm: hello: no symbols。
最后如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令:
输出信息为:
友情提醒一下,如果你用Java写一个HelloWorld.java,编译以后你也可以用strings窥探一番。
二、动态共享库怎么使用
这次我们把hello.c拆开成为两个文件:hello.c和main.c。hello.c的代码是:
而main.c的代码是:
hello.c是我们的动态共享库,在hello.c里面我们声明和实现了各种公用的函数,最后main.c可以去调用这些公用函数。首先我们要把hello.c编译成为动态共享库:
-fPIC参数声明链接库的代码段是可以共享的,-shared参数声明编译为共享库。请注意这次我们编译的共享库的名字叫做libhello.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。
然后编译main.c的时候,我们需要更多的参数让gcc知道如何寻找共享库:
-L参数指定到哪个附加路径下面去寻找共享库,现在我们指定在当前目录下面寻找;
-l参数指定链接到哪个共享库上面,我们传的参数hello,那么gcc就会自动链接到libhello.so这个共享库上面(注意我们上面说的libXXXX.so命名规则);
-I参数指定到哪个附加路径下面去寻找h文件,这个我们没有使用。
最后我们成功编译好了main,执行一下,报错:
找不到libhello.so这个共享库,怎么回事?这是因为libhello.so并不在操作系统默认的共享库的路径下面,我们可以临时指定一下链接路径:
这样就成功了。我们用ldd main看一下:
这次main程序链接到了libhello.so这个共享库上面。
三、关于Linux的动态共享库的设置
可执行程序找不到要链接的动态共享库,这是Linux上面编译和运行程序很容易碰到的问题,通过上面的小例子,我们已经大致了解共享库的一点基本原理,接下来我们要探讨一下怎么设置程序寻找动态共享库的行为。
Linux操作系统上面的动态共享库大致分为三类:
1、操作系统级别的共享库和基础的系统工具库
比方说libc.so, libz.so, libpthread.so等等,这些系统库会被放在/lib和/usr/lib目录下面,如果是64位操作系统,还会有/lib64和/usr/lib64目录。如果操作系统带有图形界面,那么还会有/usr/X11R6/lib目录,如果是64位操作系统,还有/usr/X11R6/lib64目录。此外还可能有其他特定Linux版本的系统库目录。
这些系统库文件的完整和版本的正确,确保了Linux上面各种程序能够正常的运行。
2、应用程序级别的系统共享库
并非操作系统自带,但是可能被很多应用程序所共享的库,一般会被放在/usr/local/lib和/usr/local/lib64这两个目录下面。很多你自行编译安装的程序都会在编译的时候自动把/usr/local/lib加入gcc的-L参数,而在运行的时候自动到/usr/local/lib下面去寻找共享库。
以上两类的动态共享库,应用程序会自动寻找到他们,并不需要你额外的设置和担心。这是为什么呢? 因为以上这些目录默认就被加入到动态链接程序的搜索路径里面了。Linux的系统共享库搜索路径定义在/etc/ld.so.conf这个配置文件里面。这个文件的内容格式大致如下:
假设我们自己编译安装的ImageMagick图形库在/usr/local/ImageMagick目录下面,并且希望其他应用程序都可以使用ImageMagick的动态共享库,那么我们只需要把/usr/local/ImageMagick/lib目录加入/etc/ld.so.conf文件里面,然后执行:ldconfig 命令即可。
ldcofig将搜索以上所有的目录,为共享库建立一个缓存文件/etc/ld.so.cache。为了确认ldconfig已经搜索到ImageMagick的库,我们可以用上面介绍的strings命令从ld.so.cache里面抽取文本信息来检查一下:
输出结果为:
已经成功了!
3、应用程序独享的动态共享库
有很多共享库只被特定的应用程序使用,那么就没有必要加入系统库路径,以免应用程序的共享库之间发生版本冲突。因此Linux还可以通过设置环境变量LD_LIBRARY_PATH来临时指定应用程序的共享库搜索路径,就像我们上面举的那个例子一样,我们可以在应用程序的启动脚本里面预先设置LD_LIBRARY_PATH,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。
友情提示:表乱用strip 不然等你的应用dumpcore的时候就很难gdb了
strip之后还能gdb?不能把
windows 下会生成一个默认的 DllMain 吧?
一、GNU gcc的编译工具用法
我们先来写一个简单的C程序:hello.c
#include <stdio.h> void print_hello() { printf("Hello World\n"); } int main(int argc, char argv[]) { print_hello(); return 0; }
定义了一个print_hello函数,调用main函数打印Hello World。
如何编译它呢?
gcc -o hello -O2 hello.c
-o参数指定生成的可执行程序的文件名, -O2是优化级别。该命令会编译生成hello可执行程序,看看这个文件:ls -l hello
-rwxr-xr-x 1 robbin users 11939 2008-11-02 13:48 hello
有11KB大小。
看看他链接了哪些系统动态链接库,用ldd命令:
ldd hello
输出信息为:
libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9566d000) /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)
libc是C语言标准函数库,ld是动态链接器。
接着我们看看hello这个程序里面有哪些符号,用nm命令:
nm hello
输出:
00000000005008f8 A __bss_start 000000000040043c t call_gmon_start ...... 00000000004004f0 T main 0000000000500658 d p.0 00000000004004e0 T print_hello U puts@@GLIBC_2.2.5 0000000000400410 T _start
中间省略了一些,不过我们还是可以在符号表里面找到函数定义。
hello有11KB,体积偏大,去处符号表可以给它瘦身,我们用strip命令:
strip hello
然后再ls -l hello,输出为:
-rwxr-xr-x 1 webuser users 4464 2008-11-02 13:56 hello
只有4.4KB了,瘦身效果明显! 不过这次符号表再也看不到了,nm hello,输出为:nm: hello: no symbols。
最后如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令:
strings hello
输出信息为:
/lib64/ld-linux-x86-64.so.2 SuSE libc.so.6 puts __libc_start_main __gmon_start__ GLIBC_2.2.5 t fff Hello World
友情提醒一下,如果你用Java写一个HelloWorld.java,编译以后你也可以用strings窥探一番。
二、动态共享库怎么使用
这次我们把hello.c拆开成为两个文件:hello.c和main.c。hello.c的代码是:
#include <stdio.h> void print_hello() { printf("Hello World\n"); }
而main.c的代码是:
int main(int argc, char argv[]) { print_hello(); return 0; }
hello.c是我们的动态共享库,在hello.c里面我们声明和实现了各种公用的函数,最后main.c可以去调用这些公用函数。首先我们要把hello.c编译成为动态共享库:
gcc -o libhello.so -O2 -fPIC -shared hello.c
-fPIC参数声明链接库的代码段是可以共享的,-shared参数声明编译为共享库。请注意这次我们编译的共享库的名字叫做libhello.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。
然后编译main.c的时候,我们需要更多的参数让gcc知道如何寻找共享库:
gcc -o main -O2 -L. -lhello main.c
-L参数指定到哪个附加路径下面去寻找共享库,现在我们指定在当前目录下面寻找;
-l参数指定链接到哪个共享库上面,我们传的参数hello,那么gcc就会自动链接到libhello.so这个共享库上面(注意我们上面说的libXXXX.so命名规则);
-I参数指定到哪个附加路径下面去寻找h文件,这个我们没有使用。
最后我们成功编译好了main,执行一下,报错:
引用
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
找不到libhello.so这个共享库,怎么回事?这是因为libhello.so并不在操作系统默认的共享库的路径下面,我们可以临时指定一下链接路径:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
这样就成功了。我们用ldd main看一下:
libhello.so => ./libhello.so (0x0000002a9566d000) libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9576e000) /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)
这次main程序链接到了libhello.so这个共享库上面。
三、关于Linux的动态共享库的设置
可执行程序找不到要链接的动态共享库,这是Linux上面编译和运行程序很容易碰到的问题,通过上面的小例子,我们已经大致了解共享库的一点基本原理,接下来我们要探讨一下怎么设置程序寻找动态共享库的行为。
Linux操作系统上面的动态共享库大致分为三类:
1、操作系统级别的共享库和基础的系统工具库
比方说libc.so, libz.so, libpthread.so等等,这些系统库会被放在/lib和/usr/lib目录下面,如果是64位操作系统,还会有/lib64和/usr/lib64目录。如果操作系统带有图形界面,那么还会有/usr/X11R6/lib目录,如果是64位操作系统,还有/usr/X11R6/lib64目录。此外还可能有其他特定Linux版本的系统库目录。
这些系统库文件的完整和版本的正确,确保了Linux上面各种程序能够正常的运行。
2、应用程序级别的系统共享库
并非操作系统自带,但是可能被很多应用程序所共享的库,一般会被放在/usr/local/lib和/usr/local/lib64这两个目录下面。很多你自行编译安装的程序都会在编译的时候自动把/usr/local/lib加入gcc的-L参数,而在运行的时候自动到/usr/local/lib下面去寻找共享库。
以上两类的动态共享库,应用程序会自动寻找到他们,并不需要你额外的设置和担心。这是为什么呢? 因为以上这些目录默认就被加入到动态链接程序的搜索路径里面了。Linux的系统共享库搜索路径定义在/etc/ld.so.conf这个配置文件里面。这个文件的内容格式大致如下:
/usr/X11R6/lib64 /usr/X11R6/lib /usr/local/lib /lib64 /lib /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/ImageMagick/lib
假设我们自己编译安装的ImageMagick图形库在/usr/local/ImageMagick目录下面,并且希望其他应用程序都可以使用ImageMagick的动态共享库,那么我们只需要把/usr/local/ImageMagick/lib目录加入/etc/ld.so.conf文件里面,然后执行:ldconfig 命令即可。
ldcofig将搜索以上所有的目录,为共享库建立一个缓存文件/etc/ld.so.cache。为了确认ldconfig已经搜索到ImageMagick的库,我们可以用上面介绍的strings命令从ld.so.cache里面抽取文本信息来检查一下:
strings /etc/ld.so.cache | grep ImageMagick
输出结果为:
/usr/local/ImageMagick/lib/libWand.so.10 /usr/local/ImageMagick/lib/libWand.so /usr/local/ImageMagick/lib/libMagick.so.10 /usr/local/ImageMagick/lib/libMagick.so /usr/local/ImageMagick/lib/libMagick++.so.10 /usr/local/ImageMagick/lib/libMagick++.so
已经成功了!
3、应用程序独享的动态共享库
有很多共享库只被特定的应用程序使用,那么就没有必要加入系统库路径,以免应用程序的共享库之间发生版本冲突。因此Linux还可以通过设置环境变量LD_LIBRARY_PATH来临时指定应用程序的共享库搜索路径,就像我们上面举的那个例子一样,我们可以在应用程序的启动脚本里面预先设置LD_LIBRARY_PATH,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。
评论
8 楼
Thorndike
2009-05-04
GCC在Linux环境,如果脱离Binutils和Glibc,有很多概念都不会理解透彻。
7 楼
zhangyafei_kimi
2009-05-03
seen 写道
友情提示:表乱用strip 不然等你的应用dumpcore的时候就很难gdb了
strip之后还能gdb?不能把
6 楼
night_stalker
2009-04-06
54powerman 写道
正在琢磨用gcc写供vb调用的dll,之前看很多资料说DllMain是必须的,今天搞了一个发现不需要。学习中。。。
收藏这篇。
收藏这篇。
windows 下会生成一个默认的 DllMain 吧?
5 楼
ray_linn
2009-04-06
LD_LIBRARY_PATH --不一定管用的,尤其是在交叉编译GCC的时候。
我都是用-O3 -fomit-frame-pointer,后者在x86是关闭的,要显式打开。
我都是用-O3 -fomit-frame-pointer,后者在x86是关闭的,要显式打开。
4 楼
agurick
2009-04-06
-fPIC 貌似是生成与位置无关代码吧。
3 楼
Omnibus
2008-11-21
初次編寫還是不要用-O2,用-g。萬一crash都可以用gdb debug。直至無問題才轉用-O2。
2 楼
54powerman
2008-11-20
正在琢磨用gcc写供vb调用的dll,之前看很多资料说DllMain是必须的,今天搞了一个发现不需要。学习中。。。
收藏这篇。
收藏这篇。
1 楼
seen
2008-11-02
友情提示:表乱用strip 不然等你的应用dumpcore的时候就很难gdb了
发表评论
-
Web并发模型粗浅探讨
2012-12-10 01:22 16475我带的研发部门使用的编程语言有Java,.net,PHP和Ru ... -
让textmate可以直接修改远程服务器上的文件
2012-11-06 17:20 52591. 在textmate的 Preferences | Ter ... -
晒晒我们的开源项目
2012-09-23 22:17 38078我们的研发团队是一支mini型研发团队,目前共有研发人员13人 ... -
再谈非主流工业语言
2011-03-22 00:15 22979今天看到Fenng同学的发 ... -
我的PHP,Python和Ruby之路
2011-03-21 12:12 72284因为看到一篇讨论PHP,P ... -
互联网网站的反爬虫策略浅析
2009-08-17 01:07 37943因为搜索引擎的流行, ... -
记上海Python社区聚会,谈Python和Ruby
2009-08-10 18:49 247488月9日周日,上海Python ... -
LVM - 很好很强大
2008-11-29 22:19 35787LVM (Logic Volume Management, ... -
贴一段遍历memcached缓存对象的小脚本
2008-10-13 18:07 13656memcached因为性能的缘故,没有提供遍历整个缓存当中对象 ... -
用Google的网站流量分析系统来看全球软件行业的分工趋势
2008-06-25 13:05 10374用Google的网站流量分析 ... -
memcache_engine + memcachedb = 高性能分布式内存数据库
2008-01-22 12:05 33795memcachedb是一个由新浪网 ... -
豆瓣的程序性能真的很惊人,但...
2008-01-17 22:42 34446http://www.dbanotes.net/arch/do ... -
关系模型和对象模型的究竟匹配还是不匹配?
2007-12-27 12:23 12670在过去的很多年,我以 ... -
AJAX与RIA技术之我见
2007-08-02 11:46 43253DHH于6月底曾经发表过一 ... -
从分布式系统的角度看REST
2007-05-23 15:46 51512上周末在杭州网侠大会 ... -
软件行业2006年终回顾以及2007展望(二)展望
2006-12-11 22:02 12998http://www.iteye.com/topic/1778 ... -
Linux reiserfs文件系统即将陨落
2006-10-12 16:29 25111Linux著名的高性能文件系统reiserfs向来是Linux ... -
lighttpd的tunning tips
2006-09-21 00:20 6666http://trac.lighttpd.net/trac/w ... -
动态脚本语言的部署运行方式介绍
2006-09-18 12:42 7738现在这类脚本语言的运行方式基本上有三种: 1、Apache ...
相关推荐
一、Linux 平台 gcc 和动态共享库的基础知识 1)GNU gcc 的编译工具用法 2)动态共享库怎么使用 3)关于 Linux 的动态共享库的设置 二、GCC——C 程序是如何编译成的 三、GCC 使用详解
NULL 博文链接:https://macleo.iteye.com/blog/1542221
Linux平台gcc和动态共享库的基础知识好东西啊啊
知识点2: Shell 基础语法(变量、条件、循环、函数、库) 知识点3: 实例场景(Hello World,猜数字,文件读写,网络侦测) 实战项目: LInux服务器自动监控 第五讲 Linux开发基础 知识点1: 用C语言写一个hello word...
芬兰青年Linus Torvalds和其杰作的传奇故事吸引了无数的电脑爱好者尝试去使用Linux,但他们中的大多数人却被Unix类操作系统传统的枯燥的字符界面、艰涩难懂的操作命令和数量庞大的基本概念以及基础知识所吓退。Linux...
3.lvim工作方式、gcc、gdb用法、动态库和静态库的制作与使用、makefile的编写语法,以及makefile里面的模式匹配、函数、伪目标等知识,以及文件描述符、文件操作(open、close、lseek、stat、dup等语法) 3.进程:进程...
第1篇 Linux网络开发基础 第1章 Linux操作系统概述 2 1.1 Linux发展历史 2 1.1.1 Linux的诞生和发展 2 1.1.2 Linux名称的由来 3 1.2 Linux的发展要素 3 1.2.1 UNIX操作系统 4 1.2.2 Minix操作系统 4 ...
第1章 嵌入式系统基础知识 .1 1.1 嵌入式系统概述 1 1.1.1 嵌入式系统的发展史 2 1.1.2 嵌入式系统的定义与特点 3 1.1.3 嵌入式系统的特点 4 1.2 嵌入式系统的组成 5 1.2.1 嵌入式系统的硬件架构...
第1篇 Linux网络开发基础 第1章 Linux操作系统概述 2 1.1 Linux发展历史 2 1.1.1 Linux的诞生和发展 2 1.1.2 Linux名称的由来 3 1.2 Linux的发展要素 3 1.2.1 UNIX操作系统 4 1.2.2 Minix操作系统 4 ...
《嵌入式Linux应用程序开发标准教程(第2版)》主要分为3个部分,包括Linux基础、搭建嵌入式Linux环境和嵌入式Linux的应用开发。Linux基础部分从Linux基础、基本操作命令讲起,为Linux初学者能快速入门提供了保证。...
1.5 基于ARM和Linux的嵌入式开发平台 习题 第2章 嵌入式交叉编译环境 2.1 嵌入式交叉编译环境简介 2.2 NFS服务 2.3 Samba服务 2.4 Windows和LJnux混合开发模式 2.4.1 VMware虚拟机设置共享 2.4.2 SSH客户端...
本章主要介绍了X Window以及它的配置,并且介绍了在KDE环境下汉化的基本思想,用实例来讲解了Linux汉化的基础知识。第13章:网络的基本概念与设置。本章主要介绍了网络的基本概念,并在讲解这个概念的同时,讲解...
B.3 模块编程的基础知识 222 B.4 模块的编译 224 B.5 模块实用程序modutils 226 附录C Linux内核编译 228 C.1 内核简介 228 C.2 为什么重新编译内核 228 C.3 内核编译模式 229 C.4 新版本内核的获取和更新 229 C.5 ...
讲座的目的就是在同学们中间普及 Linux 基础知识,为今后我们更加接近的了解 Linux 做一 个好的开端。 第一讲 Linux基础 在这一讲中,我们主要是了解一下 Linux 的概况,以及对 Linux 有一个初步的感性认识。 ...
7.1 套接字编程基础知识 181 7.1.1 套接字地址结构 181 7.1.2 用户层和内核层交互过程 183 7.2 TCP网络编程流程 184 7.2.1 TCP网络编程架构 184 7.2.2 创建网络插口函数socket() 186 7.2.3 绑定一个地址...
1.2 Linux的开发模式和运作机制 1.3走进Linux内核 1.3.1 Linux内核的特征 1.3.2 Linux内核版本的变化 1.4 分析Linux内核的意义 1.4.1 开发适合自己的操作系统 1.4.2 开发高水平软件 1.4.3 有助于计算机...
二:Linux基础 Linux操作系统的概念、安装方法,详细了解Linux下的目录结构、基本命令、编辑器VI ,编译器GCC,调试器GDB和 Make 项目管理工具, Shell Makefile脚本编写等知识,嵌入式开发环境的搭建。...