• linux系统编程 (四) gdb调试与makefile


    1.gdb调试工具

    程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪。到目前为止我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码中适当的位置插入printf,执行程序并分析打印结果,如果结果和预期的一样,就基本上证明了自己假设的错误原因,就可以动手修正Bug了,如果结果和预期的不一样,就根据结果做进一步的假设和分析。

    本章我们介绍一种非常强大的调试工具gdb,可以完全操控程序的运行,使得程序就像你手里的玩具一样,叫它走就走,叫它停就停,并且随时可以查看程序中所有的内部状态,比如各变量的值、传给函数的参数、当前执行的语句位置等。掌握了gdb的用法以后,调试的手段就更加丰富了。但要注意,即使调试的手段非常丰富了,其基本思想仍然是“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环,根据现象如何假设错误原因,以及如何设计新的现象去验证假设,这都需要非常严密的分析和思考,如果因为手里有了强大的工具就滥用,而忽视了严谨的思维,往往会治标不治本地修正Bug,导致一个错误现象消失了但Bug仍然存在,甚至是把程序越改越错。

    gcc -g main.c -o main
    
    • 1

    常用命令
    在这里插入图片描述
    在这里插入图片描述

    1.1 gdb调试

    gdb调试工具:大前提,程序是自己写的
    
                 -g:使用该参数编译可执行文件,得到调试表。
    	gdb ./a.out
    	list : l 2 列出源码 。根据源码指定行号设置断点。
    	b:  	b20 在20行位置设置断点。
    	run/r: 	运行程序
    	n/next:	下一条指令(会越过函数)
    	s/step:	下一条指令(会进入到函数里面去)
    	p:	p   i  查看变量的数值。
    	continue :继续执行断点后续
    
    	其他指令:
    		run:段错误:gdb直接run
    		start:单步调试,运行程序,停在第一句执行语句。
    		quit:结束gdb
    		finish:结束当前函数调用
    常见错误:
    没有符号表:是编译的时候没有加-g
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.Makefile 项目管理

    在这里插入图片描述

    2.1 用途

    + 项目代码编译管理
    + 节省编译项目时间
    + 一次编写终身受益
    + 操作示例文件:add.c sub.c mul.c dive.c main.c
    
    • 1
    • 2
    • 3
    • 4

    2.2 基本规则

    Makefile由一组规则组成,规则如下:

    目标:依赖
    (tab)命令
    如:add.o:add.c
    (一个tab缩进)gcc –Wall –g –c add.c –o add.o
    目标:要生成的目标文件
    依赖:目标文件由哪些文件生成
    命令:通过执行该命令由依赖文件生成目标
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2.2.1 三要素

    • 目标
    • 条件
    • 命令

    2.3 Makefile 工作原理

    基本原则:
    1.若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来 生成该依赖文件
    2.检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更 新,则目标必须更新

    • 分析各个目标和依赖之间的关系
    • 根据依赖关系自底向上执行命令
    • 根据修改时间比目标新,确定更新
    • 如果目标不依赖任何条件,则执行对应命令,以示更新

    2.4 Makefile 变量

    在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换, 使用变量可以使Makefile易于维护,修改内容变得简单
    变量定义及使用:

    foo = abc
    bar = $(foo)
    
    • 1
    • 2

    定义了两个变量:foo、bar,其中bar的值是foo变量值的引用。

    1、变量定义直接用'='
    2、使用变量值用$(变量名)
    
    • 1
    • 2

    通常我们在Makefile中会定义一些变量,方便Makefile的修改维护

    src = main.c func1.c func2.c
    CC = gcc #arm-linux-gcc
    CPPFLAGS : C预处理的选项 如:-I
    CFLAGS:C编译器的选项 –Wall –g -c
    LDFLAGS :链接器选项 –L -l
    
    • 1
    • 2
    • 3
    • 4
    • 5

    自动变量:

    $@:表示规则中的目标
    $<:表示规则中的第一个条件
    $^:表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。
    
    • 1
    • 2
    • 3

    模式规则:
    至少在规则的目标定义中要包含’%‘,’%‘表示一个或多个,在依赖条件中同样可以
    使用’%‘,依赖条件中的’%’的取值,取决于其目标: 模式规则示例:

    %.o:%.c
    $(CC) –c $(CFLAGS) $(CPPFLAGS) $< -o $@
    其中,“$@”表示依次取出目标值,$<表示依次取出依赖条件。
    
    • 1
    • 2
    • 3

    注意:只有写成模式规则的时候,$<才表示了所有依赖条件的依次取值,否则只是取依 赖条件中的第一个。

    2.5 Makefile 函数

    src = $(wildcard *.c)
    找到当前目录下所有后缀为.c的文件,赋值给src
    obj = $(patsubst %.c,%.o, $(src))
    把src变量里所有后缀为.c的文件替换成.o
    
    • 1
    • 2
    • 3
    • 4

    2.6 clean

    • 用途:清除编译生成的中间.o文件和最终目标文件
    • make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令
    • 伪目标声明:.PHONY:clean
    • clean命令中的特殊符号
      – “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o”
      – “@”不显示命令本身,只显示结果。如:“@echo”clean done“”
    • 其它
      – make 默认执行第一个出现的目标,可通过make dest指定要执行的目标
      – distclean目标
      – install目标
      – make -C 指定目录 进入指定目录,调用里面的Makefile
      – make -n:只打印要执行的命令,不会真正执行命令
      – make -p:显示隐含规则数据库中的信息
      – make -C:切换到另一个目录中执行该目录下的Makefile
      – make -f:-f执行一个makefile文件名称,使用make执行指定的makefile

    3.总结

    
    Makefile 就是一个脚本文件:
    脚本文件就是把一系列的命令放到一个文本里批量执行。
    	命名:makefile或Makefile
    	一个规则
    		目标:依赖条件
    		(一个tab)命令
    		1.目标的时间必须晚于依赖条件的时间,否则,更新目录
    		2.依赖条件如果不存在,找寻新的规则去产生依赖
    	两个函数
    		src=$(wildcard ./*.c):匹配当前目录下的所有.c文件。将文件名组成列表,赋值给变量src。src = add.c sub.c div.c
    		obj=$(patsubst %.c,%.o,$(src)):将参数3中的,包含参数1的部分,替换为参数2.obj=add.o sub.o div .o 
    	clean :(没有依赖)
    		-rm -rf $(obj) a.out  "-":作用是,删除不存在的文件时候,不报错。顺序执行结束	
    	make clean 只执行make里面的clean 
    	make clean -n 模拟执行make 里面的clean
    三个自动变量:
    	$@:在规则的命令中,表示规则中的目标
    	$<:在规则的命令中,还表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。
    	$^:在规则的命令中,表示所有的依赖条件。
    
    模式规则:
    	%.o:%.c
            		gcc -c $< -o $@
    静态模式规则:
    
    	$(obj):%.o:%.c
            		gcc -c $< -o $@
    
    伪目标:
    	.PHONY:clean ALL
    
    
    参数:
    	-n:模拟执行make make clean
    	-f:指定文件执行make命令
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
  • 相关阅读:
    Linux系统启动过程---目录结构---文件系统超详解析
    漏洞分析 | 漏洞调试的捷径:精简代码加速分析与利用
    Chapter 02 列表和元组,你该怎么用
    【网络】UDP协议
    tqdm高级使用方法(类keras进度条)
    Apache Doris (四十七): Doris表结构变更-Schema变更
    cv2 可视化操作整理(直线,圆,矩形,多边形,文本)
    uni-app通过 vuedraggable 创建上下拖动排序组件
    (科学:计算能量)编写程序,计算将水从初始温度加热到最终温度所需的能量。程序应该提示用户输入水的重量(以千克为单位),以及水的初始温度和最终温度。
    Leetcode刷题详解——移动零
  • 原文地址:https://blog.csdn.net/weixin_45840087/article/details/126631764