一、make和makefile
1. 什么是 make 和 Makefile?
-
make:一个命令工具,用于解释 Makefile 中的指令。
-
Makefile:一个文件,定义了项目的编译规则、依赖关系和命令。
2. 基本使用示例
bash
myproc: myproc.c
gcc -o myproc myproc.c
.PHONY: clean
clean:
rm -f myproc
-
myproc是目标文件,依赖于myproc.c -
gcc -o myproc myproc.c是生成目标的命令 -
clean用于清理项目,.PHONY表示它不生成文件,总是执行
3. make 的工作流程
-
在当前目录下查找
Makefile或makefile -
找到第一个目标文件(如
myproc) -
检查目标文件是否存在或其依赖是否更新
-
递归查找依赖链,直到所有依赖都被处理
-
执行相应命令生成最终目标
如果某个依赖文件不存在,make 会报错并退出。
4. .PHONY 的作用
-
被
.PHONY修饰的目标,总是被执行,不受文件时间戳影响。 -
典型应用:
clean、test等辅助操作。
bash
.PHONY: clean
clean:
rm -f *.o *.i *.s myproc
5. Makefile 的推导过程(多文件编译)
bash
myproc: myproc.o
gcc myproc.o -o myproc
myproc.o: myproc.s
gcc -c myproc.s -o myproc.o
myproc.s: myproc.i
gcc -S myproc.i -o myproc.s
myproc.i: myproc.c
gcc -E myproc.c -o myproc.i
这就是一个完整的从
.c到可执行文件的推导链:
.c→.i→.s→.o→可执行文件
6. Makefile 高级语法扩展
bash
BIN = proc.exe # 定义变量:最终生成的可执行文件名
CC = gcc # 定义变量:指定编译器为 gcc
SRC = $(wildcard *.c) # 使用 wildcard 函数:获取当前目录下所有 .c 文件,保存到 SRC 变量
OBJ = $(SRC:.c=.o) # 模式替换:将 SRC 中所有 .c 后缀替换为 .o,生成目标文件列表
LFLAGS = -o # 定义变量:链接阶段的编译选项(-o 指定输出文件名)
FLAGS = -c # 定义变量:编译阶段的选项(-c 表示只编译不链接)
RM = rm -f # 定义变量:删除命令,-f 表示强制删除不提示
$(BIN): $(OBJ) # 规则:proc.exe 依赖于所有 .o 文件
@$(CC) $(LFLAGS) $@ $^ # 执行链接:gcc -o proc.exe 所有.o文件
@echo "Linking ... $^ to $@" # 输出链接信息,@ 表示不显示命令本身
%.o: %.c # 静态模式规则:所有 .o 文件依赖于同名的 .c 文件
@$(CC) $(FLAGS) $< # 执行编译:gcc -c 对应的.c文件
@echo "Compiling ... $< to $@" # 输出编译信息
.PHONY: clean # 声明伪目标:clean 不是一个真实文件
clean: # 清理规则
$(RM) $(OBJ) $(BIN) # 删除所有 .o 文件和可执行文件
.PHONY: test # 声明伪目标:test 也不是真实文件
test: # 测试规则
@echo $(SRC) # 打印所有 .c 源文件
@echo $(OBJ) # 打印所有 .o 目标文件
| 语法 | 说明 | 示例 |
|---|---|---|
= |
定义变量 | BIN = proc.exe |
$(变量名) |
引用变量 | $(CC) |
$(wildcard 模式) |
查找匹配的文件 | $(wildcard *.c) → 返回所有.c文件 |
$(变量:.旧后缀=.新后缀) |
后缀替换 | $(SRC:.c=.o) → 将.c换成.o |
% |
通配符,匹配任意字符串 | %.o: %.c → 所有.o依赖同名.c |
$@ |
自动变量:目标文件名 | 在规则中代表目标 |
$^ |
自动变量:所有依赖文件 | 在规则中代表所有依赖 |
$< |
自动变量:第一个依赖文件 | 在规则中代表第一个依赖 |
@ |
命令前缀:静默执行 | @echo → 不显示echo命令本身 |
.PHONY |
声明伪目标 | 防止与同名文件冲突 |
二、git提交的流程
bash
# 1. 初始化仓库或克隆现有项目
git init
# 或
git clone <仓库地址>
# 2. 编辑文件后,查看变更
git status
# 3. 将文件添加到暂存区(准备提交)
git add <文件名> # 添加单个文件
git add . # 添加所有变更
# 4. 提交到本地仓库,并附上说明
git commit -m "修改了某个功能"
# 5. 推送到远程仓库(如GitHub、GitLab)
git push origin main
# 6. 拉取他人最新提交
git pull origin main
三、gbd/cgbd使用
1. 调试版本的编译
默认 gcc 编译出的程序是 release 模式 ,不支持调试。必须加上 -g 选项生成 debug 版本:
bash
# 不支持调试(默认)
gcc mycmd.c -o mycmd
# 支持调试(debug 模式)
gcc mycmd.c -o mycmd -g
使用 file mycmd 查看是否包含 debug_info。
2. GDB 常用命令速查表
| 命令 | 作用 | 示例 |
|---|---|---|
l / list |
显示源代码 | l main |
b / break |
设置断点 | b 10 或 b main |
info b / info breakpoints |
查看所有断点信息 | info b |
d / delete |
删除所有断点 | delete |
d 断点编号 |
删除指定编号的断点 | delete 2 |
disable |
禁用所有断点 | disable |
disable 断点编号 |
禁用指定编号的断点 | disable 1 |
enable |
启用所有断点 | enable |
enable 断点编号 |
启用指定编号的断点 | enable 1 |
r / run |
开始执行程序 | run |
n / next |
单步执行(不进入函数) | next |
s / step |
单步执行(进入函数) | step |
c / continue |
继续执行到下一断点 | continue |
p / print |
打印变量或表达式 | p result |
set var |
修改变量值 | set var flag=1 |
watch |
监视变量变化 | watch result |
finish |
执行到当前函数返回 | finish |
until |
执行到指定行 | until 14 |
info locals |
查看当前局部变量 | info locals |
bt / backtrace |
查看函数调用栈 | backtrace |
quit |
退出 GDB | quit |
3. 高级调试技巧(加餐)
1. 使用 cgdb 提升体验
bash
# Ubuntu
sudo apt install cgdb
# CentOS
sudo yum install cgdb
cgdb 兼顾 GDB 的命令行能力 + 代码窗口,调试更直观。
2. watch:监视变量变化
bash
watch result
当 result 被修改时,GDB 会自动暂停并提示旧值/新值,非常适合定位"不该变却变了"的变量。
3. set var:动态修改变量,快速验证问题
bash
p flag # 查看当前值
set var flag=1
4. 条件断点
条件断点允许我们只在某个条件满足时才触发断点,非常适合调试循环体或频繁调用的函数。
1. 添加条件断点
语法格式:
bash
break 行号 if 条件表达式
break 函数名 if 条件表达式
实战示例:
假设我们想在 Sum 函数的第 9 行(循环体内部)设置断点,并且只有当 i == 30 时才暂停:
bash
(gdb) b 9 if i == 30
Breakpoint 2 at 0x555555555156: file mycmd.c, line 9.
2. 查看条件断点
使用 info b 可以看到条件断点的特殊标记:
bash
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x00005555555551c3 in main at mycmd.c:20
breakpoint already hit 1 time
2 breakpoint keep y 0x0000555555555156 in Sum at mycmd.c:9
stop only if i == 30 # ← 条件断点的标识
可以看到,断点 2 后面多了 stop only if i == 30,表示这是一个条件断点。
3. 条件断点的执行效果
当程序运行时,GDB 会自动检查条件:
-
条件为
false(如i=1,2,3...29)→ 断点不触发,程序继续执行 -
条件为
true(如i=30)→ 断点触发,程序暂停
这样我们就不需要手动按几百次 n 来追踪循环,直接精准定位到 i == 30 的时刻。
4. 其他条件断点操作
bash
# 为现有断点添加条件
condition 2 i == 50
# 修改已有断点的条件
condition 2 i == 100
# 删除断点的条件(变为普通断点)
condition 2
# 设置条件断点的另一种写法
break mycmd.c:9 if i == 30