Linux 学习笔记3 动态库静态库与gdb调试
对于.c格式的c文件,可采用gcc编译,而对于.cc或.cpp的文件可采用g++进行编译.
编译常用选项:
-c 表示编译源文件
-o 表示输出目标文件
-g 表示在目标文件中产生调试信息,用于 gdb 调试
-D 编译时将宏定义传入进去
-Wall 打开所有类型的警告
gcc -v 查看gcc的版本
-E 表示预处理
-S 表示编译
-
gcc编译过程:预编译->编译->汇编->链接
Linux编译过程step1:预处理,包含头文件,展开宏定义 gcc -E test.c -o test.i step2:编译,将C语言——>汇编语言 gcc -S test.i -o test.s step3:汇编:汇编语言——>机器语言 as test.s -o test.o step4:链接 gcc test.c -o test
-
gcc库选项
gcc常用库选项
tips:查找动态库 在lib 中 find . -name “.so”
- 静态库与动态库
3.1
静态库时目标文件.a的归档文件(格式为libname.a)
如:add(加法函数)则为libadd.a
如果在编译某个程序时链接静态库,则链接器将会搜索静态库并直接拷贝到该程序的可执行二进制文件 到当前文件中。
动态库(格式为libname.so),编译时不会被链接到目标代码中,而是在程序运行时才被载入。
3.2
动态库创建(以add函数为例)
step1:gcc -fPIC -Wall -c add.c
step2:gcc -shared add.o -o libadd.so
step3链接库:gcc main.c -ladd
静态库创建
step1:gcc -c add.c //编译add.c源文件生成add.o目标文件
step2:ar crsv libadd.a add.o //对目标文件*.o进行归档,生成lib*.a则生成静态库libadd.a
step3:gcc main.c -ladd //编译main.c时,链接静态库
动态库与静态库比较
动态库只有在执行时才被链接使用,且一个动态库可被多个程序使用
静态库会整合到程序中在执行时不用加载,静态库容易部署但是静态库会使得程序臃肿而且难以升级。
亦或是
区别:
1编译时静态库直接编译进可执行程序,会造成可执行程序比较臃肿而动态库没有编译进可执行程序
2执行时可执行程序依赖于动态库,动态库的路径不能被改变也不能被删除
注:ldd是list, dynamic, dependencies的缩写, 意思是, 列出动态库依赖关系。 当然, 你也可以用ldd --help或者man ldd来看其用法
- 程序调式 gdb
采用-g打开调试选项,如:gcc -g main.c; gdb a.out
常用gdb命令:
命令 | 作用 |
---|---|
l | list显示代码 |
r | run 运行 |
b 6 | 在第6行设置断点 |
n | next下一步进入函数,相当于vs的F10 |
s | 单步进入函数,相当于windows下的F11 |
p a | 打印a的值 |
p &a | 打印a的地址 |
c | 运行到最后 continue |
q | 退出 quit |
info b | 查看所设置的断点 |
d 1 | 删除第一个断点 |
disable 3 | 使3号断点失效 |
enable 5 | 使5号断点生效 |
set args 3 4 | 设置运行时的参数为3,4 |
show args | 显示参数 |
path dir | 设定程序运行的路径 |
show paths | 查看程序运行的路径 |
x /12xb &i | 以16进制的方式查看12字节的变量 i 的地址 |
backtrace(bt) | 调用堆栈 |
tips:针对段错误(segmentation fault)
定位错误的方法为:
step1 :gcc -g main.c //重新添加-g参数编译
step2:ulimit -a 查看(core file size)
令ulimit -c unlimited //打开core限制
再运行一次可执行文件,则会产生一个core文件
setp3:重新运行程序
step4:gdb a.out core 则会打印程序在哪一行崩溃(即还原事故现场)