位置: 编程技术 - 正文

Linux下如何用GCC编译动态库(linux gc)

编辑:rootadmin
本文主要解决以下几个问题   1 为什么要使用库?   2 库的分类   3 创建自己的库   或许大家对自己初学 Linux时的情形仍记忆尤新吧。如果没有一个能较好的解决依赖关系的包管理器,在Linux下安装软件将是一件及其痛苦的工作。你装a包时,可能会提示你要先装b包,当你费尽心力找到b包时,可能又会提示你要先安装c包。我就曾被这样的事搞的焦头烂额,至今一提起rpm仍心有余悸,头皮发麻。说是一朝被蛇咬,十年怕井绳怕也不为过。   Linux下之所以有这许多的依赖关系,其中一个开发原则真是功不可没。这个原则就是:尽量不重复做别人已经做过的事。换句话说就是尽量充分利用别人的劳动成果。   这就涉及到如何有效的进行代码复用。   1 为什么要使用库?   关于代码复用的途径,一般有两种。   粘贴复制   这是最没有技术含量的一种方案。如果代码小,则工作量还可以忍受,如果代码很庞大,则此法不可取。即便有人原意这样做,但谁又能保证所有的代码都可得到呢?   而库的出现很好的解决了这个问题。   库,是一种封装机制,简单说把所有的源代码编译成目标代码后打成的包。   那么用户怎么能知道这个库提供什么样的接口呢?难道要用nm等工具逐个扫描?   不用担心,库的开发者早以把一切都做好了。除了包含目标代码的库外,www.Linuxidc.com一般还会提供一系列的头文件,头文件中就包含了库的接口。为了让方便用户,再加上一个使用说明就差不多完美了。   2 库的分类   2.1 库的分类   根据链接时期的不同,库又有静态库和动态库之分。   静态库是在链接阶段被链接的(好像是废话,但事实就是这样),所以生成的可执行文件就不受库的影响了,即使库被删除了,程序依然可以成功运行。   有别于静态库,动态库的链接是在程序执行的时候被链接的。所以,即使程序编译完,库仍须保留在系统上,以供程序运行时调用。(TODO:链接动态库时链接阶段到底做了什么)   2.2 静态库和动态库的比较   链接静态库其实从某种意义上来说也是一种粘贴复制,只不过它操作的对象是目标代码而不是源码而已。因为静态库被链接后库就直接嵌入可执行文件中了,这样就带来了两个问题。   首先就是系统空间被浪费了。这是显而易见的,想象一下,如果多个程序链接了同一个库,则每一个生成的可执行文件就都会有一个库的副本,必然会浪费系统空间。   再者,人非圣贤,即使是精心调试的库,也难免会有错。一旦发现了库中有bug,挽救起来就比较麻烦了。必须一一把链接该库的程序找出来,然后重新编译。   而动态库的出现正弥补了静态库的以上弊端。因为动态库是在程序运行时被链接的,所以磁盘上只须保留一份副本,因此节约了磁盘空间。如果发现了bug或要升级也很简单,只要用新的库把原来的替换掉就行了。   那么,是不是静态库就一无是处了呢?   答曰:非也非也。不是有句话么:存在即是合理。静态库既然没有湮没在滔滔的历史长河中,就必然有它的用武之地。想象一下这样的情况:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。   所谓有得必有失,正因为动态库在程序运行时被链接,故程序的运行速度和链接静态库的版本相比必然会打折扣。然而瑕不掩瑜,动态库的不足相对于它带来的好处在现今硬件下简直是微不足道的,所以链接程序在链接时一般是优先链接动态库的,除非用-static参数指定链接静态库。   2.3 如何判断一个程序有没有链接动态库?   答案是用file实用程序。   file程序是用来判断文件类型的,在file命令下,所有文件都会原形毕露的。   顺便说一个技巧。有时在 windows下用浏览器下载tar.gz或tar.bz2文件,后缀名会变成奇怪的tar.tar,到Linux有些新手就不知怎么解压了。但 Linux下的文件类型并不受文件后缀名的影响,所以我们可以先用命令file xxx.tar.tar看一下文件类型,然后用tar加适当的参数解压。   另外,还可以借助程序ldd实用程序来判断。   ldd是用来打印目标程序(由命令行参数指定)所链接的所有动态库的信息的,如果目标程序没有链接动态库,则打印“not a dynamic executable”,ldd的用法请参考manpage。   3 创建自己的库   3.1 创建动态库   创建文件hello.c,内容如下:   #include   void hello(void)   {   printf("Hello Worldn");   }   用命令gcc -shared hello.c -o libhello.so编译为动态库。可以看到,当前目录下多了一个文件libhello.so。   [leo@leo test]$ file libhello.so   libhello.so: ELF -bit LSB shared object, Intel , version 1 (SYSV), not stripped   看到了吧,文件类型是shared object了。   再编辑一个测试文件test.c,内容如下:   int   main()   {   hello();   return 0;   }   这下可以编译了:)   [leo@leo test]$ gcc test.c   /tmp/ccm7w6Mn.o: In function `main':   test.c:(.text+0x1d): undefined reference to `hello'   collect2: ld returned 1 exit status   链接时gcc找不到hello函数,编译失败:(。原因是hello在我们自己创建的库中,如果gcc能找到那才教见鬼呢!ok,再接再厉。   [leo@leo test]$ gcc test.c -lhello   /usr/lib/gcc/i-pc-Linux-gnu/4.0.0/../../../../i-pc-Linux-gnu/bin/ld: cannot find -lhello   collect2: ld returned 1 exit status   [leo@leo test]$ gcc test.c -lhello -L.   [leo@leo test]$ 第一次编译直接编译,gcc默认会链接标准c库,但符号名hello解析不出来,故连接阶段通不过了。   现在用gcc test.c -lhello -L.已经编译成功了,默认输出为a.out。现在来试着运行一下:   [leo@leo test]$ ./a.out   ./a.out: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory   咦,怎么回事?原来虽然链接时链接器(dynamic linker)找到了动态库libhello.so,但动态加载器(dynamic loader, 一般是/lib/ld-Linux.so.2)却没找到。再来看看ldd的输出:   [leo@leo test]$ ldd a.out   Linux-gate.so.1 => (0xffffe)   libhello.so => not found   libc.so.6 => /lib/libc.so.6 (0x)   /lib/ld-Linux.so.2 (0x)   果然如此,看到没有,libhello.so => not found。   Linux为我们提供了两种解决方法:   1.可以把当前路径加入 /etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。   2.把当前路径加入环境变量LD_LIBRARY_PATH中   当然,如果你觉得不会引起混乱的话,可以直接把该库拷入/lib,/usr/lib/等位置(无可避免,这样做也要有权限),这样链接器和加载器就都可以准确的找到该库了。   我们采用第二种方法:   [leo@leo test]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH   [leo@leo test]$ ldd a.out   Linux-gate.so.1 => (0xffffe)   libhello.so => ./libhello.so (0xf)   libc.so.6 => /lib/libc.so.6 (0x)   /lib/ld-Linux.so.2 (0x)   哈哈,这下ld-Linux.so.2就可以找到libhello.so这个库了。   现在可以直接运行了:   [leo@leo test]$ ./a.out   Hello World   3.2 创建静态库   仍使用刚才的hello.c和test.c。   第一步,生成目标文件。   [leo@leo test]$ gcc -c hello.c   [leo@leo test]$ ls hello.o -l   -rw-r--r-- 1 leo users 5月 6 : hello.o   第二步,把目标文件归档。   [leo@leo test]$ ar r libhello.a hello.o   ar: creating libhello.a   OK,libhello.a就是我们所创建的静态库了,简单吧:)   [leo@leo test]$ file libhello.a   libhello.a: current ar archive   下面一行命令就是教你如何在程序中链接静态库的:   [leo@leo test]$ gcc test.c -lhello -L. -static -o hello.static   我们来用file命令比较一下用动态库和静态库链接的程序的区别:   [leo@leo test]$ gcc test.c -lhello -L. -o hello.dynamic   正如前面所说,链接器默认会链接动态库(这里是libhello.so),所以只要把上个命令中的 -static参数去掉就可以了。   用file实用程序验证一下是否按我们的要求生成了可执行文件:   [leo@leo test]$ file hello.static hello.dynamic   hello.static: ELF -bit LSB executable, Intel , version 1 (SYSV), for GNU/Linux 2.6.6, statically linked, not stripped   hello.dynamic: ELF -bit LSB executable, Intel , version 1 (SYSV), for GNU/Linux 2.6.6, dynamically linked (uses shared libs), not stripped   不妨顺便练习一下ldd的用法:   [leo@leo test]$ ldd hello.static hello.dynamic   hello.static:   not a dynamic executable   hello.dynamic:   Linux-gate.so.1 => (0xffffe)   libhello.so => ./libhello.so (0xf)   libc.so.6 => /lib/libc.so.6 (0x)   /lib/ld-Linux.so.2 (0x)   OK,看来没有问题,那就比较一下大小先:   [leo@leo test]$ ls -l hello.[ds]*   -rwxr-xr-x 1 leo users 5月 6 : hello.dynamic   -rwxr-xr-x 1 leo users 5月 6 : hello.static   看到区别了吧,链接静态库的目标程序和链接动态库的程序比起来简直就是一个庞然大物!   这么小的程序,很难看出执行时间的差别,不过为了完整起见,还是看一下time的输出吧:   [leo@leo test]$ time ./hello.static   Hello World   real 0m0.s   user 0m0.s   sys 0m0.s   [leo@leo test]$ time ./hello.dynamic   Hello World   real 0m0.s   user 0m0.s   sys 0m0.s   如果程序比较大的话,应该效果会很明显的。

推荐整理分享Linux下如何用GCC编译动态库(linux gc),希望有所帮助,仅作参考,欢迎阅读内容。

Linux下如何用GCC编译动态库(linux gc)

文章相关热门搜索词:linux怎么使用gcc,linux如何使用gcc,linux怎么用gcc编译c程序,linux gc,linux如何使用gcc,linux yum gcc,linux怎么用gcc,linux gc,内容如对您有帮助,希望把文章链接给更多的朋友!

linux的简介 linux与windows服务器系统的区别 通过什么是服务器?一文我们了解到,服务器系统主要有linux与windows系统,对于windows系统大家可能都熟悉些,虽然windows服务器系统,如windows、windows

centos 5.5如何配置vnc,开启linux远程桌面教程 Centos下vnc远程桌面连接配置(完全版,Centos5.5亲测)1.查看本机是否有安装vnc(centOS5默认有安装vnc)rpm-qvncvnc-server如果显示结果为:packagevncisnotinstalledvnc-se

Linux fdisk 命令使用详解 一、fdisk的介绍fdisk-PartitiontablemanipulatorforLinux,译成中文的意思是磁盘分区表操作工具;本人译的不太好,也没有看中文文档;其实就是分区工具fdsik能

标签: linux gc

本文链接地址:https://www.jiuchutong.com/biancheng/364123.html 转载请保留说明!

上一篇:gcc 动态编译(gcc编译选项详解)

下一篇:linux的简介 linux与windows服务器系统的区别(linux的含义)

  • 合伙企业所得税怎么征收
  • 车辆购置税和车船税的区别在哪
  • 研发费用加计扣除是什么意思啊
  • 两个公司发工资怎么交个税
  • 分公司可以用总公司的业绩吗
  • 公司名下的车过户到个人名下费用
  • 社保申报后不能缴费
  • 股息红利增值税和企业所得税
  • 免费给客户提供服务怎么做账
  • 季度超了30万年度没超120
  • 国外客户付款方式
  • 汽车租赁的印花税税率
  • 准予抵扣的进项税额计算公式
  • 广告服务怎么做分录
  • 酒店购买毛巾客房领用怎么做会计分录?
  • 营改增后出售以前年度的固定资产怎么申报?
  • 小规模纳税人城镇土地使用税减免政策
  • 残保金退回属于政府补助吗
  • 母子公司之间转让房产
  • 发票验证查询系统官网入口
  • 销售原材料会计分录,款项已收
  • 核定应纳税额的具体程序和方法
  • 腾讯电脑管家中蓝牙在哪
  • 金税盘技术维护费可以抵扣吗
  • 劳务费意思
  • 中秋福利发放现金文案怎么写
  • 挂账多年的往来账怎么处理
  • php连接数据库代码是什么
  • php declare
  • 企业债券利息收入计入什么科目
  • 最贵的节能灯泡品牌
  • 实收资本明细账模板
  • 劳务派遣企业简易征收管理办法
  • 再就业优惠怎么办理
  • 两借两贷属于复合会计分录吗
  • 收到税务局退款怎么做分录
  • 补交之前年度税款怎么调账
  • 企业所得税汇算清缴
  • python怎么求列表里的和
  • 合同价格约定不明法律规定
  • 租赁房产税如何交税
  • 厂区道路不应该使用哪种材料
  • 季度销售额未超过30万元 季度中间
  • 印花税计算公式
  • 开发日志模板
  • 社保减免财务账务处理
  • 异地预交个人所得税
  • 企业开办期间费用需要开发票吗
  • 往来账户余额
  • 科研项目财政拨款怎么算
  • SqlServer 2005/2008数据库被标记为“可疑”的解决办法
  • MySQL数据库性能优化
  • 日常费用报销表格
  • 收据和发票有什么用
  • 银行承兑到期之前怎么办
  • 投资损益科目
  • 应收账款和应付账款属于什么科目
  • 个体工商户是否要交税
  • 企业会计准则规定,企业在对会计要素
  • 销售废旧物资如何入账
  • win7超级账户如何启用
  • win2000安装过程
  • 删除默认操作系统选项
  • 电脑bios怎么设置usb启动
  • 命令行批量重命名
  • win10更新后有线网络无法使用
  • win7系统删除密码
  • cocos2dx-js
  • bootstrap 图表插件
  • dos 批处理
  • 象棋软件编程
  • linux shell脚本命令
  • cd弹出错误怎么回事
  • jquery fadein不起作用
  • Unity3d C# Socket 下载文件 (同步向)
  • unity的text
  • 江苏省发票真伪查询网站
  • 契税完税证明怎么补打
  • 中行网银查询
  • 没有税费种认定信息是什么意思
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设