在Linux下如何使用GCC编译程序、简单生成 静态库及动态库
最近在编写的一个Apache kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a 静态库编译的,,,而我们这边要求使用动态库方法编译,,,所以简单了解一下,静态库编译的动态库编译的区别,下边是一个网上搜的一篇文章,到最后有一点简单介绍!
【转】在Linux下如何使用GCC编译程序、简单生成 静态库及动态库。
本文适用于Linux下开发初学者。本文初步讲解在Linux下如何使用GCC编译程序、简单生成静态库及动态库。
一、关于安装。一般系统默认是安装好编译器的,并且网络上有大量资料介绍不同发行版本下的安装问题,本文不再描述。
二、C编程中的文件后缀名介绍
.a 静态库(打包文件)
.c 未经过预处理的C源码
.h C头文件
.i 经过预处理的C源码
.o 编译之后产生的目标文件
.s 生成的汇编语言代码
.so 动态库(动态链接库)
解释:*.a是我们在编译过后用ar打包生成的静态库;*.c一般使我们自己编辑的代码,使我们劳动的结晶;*.h一般是 我们手工生成的接口文件,如果愿意,也可在*.c完成后用GCC的选项-aux-info帮我们生成;*.i是经过预处理后的源码,是由GCC在选项-E编译下自动生成 的文件;*.o是编 译后产生的目标文件;*.s是GCC在选项-S编译下生成的汇编语言代码,对于性能要求很高的程序可以先生成汇编语言文件并对汇编做优化,然后用优 化后的汇编生成目标文件并链接;*.so是动态库,通过GCC的-fpic -shared选项生成。
三、hello.c的编译过程
本小节的演示都针对文件 hello.c 进行
- /*
- * hello.c
- */
- #include <stdio.h>
- int main()
- {
- printf("hello, world!/n");
- return 0;
- }
1. 直接生成可执行程序
- $ gcc -o hello hello.c
- $ ./hello
- hello, world!
- 如 下编译方式 结果相同:
- $ gcc hello.c -o hello
- $ ./hello
- hello, world!
- 如 下编译方式 有别于以上编译方 案(具体查找ELF和a.out文件格式差别的网络资料,对于此处结果是无任何区别的):
- $ gcc hello.c
- $ ./a.out
- hello, world!
2. 生成预处理后的文件 hello.i
- $ gcc -E hello.c -o hello.i
- $ ls
- a.out hello hello.c hello.i
- hello.i 就 是新生成的文件
- 如下语句结果相同:
- $ gcc -E -o hello.i hello.c
- 如 果不设定输出文件,则打印到标准终端,此时我们可以用 less 查看:
- $ gcc -E hello.c | less
- # 1 "hello.c"
- # 1 "<built-in>"
- # 1 "<command line>"
- # 1 "hello.c"
- # 1 "/usr/include/stdio.h" 1 3 4
- # 28 "/usr/include/stdio.h" 3 4
- # 1 "/usr/include/features.h" 1 3 4
- # 329 "/usr/include/features.h" 3 4
- ..............................
- 或 者执行:
- $ gcc -E hello.c -o hello.i
- $ vi hello.i
- 1 # 1 "hello.c"
- 2 # 1 "<built-in>"
- 3 # 1 "<command line>"
- 4 # 1 "hello.c"
- 5 # 1 "/usr/include/stdio.h" 1 3 4
- 6 # 28 "/usr/include/stdio.h" 3 4
- 7 # 1 "/usr/include/features.h" 1 3 4
- 8 # 329 "/usr/include/features.h" 3 4
- .......... < 中间部分略> ..................
- 929 # 844 "/usr/include/stdio.h" 3 4
- 930
- 931 # 2 "hello.c" 2
- 932
- 933 int main()
- 934 {
- 935 printf("hello, world!/n");
- 936
- 937 return 0;
- 938 }
- 可 见,将近1000行的代码,我们的只占了最末8行。
3.生成汇编语言文件 hello.s
- $ gcc -S hello.c -o hello.s
- $ ls
- a.out hello hello.c hello.i hello.s
- hello.s 就是新生成的文件
- 如下语句结果相同:
- $ gcc -S -o hello.s hello.c
- 如 下语句结果相同:
- $ gcc -S hello.c
- 也 可以采用前一步骤产生的中间文件生成汇编文件:
- $ gcc -S hello.i -o hello.s
- $ gcc -S -o hello.s hello.i
- $ gcc -S hello.i
- 生 成的汇编部分代码如下:
- $ vi hello.s
- 1 .file "hello.c"
- 2 .section .rodata
- 3 .LC0:
- 4 .string "hello, world!"
- 5 .text
- 6 .globl main
- 7 .type main, @function
- 8 main:
- 9 leal 4(%esp), %ecx
- 10 andl $-16, %esp
- 11 pushl -4(%ecx)
- 12 pushl %ebp
- // 注释:如果你熟悉,就可以对部分汇编优化以达到更好效果。
4.生成目标文件 hello.o
- $ gcc -c hello.c -o hello.o
- $ ls
- a.out hello hello.c hello.i hello.o hello.s
- hello.o 就是新生成的目标文件:
- 如下语句结果相同:
- $ gcc -c -o hello.o hello.c
- 如 下语句结果相同:
- $ gcc -c hello.c
- 也 可以采用前面步骤产生的中间文件hello.i或hello.s来生成目标文件:
- $ gcc -c hello.i
- $ gcc -c hello.s
- 我 们可以用 objdump 查看 hello.o 的二进制码:
- $ objdump -s hello.o
- hello.o: file format elf32-i386
- Contents of section .text:
- 0000 8d4c2404 83e4f0ff 71fc5589 e55183ec .L$.....q.U..Q..
- 0010 04c70424 00000000 e8fcffff ffb80000 ...$............
- 0020 000083c4 04595d8d 61fcc3 .....Y].a..
- Contents of section .rodata:
- 0000 68656c6c 6f2c2077 6f726c64 2100 hello, world!.
- Contents of section .comment:
- 0000 00474343 3a202847 4e552920 342e312e .GCC: (GNU) 4.1.
- 0010 31203230 30373031 30352028 52656420 1 20070105 (Red
- 0020 48617420 342e312e 312d3532 2900 Hat 4.1.1-52).
5. 采用中间级文件生成可执行程序
- $ gcc -o hello hello.i
- $ ./hello
- hello, world!
- $ gcc -o hello hello.s
- $ ./hello
- hello, world!
- $ gcc -o hello hello.o
- $ ./hello
- hello, world!
四、 静态库的生成
linux下静态库的生成比较方便。在生成目标文件后用 ar 打包即可。在中大型项目中一个模块一般会做成一个静态库,以方便管理、提高编译、链接效率。
本小节的展示针对 main.c、func1.c、func2.c三个文件
- /*
- * main.c
- */
- #include <stdio.h>
- extern int func1();
- extern int func2();
- int main()
- {
- int i;
- i = func1();
- printf("func1 return = %d/n",i);
- i = func2();
- printf("func2 return = %d/n",i);
- return 0;
- }
-----------------------------------------------------
- /*
- * func1.c
- */
- int func1()
- {
- return 100;
- }
-----------------------------------------------------
- /*
- * func2.c
- */
- int func2()
- {
- return 200;
- }
一 下是编译指 令:
- $ gcc -c func1.c
- $ gcc -c func2.c
- $ ls
- func1.c func1.o func2.c func2.o main.c
- func1.o 和 func2.o 是 我们生成的目标文件。打包指令如下:
- $ ar -r libfunc.a func1.o func2.o
- 我 们查看 libfunc.a 中的文件:
- $ ar -t libfunc.a
- func1.o
- func2.o
- 现 在用静态库和 main.c 共同生成目标程序:
- $ gcc -o main main.c libfunc.a
- $ ./main
- func1 return = 100
- func2 return = 200
- 和 我们的预期相符合。下面我们进入动态库。
五、动态库的生成
linux下动态库的生成通过GCC选项实现。案例程序和静态库中的相同。一下是操作指令:
- 首 先我们生成目标文件,但是需要加编译器选项 -fpic 和链接器选项 -shared
- $ gcc -fpic -c func1.c 注:许多地方动态库的编译是使用-fPIC选项 而不是小写-fpic
- $ gcc -fpic -c func2.c
- $ gcc -shared -o libfunc.so func1.o func2.o
- $ ls
- func1.c func1.o func2.c func2.o libfunc.so main.c
- libfunc.so 就是我们生成的目标动态库。我们用动态库和 main.c 生成目标程序:
- $ gcc -o main main.c -L. -lfunc
- 注 意,我们用 -L. -lfunc 作为编译选项。-L. 表从当前目录查找需要的动态库,-lfunc 是动态库的调用规则。Linux系统下的动态库命名方 式是 lib*.so,而在链接时表示位 -l* , *是自己起的库名。下面我们运行它:
- $ ./main
- ./main: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory
- 提 示一个错误, 指示无法找到动态库。在linux下最方便的解决方案是拷贝libfunc.so到绝对目录 /lib 下。但是只有超级用户才有这个权限。另外一个方案 是更改环境变量 LD_LIBRARY_PATH。如下:
- $ $ export LD_LIBRARY_PATH=`pwd`
- $ ./main
- func1 return = 100
- func2 return = 200
- 运 行成功。现在我们更改动态库的函数而不重新链接。如下:
- 更改 func1.c 为:
- int func1()
- {
- return 101;
- }
- 更 改 func2.c 为:
- int func2()
- {
- return 202;
- }
- 重 新生成库:
- $ gcc -fpic -shared func1.c func2.c -o libfunc.so
- $ ./main
- func1 return = 101
- func2 return = 202
- 可 以看出,动态库已经更新了。
六、结束语
本文简单介绍了linux下如何使用gcc进行编译程序、以及简 单的静态、动态库的生成。静态库提供了一种打包管理方案,而动态库使程序局部更新成为了可能,更重要的是,当有多份实例存在时,动态库可减小内存的消耗 (只占用一份代码空间)。
对本系列知识感兴趣者可继续跟踪阅读后续文章:库的版本管理、GCC的编译选项、Makefile与自动化编译
在Linux下如何使用GCC编译程序、简单生成 静态库及动态库的更多相关文章
- 详细讲解 关于Linux静态库和动态库的分析
基本概念 库有动态与静态两种,动态通常用.so为后缀,静态用.a为后缀. 例如:libhello.so libhello.a 为了在同一系统中使用不同版本的库,可以在库文件名后加上版本号为后缀,例如: ...
- Linux中的静态库与动态库
什么是库文件? 库文件是事先编译好的方法的合集.比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写. Linux系统中: 1.静态库的扩展名为.a:2. ...
- Linux下Gcc生成和使用静态库和动态库详解(转)
一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...
- Linux下Gcc生成和使用静态库和动态库详解
参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...
- 【转】Linux下gcc生成和使用静态库和动态库详解
一.基本概念 1.1 什么是库 在Windows平台和Linux平台下都大量存在着库. 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不 ...
- Linux下GCC生成和使用静态库和动态库【转】
本文转载自:http://www.cppblog.com/deane/articles/165216.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本 ...
- [转]Linux下用gcc/g++生成静态库和动态库(Z)
Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10| 分类: linux | 标签:链接库 linux g++ gcc |举报|字号 订阅 ...
- linux 下多版本gcc 共存问题
linux 下多版本gcc 共存问题 http://blog.csdn.net/isfirst/article/details/42296583 参考 http://blog.csdn.net/chi ...
- linux下scsi共享磁盘的简单搭建
linux下scsi共享磁盘的简单搭建 Scsi 共享磁盘需要我先有空余的分区,或者可以在虚拟机里面添加一块磁盘,安装所需的软件我在虚拟机里面添加了一块硬盘,分了一个主分区,sdb1 1G,将这个用s ...
随机推荐
- css-css权威指南学习笔记3
第三章 结构和层叠 1.确定应向一个元素应用哪些值时,用户代理不仅要考虑继承,还要考虑声明的特殊性,另外需要考虑声明本身的来源,这个过程就称为层叠.. 2.特殊性.如果一个元素有两个或多个冲突的属性声 ...
- 【BZOJ-3786】星系探索 Splay + DFS序
3786: 星系探索 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 647 Solved: 212[Submit][Status][Discuss] ...
- 【BZOJ-3555】企鹅QQ 字符串Hash
3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1545 Solved: 593[Submit][Statu ...
- Restful api介绍
网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信.这导致AP ...
- 关于git的学习
Git是目前世界上最先进的分布式版本控制系统(没有之一)! 由于现在用的还不多,还没有这种体会,但是前人的经验是值得借鉴的,所以我认真的学习了一些关于git的简单操作,现在在这分享一些心得,或者说是为 ...
- memcached的分布式
今天写点周末在火车上看的memcached的东西: 一:memcached的分布式 虽然memcached被称为“分布式”缓存服务器,但是服务器端并没有“分布式”的功能.而是通过客户端来实现的. Me ...
- 强连通分量的Tarjan算法
资料参考 Tarjan算法寻找有向图的强连通分量 基于强联通的tarjan算法详解 有向图强连通分量的Tarjan算法 处理SCC(强连通分量问题)的Tarjan算法 强连通分量的三种算法分析 Tar ...
- 利用php制作简单的文本式留言板
del.php 代码如下: <html><head ><meta charset="utf-8"><title>我的留言板</ ...
- Beta版本冲刺第七天 12.13
一.站立式会议照片: 二.项目燃尽图: Android端 后台 三.项目进展: 成 员 昨天完成任务 今天完成任务 问题困难 心得体会 胡泽善 用户评价的查看以及审核 用户详情的加入,并且修改了一些卡 ...
- Mysql学习笔记(三)对表数据的增删改查。
正文内容. 这一部分是最简单的,也是最麻烦的.简单是因为其实只包括增删该插四个部分.大体上看,增加数据.删除数据.修改数据.查询数据都不麻烦啊,我们日常都是常用的.这个谁不会呢?以前在培训机构学mys ...