翼度科技»论坛 云主机 LINUX 查看内容

Linux下gcc编译,动态库和静态库,makefile,gdb调试

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
1.编译过程

1.1 预处理(Pre-Processing)

  展开头文件, 宏替换(变量宏、函数宏)、替换空格等
  1. gcc -E hello.c  -o hello.i     // -E 预处理选项, -o 重命名
复制代码

1.2 编译(Compilation)

  逐行检查程序中出现的语法错误,简单的逻辑错误
  1. gcc -S hello.i -o hello.s
复制代码

1.3 汇编(Assemble)

  将 .s 汇编文件中所有的汇编指令翻译成二进制机器码(下面就是来了个截图,二进制显示了乱码)
  1. gcc -c hello.s -o hello.o
复制代码

1.4 链接(Linking)

  将 .o 的目标文件,链接库文件、数据段合并,地址回填(把汇编里相对地址替换成程序运行后真正可以运行的地址)。生成可执行文件 hello
  1. gcc hello.o -o hello
复制代码
1.5 gcc常用参数
  1. -E // 展开头文件
  2. -s // 生成汇编文件
  3. -c // 编译生成2进制文件
  4. -I // 指定头文件路径 大i
  5. -L // 指定库文件路径
  6. -l // 指定库名 小L
  7. -g // 包含调试信息
  8. -On // n取 0-3, n 越大优化级别越高
  9. -Wall //warning all 显示所有警告
  10. -D // 编译时动态注入一个宏, 编译的时候控制#define的具体数值
复制代码
2.动态库和静态库

2.1 函数库

  本质:把具有相同功能的一组函数放到同一份文件中(源码或二进制的形式)
2.2 静态库

  对执行速度有要求

  • 机制:把引入的库文件通过编译直接复制到 .out 文件中
  • 优点:将函数库中的函数本地化,寻址方便,速度快(函数库执行效率 = 自定义函数的执行效率)
  • 缺点:每个程序都需要复制一份,会浪费内存
  制作静态库: 
  1. gcc -c add.c sub.c mul.c    // 制作 .o 文件
  2. ar rs libmymath.a add.o sub.o mul.o    // 制作静态库
  3. gcc hello.c -L ./ -lmymath -o app    // 指定头文件路径, 指定库名, 设置文件输出名app
复制代码
2.3 动态库

  对执行速度不敏感,对系统资源敏感;更新比较频繁(可以避免完全重新编译)

  • 机制:代码共享
  • 优点:节省内存(共享)、易于更新(动态链接)
  • 缺点:相较于静态库函数调用速度慢,函数地址是延时绑定机制
  1. gcc -c -fPIC add.c sub.c mul.c    // -fPIC生成与位置无关的目标文件
  2. gcc -shared -o libmymath.so sub.o mul.o add.o    // 生成一个动态库
  3. gcc hello.c -o app -L ./lib -l mymath -I ./inc    // 生成文件
复制代码
 启动 ./app 报错,错误原因:”动态链接器“ ld-linux-x86-64.so.2 搜索动态库的路径没有指定
  链接器:工作于 gcc 编译过程中的链接阶段。工作结束后生成可执行文件
  动态链接器:工作于可执行程序运行之后,辅助加载器负责将动态库加载到内存
 解决办法
  环境变量法:export LD_LIBRARY_PATH=./lib 将当前动态库所在的目录加入到环境变量,终端退出后环境变量就会失效
  配置文件法:vi .bashrc 加入一行 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib,重启终端,每次启动终端自动生效
  拷贝法:把自己的动态库直接拷贝到 /lib 或 /usr/lib 中
  缓存文件法(推荐):修改配置文件,修改缓存文件,生成动态链接器需要搜索的新目录位置
  1. sudo vim /etc/ld.so.conf    // 修改动态链接库的路径
  2. // 将绝对路径增加到文件中
  3. sudo ldconfig -v    // 更新 ld.so.cache 该文件影响动态链接库搜索的位置
复制代码
3.makefile

3.1 语法

 目标:依赖条件
 tab缩进,指令
  1. hello:hello.o add.o sub.o mul.o
  2.     gcc hello.o add.o sub.o mul.o -o hello
  3. hello.o:hello.c
  4.     gcc -c hello.c -o hello.o
  5. sub.o:sub.c
  6.     gcc -c sub.c -o sub.o
  7. add.o:add.c
  8.     gcc -c add.c -o add.o
  9. mul.o:mul.c
  10.     gcc -c mul.c -o mul.o
复制代码
 模式规则:在makefile中,具有有严格统一的规则,使用模式规则代替,模式规则中只能使用 $< 符号
  1. %.o:%.c
  2.     gcc -c $< -o $@
复制代码
 静态模式规则:将模式规则指定给某一个变量使用
  1. $(obj):%.o:%.c
  2.     gcc -c $< -o $@
复制代码
 伪目标:针对残缺的规则,使之生成目标(比如有一个clean.o文件已经是最新的,就不会执行clean清除命令
  1. .PHONY:clean ALL
复制代码
3.2 函数介绍

3.2.1 wildcard 函数
  1. // 匹配当前工作目录下的所有 .c 文件,将文件名组成列表,赋值给 src 变量
  2. // src = add.c sub.c mul.c hello.o
  3. src = $(wildcard ./*.c)
复制代码
3.2.2 patsubst 函数
  1. // 用来替换参数, 将 参数3 中包含 参数1 的部分替换为 参数2
  2. // obj = add.o sub.o mul.o hello.o
  3. obj = $(patsubst %.c, %.o, $(src))
复制代码
3.3 普通变量和自动变量

 普通变量

  • 定义变量语法:变量名 = 变量值     (foo = abc)
  • 取变量值语法:$(变量)           (bar = $abc ---> bar = abc)
 自动变量

  • $@: 在规则的命令中,表示规则中的目标
  • $^ : 在规则的命令中,表示所有依赖条件
  • $< : 在规则的命令中,表示第一个依赖条件。如果该变量应用在”模式规则“中,它可以将依赖条件列表中的每一个依赖,依次取出,套用模式规则
3.4 关键字

  ALL: 默认情况下第一组生成文件的目标就是终极目标,或者显示的写ALL:hello表示终极目标,完成后结束makefile
  clean: 借助makefile清除项目中的指定文件,例如(clean: -rm -rf $(obj) hello
  指令 make -n 模拟执行命令,不真正执行,可以先看一次避免出问题
3.5 修改后的 makefile
  1. src = $(wildcard *.c)
  2. obj = $(patsubst %.c, %.o, $(src))
  3. CC = gcc
  4. target = app
  5. ALL:$(target)
  6. $(target):$(obj)
  7.     $(CC) $^ -o $@
  8. $(obj):%.o %.c
  9.     $(CC) -c $< -o $@
  10. clean:
  11.     -rm -rf $(obj) $(target)
  12. .PHONY:clean ALL
复制代码
4. gdb调试

4.1 基础指令

 基础的断点设置和继续运行等指令

  • -g:使用该指令编译可执行文件,否则没有调试表
  • gdb ./a.out
  • list:list 1 列出源码,根据源码指定行号设置断点,1表示从第一行开始显示源码
  • b:b 55 在第55行添加断点
  • run/r:运行程序,启动调试(可以直接找到停止位置就是出错位置)
  • next/n:下一条指令(越过函数)
  • step/s:下一条执行(进入函数内部)
  • print/p:打印变量值,如p var 查看 var 变量的值
  • continue:执行到下一个断点
  • finish:结束当前函数调用
  • quit:退出调试
  • start:不使用断点,直接开始单步调试
 设置一些条件和查看栈帧及变量

  • set args:启动gdb调试后,通过该指令可以设置main函数的参数,需要在start和run指令之前设置
  • info b:查看当前断点信息表
  • b 23 if i=5:设置断点在23行,如果 i=5 时断点才生效
  • ptybe:查看变量类型
  • display:设置跟踪变量,display i,跟踪变量 i
  • undisplay:取消跟踪变量
  • bt:列出当前程序存活的栈帧
  • frame:如果有多层调用,在内层想查看外层栈帧里的参数,使用 frame n (n 是栈帧编号)切换栈帧,再使用 p var 打印变量

来源:https://www.cnblogs.com/stux/p/17785144.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具