目录
工程编译
Ubuntu编译C程序采用的是gcc编译器
gcc xxx.c //编译xxx.c文件,默认输出可执行文件a.out gcc xxx.c -o xxx //输出可命名的执行文件 |
C语言程序编译的四个阶段
1编译预处理:处理伪指令(头文件\宏\条件编译) | gcc -E xxx.c -o xxx.i |
2编译:将代码编译为汇编程序 | gcc -S xxx.i -o xxx.s |
3汇编:将汇编代码译成机器代码 | as xxx.s -o xxx.o (gcc -c xxx.c -o xxx.o) |
4连接:寻找程序中使用到的库文件 | gcc xxx.o -o xxx |
常用的编译选项
1、没有任何选项:gcc helloworld.c
2、-o选项,指定输出文件名:gcc -o helloworld helloworld.c
3、-c选项,只编译,不链接:gcc -c helloworld.c
4、-S选项,使用预处理C源文件产生的文件,产生汇编源文件:gcc -S helloworld.c
5、-E选项,预处理C源文件:gcc -E helloworld.c
6、-g选项,产生供gdb调试用的可执行文件:gcc -g helloworld.c
动态库与静态库的制作
库的概念:库包含了通用函数的数据和二进制可执行机器码的文件,静态库文件后缀为xxx.a,动态库文件后缀为xxx.so;库具有移植性高、封装性好和对源码具有良好的保护性等优点。
静态库
静态库的优点是运行速度快,以空间换区时间,不足的是如果库更新,代码需要重新编译。
静态库的创建:如创建一个学生信息库,库名为libxxx.a,工程里关于学习信息操作的文件有add.c、del.c,顶层源文件为strudent.c。
1 准备功能函数的源文件,只编译,不链接。
2 制作静态库
3 使用静态库:gcc main.c -l 库名 -L 库的路径
动态库
动态库的优点是如果库更新,源码不需要重新编译,但不足的是运行时间较慢,以时间换空间。在程序编译阶段,不会将函数源码编译到目标文件,而是在执行过程中,使用到哪个函数,从库中寻找,跳转到对应函数入口执行。
1 只编译,不链接
2 动态库的制作:gcc -fpic -shared xxx.o yyy.o -o libxxx.so
3 使用动态库:gcc main.c -lxxx -L ./
-l:指明用到的库文件
-L:库文件所在的的路径
添加动态库搜索路径,注意:export:该指令用于设置环境变量如果该指令在终端执行,那么配置在系统重启之后失效;如果将该执行放到/etc/profile文件中,该指令永久有效
Linux动态库.so搜索路径,Linux会按照如下顺序寻找动态库.so文件。
1 编译目标代码时指定的动态库搜索路径;
2 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4 默认的动态库搜索路径/lib;
5 默认的动态库搜索路径/usr/lib。
详见:Linux动态库.so搜索路径
补充
-fpic 与-fPIC的异同
相同点:都是为了在动态库中生成位置无关的代码。通过全局偏移表(GOT)访问所有常量地址。程序启动时动态加载程序解析GOT条目。
如果目标机器支持,则生成适合在共享库中使用的位置无关代码(PIC)。这样的代码通过全局偏移表(GOT)访问所有的常量地址。动态加载器在程序启动时解析GOT条目(动态加载器不是GCC的一部分;它是操作系统的一部分)。如果链接的可执行文件的GOT大小超过了特定于机器的最大大小,你会从链接器得到一条错误消息,指示-fpic不能工作;在这种情况下,用-fPIC重新编译。这些最大值在SPARC上是8k,在AArch64上是28k
详见gcc手册:Using the GNU Compiler Collection (GCC)
调试工具gdb
调试步骤: