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

一、GNU gcc的编译工具用法

我们先来写一个简单的C程序:hello.c

C代码

  1. 01 #include <stdio.h>
    02  
    03 void print_hello() {
    04   printf("Hello World\n");
    05 }
    06  
    07 int main(int argc, char argv[]) {
    08   print_hello();
    09   return 0;
    10 }

定义了一个print_hello函数,调用main函数打印Hello World。
如何编译它呢? 

C代码

1 gcc -o hello -O2 hello.c

-o参数指定生成的可执行程序的文件名, -O2是优化级别。该命令会编译生成hello可执行程序,看看这个文件:ls -l hello

C代码

1 -rwxr-xr-x  1 robbin users 11939 2008-11-02 13:48 hello

有11KB大小。
看看他链接了哪些系统动态链接库,用ldd命令:

C代码

  1. 1 ldd hello

输出信息为:

C代码

1 libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9566d000)
2 /lib64/ld-linux-x86-64.so.2 (0x0000002a95556000)

libc是C语言标准函数库,ld是动态链接器。
接着我们看看hello这个程序里面有哪些符号,用nm命令:

C代码

1 nm hello

输出:

C代码

1 00000000005008f8 A __bss_start
2 000000000040043c t call_gmon_start
3 ......
4 00000000004004f0 T main
5 0000000000500658 d p.0
6 00000000004004e0 T print_hello
7                  U puts@@GLIBC_2.2.5
8 0000000000400410 T _start

中间省略了一些,不过我们还是可以在符号表里面找到函数定义。
hello有11KB,体积偏大,去处符号表可以给它瘦身,我们用strip命令:

C代码

1 strip hello

然后再ls -l hello,输出为:

C代码

1 -rwxr-xr-x  1 webuser users 4464 2008-11-02 13:56 hello

只有4.4KB了,瘦身效果明显! 不过这次符号表再也看不到了,nm hello,输出为:nm: hello: no symbols。
最后如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令:

C代码

1 strings hello

输出信息为:

C代码

1 /lib64/ld-linux-x86-64.so.2
2 SuSE
3 libc.so.6
4 puts
5 __libc_start_main
6 __gmon_start__
7 GLIBC_2.2.5
8 t fff
9 Hello World

友情提醒一下,如果你用Java写一个HelloWorld.java,编译以后你也可以用strings窥探一番。

二、动态共享库怎么使用

这次我们把hello.c拆开成为两个文件:hello.c和main.c。hello.c的代码是:

C代码

1 #include <stdio.h>
2  
3 void print_hello() {
4   printf("Hello World\n");
5 }

而main.c的代码是:

C代码

1 int main(int argc, char argv[]) {
2   print_hello();
3   return 0;
4 }

hello.c是我们的动态共享库,在hello.c里面我们声明和实现了各种公用的函数,最后main.c可以去调用这些公用函数。首先我们要把hello.c编译成为动态共享库:

C代码

1 gcc -o libhello.so -O2 -fPIC -shared hello.c

-fPIC参数声明链接库的代码段是可以共享的,-shared参数声明编译为共享库。请注意这次我们编译的共享库的名字叫做libhello.so,这也是Linux共享库的一个命名的惯例了:后缀使用so,而名称使用libxxxx格式。
然后编译main.c的时候,我们需要更多的参数让gcc知道如何寻找共享库:

C代码

1 gcc -o main -O2 -L. -lhello main.c

-L参数指定到哪个附加路径下面去寻找共享库,现在我们指定在当前目录下面寻找;
-l参数指定链接到哪个共享库上面,我们传的参数hello,那么gcc就会自动链接到libhello.so这个共享库上面(注意我们上面说的libXXXX.so命名规则);
-I参数指定到哪个附加路径下面去寻找h文件,这个我们没有使用。
最后我们成功编译好了main,执行一下,报错:

引用

1 ./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory

找不到libhello.so这个共享库,怎么回事?这是因为libhello.so并不在操作系统默认的共享库的路径下面,我们可以临时指定一下链接路径:

C代码

1 export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

这样就成功了。我们用ldd main看一下:

C代码

1 libhello.so => ./libhello.so (0x0000002a9566d000)
2 libc.so.6 => /lib64/tls/libc.so.6 (0x0000002a9576e000)
3 /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这个配置文件里面。这个文件的内容格式大致如下:

C代码

1 /usr/X11R6/lib64
2 /usr/X11R6/lib
3 /usr/local/lib
4 /lib64
5 /lib
6 /usr/lib64
7 /usr/lib
8 /usr/local/lib64
9 /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里面抽取文本信息来检查一下:

C代码

1 strings /etc/ld.so.cache | grep ImageMagick

输出结果为:

C代码

1 /usr/local/ImageMagick/lib/libWand.so.10
2 /usr/local/ImageMagick/lib/libWand.so
3 /usr/local/ImageMagick/lib/libMagick.so.10
4 /usr/local/ImageMagick/lib/libMagick.so
5 /usr/local/ImageMagick/lib/libMagick++.so.10
6 /usr/local/ImageMagick/lib/libMagick++.so

已经成功了!

3、应用程序独享的动态共享库

有很多共享库只被特定的应用程序使用,那么就没有必要加入系统库路径,以免应用程序的共享库之间发生版本冲突。因此Linux还可以通过设置环境变量LD_LIBRARY_PATH来临时指定应用程序的共享库搜索路径,就像我们上面举的那个例子一样,我们可以在应用程序的启动脚本里面预先设置 LD_LIBRARY_PATH,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。

GNU gcc的编译工具用法(转)相关推荐

  1. Linux 命令之 make -- GNU的工程化编译工具

    文章目录 一.命令介绍 二.常用选项 三.命令示例 (一)指定命令 make 的工作目录 一.命令介绍 make 命令是 GNU 的工程化编译工具,用于编译众多相互关联的源代码文件,还可以编辑内核或模 ...

  2. Linux 之八 完整嵌入式 Linux 环境、(交叉)编译工具链、CPU 体系架构、嵌入式系统构建工具

      最近,工作重心要从裸机开发转移到嵌入式 Linux 系统开发,由于之前对嵌入式 Linux 环境并不是很了解,因此,第一步就是需要了解如何搭建一个完整的嵌入式 Linux 环境.现在将学习心得记录 ...

  3. Linux 之八 完整嵌入式 Linux 环境及构建工具、(交叉)编译工具链、CPU 体系架构

      最近,工作重心要从裸机开发转移到嵌入式 Linux 系统开发,由于之前对嵌入式 Linux 环境并不是很了解,因此,第一步就是需要了解如何搭建一个完整的嵌入式 Linux 环境.现在将学习心得记录 ...

  4. makefile:带你了解一种常用于GNU gcc编译的工具语言

    摘要:该文章主要介绍makefile,一种常用语GNU gcc编译的工具语言,同时LiteOS也是利用该文件对工程项目进行make构建生成执行文件的. LiteOS源码中使用makefile进行文件的 ...

  5. gcc mips64编译后无法运行在octeon上运行_编译工具链

    软件的编译过程由一系列的步骤完成,每一个步骤都有一个对应的工具.这些工具紧密地工作在一起,前一个工具的输出是后一个工具的输入,像一根链条一样,我们称这些工具为工具链. Linux系统上,通常只需要使用 ...

  6. Linux中GCC编译工具集中个软件的用途、gcc的简单编译以及ELF文件格式

    文章目录 一.gcc编译工具集中各软件的用途 1.1 GCC 1.2 Binutils 1.3 C运行库 二.简单编译 2.1 代码编译过程 2.2 多个程序文件的编译 2.3 检错 2.4 库文件连 ...

  7. Linux 环境编程 day01 Linux系统介绍、GNU编译工具、静态/共享库、环境变量表

    Linux 环境编程 day01 Linux系统介绍.GNU编译工具.静态/动态库.环境变量表 学习Linux环境编程的原因 UNIX系统介绍 Linux系统介绍 GNU工程 POSIX标准 GNU通 ...

  8. GCC编译工具集和nasm编译器

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一.gcc编译工具集 1.1gcc工具有哪些 1.2gcc编译过程 1.2.1.这里我们是使用一个hello.c文件进行演 ...

  9. 反编译工具jad简单用法

    反编译工具jad简单用法 下载地址: [url]http://58.251.57.206/down1?cid=B99584EFA6154A13E5C0B273C3876BD4CC8CE672& ...

最新文章

  1. Scrum Master的职业发展路线
  2. 机器人十大前沿热点领域(2012-2022年)
  3. python中怎么比较两个列表-python中比较两个列表的实例方法
  4. 【C language】C语言二分法查找
  5. 【Arduino】按键按下执行不同模式程序
  6. JZOJ 5660. 【HNOI2018D2T3】道路
  7. 使用pos标记寻找三词短语
  8. scala 函数中嵌套函数_如何在Scala中将函数转换为部分函数?
  9. 直播+抽奖丨eygle等4位大咖讲述DBA职业发展必备软实力
  10. python远程控制终端数据_python 网络远程控制
  11. Java JSP JSTL
  12. 一位老司机开车20年后得到的26条教训
  13. 小程序按钮调用扫一扫_他在一个小程序“按钮”上动了个手脚,生意大火,赢得美人归!...
  14. torchtext用法
  15. 流畅的 Python
  16. 【githubgirl】如何通过实现一个简单的编译器(TinyC),并借助实例来描述基本的编译原理及过程
  17. python连接Oracle数据库报错Cannot locate a 64-bit Oracle Client library问题
  18. ueditor编辑器的坑(视频空白/保存无数据/无法删除/不能插入百度动态地图/有序列表显示问题)
  19. win10找不到wifi网络_笔记本电脑搜索不到自己家wifi怎么回事?无线网络信号的解决方法...
  20. linux双击执行sh脚本

热门文章

  1. item-设置可见性
  2. C#环境下的钩子详解
  3. SQLServer锁升级
  4. sql2005备份还原详解
  5. [ASP,VB] - 利用ASP调用API COM接口实现开关机
  6. (转)Shell中获取字符串长度的七种方法
  7. redis 笔记06 发布与订阅、事务、慢查询日志、监视器
  8. Devexpress VCL Build v2014 vol 14.1.4 发布
  9. Navigation Drawer介绍
  10. C语言宏定义##连接符和#符的使用及其它宏定义注意事项