目录1 make 与 Makefile 自动化构建1.1 为什么需要 Makefile1.2 Makefile 基础规则1.3 make 工具推演执行逻辑1.4 伪目标 .PHONY1.5 Makefile 进阶语法自定义变量三大自动变量高频面试wildcard 通配符 后缀替换模式规则 %.o:%.c1.6 多文件项目通用 Makefile 模板编辑2 实战Linux 终端进度条程序2.1 \r回车 与 \n换行2.2 完整进度条代码编辑3 Git 版本控制基础3.1 版本控制解决什么痛点3.2 Git 简单历史3.3 安装与基础配置3.4 Github 基础三板斧编辑4 gdb 调试器基础4.1 debug 版本与 release 版本gdb 常用核心命令5 本篇小结6 面试 实操高频问答Q1 make 和 Makefile 关系Q2 .PHONY 伪目标作用Q3 $ $^ $ 分别是什么Q4 \r 和 \n 区别fflush 作用Q5 gdb 调试为什么编译要加‑g1 make 与 Makefile 自动化构建1.1 为什么需要 Makefile小项目只有一两个.c文件可以直接手动敲 gcc 命令。 当项目源文件数量变多每次修改源码手动敲编译命令非常麻烦。make命令行工具用来解析 Makefile 文件规则Makefile文本文件记录项目编译的依赖规则。价值写好 Makefile 之后只输入make一条命令就自动编译make 会对比文件修改时间只重新编译被修改过的文件不会全部重编译提升编译效率。1.2 Makefile 基础规则每条规则格式目标: 依赖文件列表 Shell命令 # 必须Tab制表符开头不能用空格目标 (target)想要生成的文件例如可执行程序依赖生成目标所需要的文件依赖方法Tab 开头 shell 指令描述如何由依赖生成目标简单示例test.c源码#include stdio.h int main() { printf(hello Makefile!\n); return 0; }Makefile内容test:test.c gcc -o test test.c终端执行make ./test1.3 make 工具推演执行逻辑make 在当前目录寻找Makefile或者makefile读取文件取第一条规则的目标作为终极目标判断目标文件是否存在如果目标不存在执行命令生成目标如果目标已经存在对比目标文件修改时间 和 所有依赖文件修改时间。任意依赖文件比目标新 → 执行命令重新编译全部依赖比目标旧 → 什么都不做提示is up to date。如果依赖本身是另一条规则的目标则递归先执行这条规则生成依赖文件。测试时间逻辑make #生成test make #输出 is up to date touch test.c #更新c文件时间 make #重新编译1.4 伪目标.PHONYclean目标用来删除编译生成的中间文件与可执行程序clean: rm -f test *.o *.i *.s问题如果当前目录刚好存在名叫clean的普通文件执行make clean不会执行 rm 命令make 会认为 clean 文件已经是最新不需要执行规则。使用.PHONY把 clean 声明为伪目标 伪目标不在乎磁盘有没有同名文件只要执行make clean无条件执行对应命令不做时间戳对比。正确写法.PHONY:clean clean: rm -f test *.o *.i *.s运行清理make clean1.5 Makefile 进阶语法自定义变量CCgcc RMrm -f test:test.c $(CC) -o test test.c .PHONY:clean clean: $(RM) test$(变量名)取出变量内容。三大自动变量高频面试表格变量含义$当前规则的目标$^全部依赖文件集合自动去重$依赖列表第一个文件改写CCgcc RMrm -f test:test.c $(CC) -o $ $^ .PHONY:clean clean: $(RM) testwildcard 通配符 后缀替换wildcard *.c获取当前目录所有.c文件名$(SRC:.c.o)把列表中.c后缀替换为.oSRC$(wildcard *.c) OBJ$(SRC:.c.o)模式规则%.o:%.c%代表通配任意文件名。含义任意 xxx.o 文件依赖 xxx.c 源文件。%.o:%.c $(CC) -c $ -o $命令前面加代表不在终端回显这条 shell 命令静默执行。%.o:%.c $(CC) -c $ -o $1.6 多文件项目通用 Makefile 模板可以直接复制用于多 c 文件小项目CCgcc RMrm -f TARGETapp SRC$(wildcard *.c) OBJ$(SRC:.c.o) $(TARGET):$(OBJ) $(CC) $^ -o $ %.o:%.c $(CC) -c $ -o $ .PHONY:clean clean: $(RM) $(OBJ) $(TARGET)使用make make clean注意头文件.h不会被 wildcard 捕获大型项目需要手动把头文件加入依赖。2 实战Linux 终端进度条程序2.1\r回车 与\n换行老式打字机模型理解\n换行光标移动到下一行行首\r回车光标回到当前这一行的最开头不向下换行示例区分现象// 1 会sleep之后才打印hello printf(hello); sleep(3); // 2 \n会刷新行缓冲 printf(hello\n); sleep(3);Linux stdout 是行缓冲遇到\n才刷新缓冲区输出内容没有换行内容留在缓冲区不会立刻打印。fflush(stdout);强制刷新标准输出缓冲区立刻输出缓冲区内容。倒计时 demo#include stdio.h #include unistd.h int main() { int i 10; while(i 0) { printf(%2d\r,i); fflush(stdout); sleep(1); i--; } printf(\n); return 0; }2.2 完整进度条代码process.h#pragma once #include stdio.h void process_v1(); void FlushProcess(double total, double current);process.c#include process.h #include string.h #include unistd.h #define NUM 101 #define STYLE void process_v1() { char buffer[NUM]; memset(buffer, 0, sizeof(buffer)); const char *lable|/-\\; int len strlen(lable); int cnt 0; while(cnt 100) { printf([%-100s][%d%%][%c]\r, buffer, cnt, lable[cnt%len]); fflush(stdout); buffer[cnt] STYLE; cnt; usleep(50000); } printf(\n); } void FlushProcess(double total, double current) { char buffer[NUM]; memset(buffer, 0, sizeof(buffer)); const char *lable|/-\\; int len strlen(lable); static int cnt 0; int num (int)(current*100/total); int i 0; for(; i num; i) { buffer[i] STYLE; } double rate current/total; cnt % len; printf([%-100s][%.1f%%][%c]\r, buffer, rate*100, lable[cnt]); cnt; fflush(stdout); }main.c#include process.h #include unistd.h double total 1024.0; double speed 1.0; void DownLoad() { double current 0; while(current total) { FlushProcess(total, current); usleep(3000); current speed; } printf(\ndownload Done\n); } int main() { DownLoad(); return 0; }配套简易 MakefileCCgcc RMrm -f TARGETprocessbar SRC$(wildcard *.c) OBJ$(SRC:.c.o) $(TARGET):$(OBJ) $(CC) $^ -o $ %.o:%.c $(CC) -c $ -o $ .PHONY:clean clean: $(RM) $(OBJ) $(TARGET)运行make ./processbar3 Git 版本控制基础3.1 版本控制解决什么痛点写代码经常复制一大堆副本v1、v2、最终版、最终版改改版本混乱分不清每版改了什么回滚麻烦。 Git 是分布式版本控制系统记录每一次文件修改历史支持版本回退、多人协同开发。3.2 Git 简单历史Linux 内核社区早期使用商业 BitKeeper2005 年合作终止。Linus Torvalds 开发 Git目标速度快、分布式、支持海量项目、强大分支管理。3.3 安装与基础配置CentOS 安装 gitsudo yum install git -y git --version首次使用配置用户名邮箱提交记录会携带git config --global user.name 你的名字 git config --global user.email 你的邮箱3.4 Github 基础三板斧Github 网页注册账号新建仓库New repository复制仓库 https/ssh 地址。克隆仓库到本地git clone 仓库地址进入仓库目录修改文件。三板斧git add 文件名 # 将改动加入暂存区 git commit -m 写本次修改说明 # 提交到本地仓库 git push # 推送到远端Github辅助常用命令git status #查看当前状态 git log #查看提交日志 git pull #拉取远端最新代码到本地.gitignore文件配置哪些文件不需要 git 管理比如编译生成的可执行程序、中间.o文件。4 gdb 调试器基础4.1 debug 版本与 release 版本gcc 默认生成 release 版本没有调试信息不能 gdb 调试。 想要使用 gdb编译的时候必须加上‑g选项生成 debug 调试信息。示例代码sum.c#include stdio.h int Sum(int s, int e) { int result 0; for(int i s; i e; i) { result i; } return result; } int main() { int start 1; int end 100; printf(I will begin\n); int n Sum(start, end); printf(running done, result is: %d\n, n); return 0; }编译带调试信息gcc -g sum.c -o sum gdb sumgdb 常用核心命令表格命令功能list/l查看源码l 行号run/r开始运行程序break/b 行号设置断点info breakpoints查看所有断点delete d 断点编号删除断点next/n逐过程不进入函数step/s逐语句遇到函数进入函数内部print/p 变量打印变量值display 变量持续跟踪打印变量continue/c运行到下一个断点quit/q退出 gdb5 本篇小结make/Makefile 实现自动化编译目标、依赖、Tab 命令.PHONY伪目标$ $^ $自动变量。\r回到行首、\n换行stdout 行缓冲fflush强制刷新实现终端进度条。git 分布式版本控制add commit push三板斧管理代码版本。gdb 调试编译必须加‑g掌握断点、next、step、print 基础调试命令。6 面试 实操高频问答Q1 make 和 Makefile 关系make 是可执行工具Makefile 是保存编译规则的文本文件make 读取该文件执行构建。Q2 .PHONY 伪目标作用忽略文件时间戳不管磁盘是否存在同名文件执行 make 伪目标就无条件执行规则典型用于 clean。Q3 $ $^ $ 分别是什么$当前规则目标$^全部依赖$第一个依赖。Q4 \r 和 \n 区别fflush 作用\n光标跳到下一行开头\r光标回到本行开头stdout 行缓冲fflush 强制刷新缓冲区立刻输出内容。Q5 gdb 调试为什么编译要加‑g-g生成调试符号信息release 版本没有调试信息无法 gdb 断点调试。系列回顾 04 上yum vim gcc/g 04 下make/Makefile 进度条 git gdb 调试 后续预告Linux 进程基础