一、GNU gcc的编译工具用法

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

1. #include <stdio.h>
2.
3. void print_hello() {
4. printf("Hello World/n");
5. }
6.
7. int main(int argc, char argv[]) {
8. print_hello();
9. return 0;
10. }

定义了一个print_hello函数,调用main函数打印Hello World。

如何编译它呢?

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命令:

1. ldd hello

输出信息为:

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

libc是C语言标准函数库,ld是动态链接器。

接着我们看看hello这个程序里面有哪些符号,用nm命令:

1. nm hello

输出:

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命令:

1. strip hello

然后再ls -l hello,输出为:
1. -rwxr-xr-x 1 webuser users 4464 2008-11-02 13:56 hello

只有4.4KB了,瘦身效果明显! 不过这次符号表再也看不到了,nm hello,输出为:nm: hello: no symbols。

最后如果我们想从可执行程序里面提取出来一点什么文本信息的话,还可以用strings命令:

1. strings hello

输出信息为:

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的代码是:

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

而main.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知道如何寻找共享库:

1. 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并不在操作系统默认的共享库的路径下面,我们可以临时指定一下

链接路径:

1. export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

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

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这个配置文件里面。这个文件的内容格式

大致如下:

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里面抽取文本信息来检查一下:

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

输出结果为:

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,指定本应用程序附加的共享库搜索路径,从而让应用程序找到它。

具体如下:

1)新建自己的头文件路径/home/user/workspace/include和库文件路径/home/user/workspace/lib,这两个目录用来存放我自己编写的头文件和库文件;
(2)接下来写个头文件和库文件作测试,在/home/user/workspace/include下新建文件test.h,在/home/user/workspace/lib下新建test.c,test.h中是一些函数原型,test.c是函数的实现;
(3)通过命令gcc -fPIC -shared -o libtest.so test.c在/home/user/workspace/lib生成了一个动态链接库文件libtest.so;
(4)现在把库文件路径添加进.bash_profile文件,添加内容如下:
# my code
C_INCLUDE_PATH=/home/cheney/workspace/include
export C_INCLUDE_PATH
LD_LIBRARY_PATH=/home/cheney/workspace/lib
export LD_LIBRARY_PATH
然后通过source .bash_profile把.bash_profile文件即时更新了

gcc动态链接库基本知识 [转]相关推荐

  1. gcc动态链接库基本知识

    一.GNU gcc的编译工具用法 我们先来写一个简单的C程序:hello.c 1. #include <stdio.h> 2. 3. void print_hello() { 4. pri ...

  2. GCC GDB基础知识总结

    GCC GDB基础知识总结 1GCC部分 (1)查看gcc版本命令:**gcc -v** (2)gcc编译程序过程: (3)编译参数 (4)gcc警告提示: (5)gcc库依赖: (6)gcc代码优化 ...

  3. Unity与 SO 交互 ☀️| .so文件(动态链接库 ) 基础知识科普

  4. Linux gcc 制作动/静态链接库

    gcc 静态链接库 以 math.c为例 gcc -c math.c ar rcs libmath.a math.o ar命令 将多个文件打包成一个备份文件 参数r:用来替换库中已有的目标文件,或加入 ...

  5. Centos6.5升级GCC

    由于CentOS自带的gcc实在是老掉牙了,所以决定升级一下gcc,下面介绍如何进行源码编译,升级gcc. 从GNU网站下载你想要的gcc版本,链接:ftp://ftp.gnu.org/gnu/gcc ...

  6. gcc的ar工具及as汇编编译器入门练习及curses库

    gcc的ar工具及as汇编编译器入门练习及curses库 目标 参考资料 一.ar工具使用 1.编写三个函数main.c/sub1.c/sub2.c 2.将x2x.x2y目标文件用 ar工具生成1个 ...

  7. linux下编译isl,CentOS 6 编译GCC 4.8.1简明流程

    之前讨论了很多关于编译gcc的事情,都源自于当年在CentOS6.2上编译gcc4.7.2的事情,简直苦不堪言. 今天工作需要又要用CentOS了,用于gcc只用了更严格的开源协议GPL v3的问题, ...

  8. 静态链接库,动态链接库【滴水逆向三期48笔记】

    在开发过程中,我们通常会有很多函数,需要多次使用或在不同的程序中使用该函数,也有可能我们会将我们写好的函数给别人使用,但是我们又不想给他源代码,毕竟代码是我们花了很多功夫写出来的,那么我们如何不发给其 ...

  9. 动态链接库的建立与调用

    一:实验目的 (1)理解动态链接库的实现原理. (2)掌握Windows系统动态链接库的建立方法. (3)掌握Windows环境下动态链接库的调用方法. 二:实验准备知识:动态链接库介绍 ​ 动态链接 ...

  10. Gstreamer基础讲解

    Gstreamer讲解 文章目录 Gstreamer讲解 基础 背景 小结 元件(Element) 衬垫(Pads) Gstreamer的面向对象 Gstreamer的多线程 实用工具 Gstream ...

最新文章

  1. SQL Server 插入含有中文字符串出现乱码现象的解决办法
  2. Visual studio 生成事件的使用 、xcopy 实现 dll 复制操作、
  3. Vue+Openlayers显示TileWMS时不显示默认控件放大缩小旋转等组件
  4. 打印SAP ABAP web service call完整的payload
  5. vasp服务器中断,求助VASP能带计算的中断原因
  6. 轻量级动态线程池才是“王道”?
  7. Python制作AI贪吃蛇,细节、思路都写下来了!
  8. http://bsideup.blogspot.com/2015/04/spring-boot-thrift-part3.html
  9. 赛锐信息:ABAP程序优化的一些总结
  10. delphi 用户可以点击格式修改进行模板修改
  11. 下一站,人到三十而立之年有感!
  12. 通过计划任务使FlashFXP在晚上自动下载备份
  13. redis安装----非基于lnmp安装
  14. 一个RSS阅读器的开源 ---- 邀请您加入开发队伍
  15. java中的关键字有哪些_java关键字有哪些?java关键字大全
  16. Wintel机器代码反逆向(C/C++反逆向破解)
  17. 使用Tin快速安装 Apache APISIX(全网最快)
  18. iOS软键盘弹出后视图向上移动
  19. 浅谈工程总承包项目WBS的重要性与创建方法
  20. 日本剑道规则及道场礼节 ——值得学习

热门文章

  1. 大型网站的系统架构(摘)
  2. b树删除节点每次只能删一个吗_【面试索引】BTree、B+Tree、红黑树、B*Tree数据结构...
  3. 浅析 路印协议--Loopring 及整体分析 Relay 源码
  4. shell脚本备份数据库
  5. 【169天】黑马程序员27天视频学习笔记【Day08-上】
  6. log4j.xml的实用例子
  7. 用DISKGEN恢复硬盘数据
  8. elasticsearch设置_search的size
  9. error create beanException
  10. python实现归并算法