`
robbin
  • 浏览: 4821803 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
377a9ecd-1ea1-34ac-9530-9daa53bb2a7b
robbin谈管理
浏览量:137080
社区版块
存档分类
最新评论

Linux平台gcc和动态共享库的基础知识

    博客分类:
  • Tech
阅读更多
对大多数不从事Linux平台C语言开发的人来说,GNU gcc的一套工具和Linux平台的共享库的使用还是十分陌生的,其实我也不太熟悉,姑且写点基础知识,权当做备忘吧。

一、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是关闭的,要显式打开。
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了

相关推荐

    Linux平台gcc和动态共享库的基础知识dd

    一、Linux 平台 gcc 和动态共享库的基础知识 1)GNU gcc 的编译工具用法 2)动态共享库怎么使用 3)关于 Linux 的动态共享库的设置 二、GCC——C 程序是如何编译成的 三、GCC 使用详解

    Linux平台gcc和动态共享库的基础知识 收集

    本篇文章将深入探讨Linux环境下GCC的使用以及动态共享库的基础知识。 首先,GCC的工作流程可以分为预处理、编译、汇编和链接四个阶段。预处理阶段处理宏定义、条件编译指令和包含文件;编译阶段将源代码转换为汇编...

    linux静态库及动态库创建及使用

    ### Linux静态库及动态库创建及使用 #### 一、基本概念 ##### 1.1 什么是库 在计算机编程领域,**库**(Library)是一系列预编译的代码集合,这些代码通常...这些基础知识对于理解和使用Linux系统中的库非常有帮助。

    Linux下使用动态库小结

    本文旨在介绍Linux下动态库的基础知识及其使用方法。 **1.1 静态库与动态库的区别** - **静态库**: 在编译链接阶段,静态库中的代码会被复制到可执行文件中,成为可执行文件的一部分。这意味着使用静态库编译的...

    Linux静态库和动态库学习总结

    ### Linux静态库与动态库详解 #### 一、引言 在Linux环境下开发软件时,经常需要使用到库文件来实现复杂的功能。这些库文件可以分为两大类:...在实际开发中,了解这些基础知识对于提高开发效率和软件质量至关重要。

    Linux静态动态链接库的创建和使用.pdf

    ### Linux静态与动态链接库的创建及使用 #### 一、引言 在Linux系统中,库文件是...了解这些基础知识对于开发高质量的Linux应用程序至关重要。通过合理选择静态库或动态库,可以根据具体需求优化程序性能和资源利用。

    Linux系统下C语言编程基础知识介绍.pdf

    ### Linux系统下C语言编程基础知识详解 #### 一、源程序编译 在Linux环境下,进行C语言编程的首要步骤是源程序的编译。这一过程通常借助于GNU的GCC(GNU Compiler Collection)编译器完成。GCC不仅支持C语言,还...

    linux编程基础

    Linux编程基础是一个涵盖广泛的主题,包括使用GCC编译器、GDB调试器、动态库的构建以及Makefile的编写。这些是Linux环境下软件开发的重要工具和技术。以下是对这些知识点的详细解释: 1. **GCC(GNU Compiler ...

    Linux下的C++标准库

    `libstdc++.so.6.0.13`是`libstdc++`的一个具体版本,其中`.so`表示共享对象(Shared Object),在Linux中就是动态链接库。当程序运行时,如果没有找到所需的动态链接库,可以通过手动将库文件复制到系统库路径(如/...

    gcc linux

    【标题】:“gcc Linux”...以上内容涵盖了与“gcc Linux”相关的多个知识点,包括`gcc`的使用、Linux环境配置、虚拟机网络设置以及基础的Linux工具使用。了解和掌握这些内容对Linux系统的日常使用和开发工作至关重要。

    动态库的建立

    在Linux环境下,动态库和静态库是软件开发中的两种常见库类型,它们在程序编译链接阶段扮演着重要角色。本文将深入解析动态库的建立过程,同时对比静态库,以帮助读者更好地理解和应用。 #### 静态库与动态库的区别...

    Linux平台上学C语言 PDF格式

    一、C语言基础知识 1. C语言概述:C语言由Dennis Ritchie于1972年开发,是一种中级语言,结合了高级语言的可读性和低级语言的控制力。它的语法简洁,执行效率高,被广泛用于系统编程、嵌入式开发和软件开发等领域。 ...

    【重点】静态库动态库的制作和使用.docx

    接下来,我们详细介绍了链接库的基础知识。链接库文件是实现了特定功能的函数集合,分为静态链接库和动态链接库。静态库(如在Linux下以`.a`结尾的文件)在编译时会将库代码合并到可执行文件中,使得程序独立,但...

    Linux平台上学C语言.rar

    本文将围绕“Linux平台上学C语言”这个主题,详细讲解相关知识点,帮助初学者或有志于深入Linux环境下的C语言编程者。 首先,C语言是一种强大的、高效的编程语言,它的语法简洁明了,对于理解计算机工作原理和操作...

    Linux操作系统基础教程.pdf

    这个基础教程旨在帮助初学者快速入门Linux,通过学习这些基础知识,可以理解Linux系统的运作机制,并能够熟练地在终端进行日常操作。随着对Linux的深入理解,可以进一步探索更高级的主题,如系统管理、网络服务、...

    Linux开发基础ppt课件.ppt

    本节将从Linux函数库开始,详细介绍Linux开发基础的知识点。 一、Linux函数库 Linux函数库是一个文件,包含了一些编译好的代码和数据,这些编译好的代码和数据可以在事后供其他程序使用。函数库可以使整个程序更加...

Global site tag (gtag.js) - Google Analytics