gcc 编译四步骤
1.预处理
命令:gcc -E -o main.i main.c
作用:展开宏,头文件
替换条件编译
删除注释,空白行
2.编译 (消耗时间,系统资源最多)
命令:gcc -S -o main.s main.i (main.s是汇编文件)
作用:检查语法
3.汇编
命令:gcc -c -o main.o main.s (main.o是二进制文件)
作用:将汇编代码翻译成机器码
4.链接
命令:无参数 gcc -o main main.o sub.o
作用:数据段合并,地址回填
gcc 编译常用选项
-E
只做预处理
-S
预处理和编译
-c
预处理,编译,汇编,但是不链接
-I
头文件路径: gcc -o main main.c -I./inc (头文件放在当前目录的inc子目录下,-I和目录之间没有空格)
-L
动态库路径:gcc -o test main.o -lsub -L /libsub.so/所在目录/ (动态库在/libsub.so/所在目录/)
-l
库名:指定库名,其中库名是去掉前缀lib和后缀.so (例如:libsub.so -lsub)
-g
包含调试信息,用于gdb调试
-Wall
提示更多警告信息
-On
n=0~3, n越大优化越大
-D
向程序中注册宏
静态库和动态库理论对比
1.使用库的好处:
1.无论静态库还是动态库都已经编译好的,直接链接进可执行程序,省去了最耗时的编译步骤
2.可移植性好,容易维护
3.方便程序的模块化设计
2.程序库:包含数据和执行码的文件,不能单独执行,作为其他可执行程序的一部分完成某个功能,分为动态库和静态库。
3.静态库:程序运行前加入到执行码中,成为可执行文件的一部分 一般以.a作为后缀名
4.动态库:程序启动时加入到可执行程序中,可以被多个可执行文件共享使用,也成为共享库。一般命名为lib库名.so格
式
5.程序运行效率
时间效率:静态库直接在可执行程序内,动态库程序加载时,需要到特定路径下加载。静态库时间效率比动态库高
空间效率:静态库在可执行程序内不,的空间占用高。动态库不在可执行程序内,空间占用低
6.应用场景:静态库用于时间效率要求高,空间效率要求低的程序
动态库用于时间效率要求低,空间效率要求高的程序
但是目前随着操作系统的优化,静态库和动态库的执行效率差不多,一般都使用动态库。
当有人需要用到你写的程序的功能时,你又不想让他看到你的源码,可以直接给一个静态库给他
静态库制作和使用
1.编写.c .h文件
2. 将.c 生成.o
gcc -c -o add.o add.c
gcc -c -o add.o sub.c
gcc -c -o add.o div.c
3. 使用ar工具生成静态库:
ar rcs libmymath.a add.o sub.o div.o
4. 使用静态库:(就是将静态库编译进可执行程序中)
gcc -o main libmymath.a test.c
静态库使用和头文件对应
问题:当执行 gcc -o main libmymath.a test.c -Wall时,提示函数add(), sub(), div() 隐式声明
原因:tset.c程序中没有函数定义也没有函数声明,编译器自动隐式声明。但是编译器隐式声明的形式只有一种:int
add(int, int)
解决:指定头文件,头文件中有函数声明,与静态库配套mymath.h,再test.c中#include "mymath.h"
头文件写法:
头文件首位:ifndef _MYMATH_H
define _MYMATH_H
...
endif
防止头文件重复包含
动态库制作和使用
1. 编写.c .h
2. 将.c 生成.o (生成与位置无关的代码) gcc -o main.o main.c -fPIC
2.1 自定义函数中地址回填:func1(), func2()是自定义函数
main(){
func1();
func2();
}
func1(), func2()的函数地址是由main函数地址决定的,是相对main()地址的
2.2 动态库中函数地址回填:func3(), func4()是动态库里的函数
main(){
func3();
func4();
}
func3(), func4()的函数地址是由@plt决定的,当程序运行到func3()时,程序加载动态库,@plt才被赋值。动态库函
数地址绑定时间晚于自定义函数,成为延迟绑定。
3. 使用gcc -shared 制作动态库
gcc -shared -o libmymath.so add.o sub.o div.o
4. 使用动态库(就是在编译可执行程序时指定动态库和动态库路径) -l库名 -L 路径
动态库加载错误原因及解决
问题:当执行 gcc -o test test.c -lmymath -L./lib 时报错:can not open shared objiect file
原因:链接器: 工作于链接阶段,需要 -l -L链接
动态连接器: 工作于程序运行阶段,工作时需要提供动态库所在目录位置,会自动去固定目录找
动态链接器按照以下顺序一次查找动态库
1. 环境变量 LD_LIBRARY_PATH指定目录 (方法1,2)
2. 文件/etc/ld.so.cache (方法4)
3. 默认目录,先/usr/lib, 然后/lib (方法3)
解决:在固定目录(LD_LIBRARY_PATH)中放入动态库
方法一:修改环境变量 export LD_LIBRARY_PATH=./lib, 临时生效,进程关闭,环境变量自动失效
方法二:修改.bashrc 在末尾加入 export LD_LIBRARY_PATH=./lib 然后 source .bashrc使其生效
永久生效(建议使用绝对路径)
方法三:将自定义库放入标准c库所在路径
方法四:配置文件法
vi /etc/ld.so.conf
写入动态库所在目录
ldconfig