
🔥铅笔小新z:个人主页
🎬博客专栏:Linux学习
💫滴水不绝,可穿石;步履不休,能至渊。

引言
本文我们要学习的目标是:
- 学习
yum使用工具,进行软件安装 - 掌握
vim编辑器使用,学会vim的简单配置 - 掌握
gcc/g++编译器的使用,并了解过程和原理 - 掌握简单的
Makefile编写,了解其运行思想 - 学习
git命令行的简单操作,能够将代码上传到 Gitee上 - 掌握简单的
gdb用法用于测试
那么我们接下来开始进入正题。
一、软件包管理器
大家可以回想一下,在
Windows或MacOS中,我们通常怎么下载软件?大概是从官网下载一个.exe或.dmg文件,双击,然后一路点击"下一步"。但在Linux世界里,早期可没有这么方便,我们需要下载源代码,自己去编译。为了解决这个问题,软件包管理器应运而生。
1.1 什么是软件包管理器
简单来说,软件包管理器就是Linux系统中的"物流中心"和"大管家"。可以把它理解为现代智能手机里的"应用商店",但它比应用商店更底层,更强大。
它负责全自动的完成软件的搜索、下载、安装、更新、配置和卸载。
为了实现这些功能,它依赖于以下几个核心概念:
- 软件包: 就像是一个打包好的快递箱,里面包含了软件编译好的可执行文件、配置文件、文档说明以及最重要的------元数据(记录了这个软件的名字、版本、以及它需要依赖哪些其他软件)。
- 软件源: 简称"源",相当于云端的巨型仓库。软件包管理器会通过网络连接到这些官方或第三方的镜像服务器,从中下载你需要的软件。
- 依赖关系: 软件A可能需要软件B的某个库才能运行,这就叫依赖。软件包管理器的最伟大之处,就在于它能自动计算并下载所有缺失的依赖项。
1.2 为什么我们需要它
我们需要软件包管理器的核心驱动力有三点:
- 解决依赖关系: 避免了手动寻找和安装各种底层动态链接库(
.so文件)的痛苦。 - 集中化的更新: 所有的软件更新都可以通过一条命令完成(比如:
yum(apt) upgrade)。 - 干净的系统状态: 当你卸载一个软件时,管理器知道哪些文件是属于它的,哪些依赖已经再被其他软件使用,从而把它们清理干净,不留系统垃圾。
1.3 常用的软件包管理器
1.3.1 apt
用于 Ubuntu等 ,能够连接网络软件源,自动解析和解决依赖关系。
1.3.2 yum
用于 CentOS、Fedora 等。
1.4 yum 或 apt 的具体操作(以下内容以 yum 为例)
1.4.1 查看软件包
通过 yum list 命令可以罗列出当前一共有哪些软件包。
由于包的数量非常之多,这里不做演示。
bash
yum list
1.4.2 安装软件
通过 yum,我们可以安装一个趣味命令。
bash
sudo yum install sl
当出现下面图片中的 Complete 就代表安装完成了。

输入这段趣味命令sl时,会出现一个火车,提示用户拼写 ls 错误。

1.4.3 卸载软件
卸载软件我们使用 remove。
bash
sudo yum remove sl
跟安装一样,出现 Complete 代表卸载成功。

二、vim 编辑器
2.1 vim 的概念
vi\vim的区别简单来说,它们都是多模式编辑器,不同的是 vim 是vi 的升级版本,它不仅兼容 vi 的所有指令,而且还有一些新的特性在里面。
vim 通常有三种模式:
- 命令模式: 控制屏幕光标的移动,字符、字、行的删除,移动复制某区段及进入插入模式(按
i)下,或者到底行模式(按:)下。 - 插入模式: 只有在插入模式下才可以做文字输入,按
Esc可以回到命令模式。 - 底行模式: 进行文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。
下图是三种模式之间互相切换的示意图:

2.2 vim 的基本操作
输入下面命令进入 vim:
bash
vim [文件名]
2.2.1 命令模式
移动光标:
i: 进入插入模式并从光标当前位置进行输入。a: 进入插入模式并从光标当前位置的下一个位置进行输入。o: 进入插入模式并从光标当前位置另起一行进行输入。h\j\k\l: 控制光标进行左、下、上、右移动一格。gg: 控制光标到文本的开头位置。G: 控制光标到文本的末尾位置。^: 控制光标到所在行的行首。$: 控制光标到所在行的行尾。w: 控制光标跳到下个单词的开头。e: 控制光标跳到下个单词的末尾。b: 控制光标回到上个单词的开头。[数字]l: 控制光标到该行的第[数字]个位置。Ctrl + b: 屏幕向后移动一页。Ctrl + f: 屏幕向前移动一页。Ctrl + u: 屏幕向后移动半页。Ctrl + d: 屏幕向后移动半页。
删除文字:
x: 删除光标所在位置的一个字符。[数字]x: 删除光标所在位置后面的[数字]个字符(包括自己在内)。X: 删除光标所在位置前面一个字符。[数字]X: 删除光标所在位置前面的[数字]个字符(包括自己在内)。dd: 删除光标所在行。[数字]dd: 从光标所在行开始删除[数字]行。
复制:
yw: 将光标所在之处到字尾的字符复制到缓冲区中。[数字]yw: 复制[数字]个字到缓冲区。yy: 复制光标所在行到缓冲区。[数字]yy: 表示复制从光标所在行所在的该行往下[数字]行文字。p: 将缓冲区内的内容粘贴到光标所在位置。
替换:
r: 替换光标所在处的字符。R: 替换光标所在之处的字符,直到按下Esc为止。~:进行大小写切换。
撤销:
u: 撤销上一次的操作。Ctrl + r: 恢复撤销。
更改:
cw: 更改光标所在处的字符到字尾处。c[数字]w: 更改[数字]个字符。
跳到指定行:
Ctrl + g: 列出光标所在行的行号。[数字]G: 移动光标到文章的第[数字]行的行首。
2.2.2 底行模式
在命令模式按 : 进入底行模式。
set nu: 列出文件的所有行号。[数字]: 跳到文件的第[数字]行。/[关键字]: 向下查找关键字 ,可以按n向下来连续查找。?[关键字]: 向上查找关键字 ,可以按n向上来连续查找。w: 将文件保存起来。q: (quit)退出文件 。如果无法退出,加个!强制退出。wq: 在退出时保存文件。vs [文件名]: 可以同时编辑多个文件,要进行文件切换时按Ctrl + w + w。
2.2.3 视图模式
在命令模式下按 Ctrl + c进入视图模式。
按h / j / k / l进行光标移动,光标所覆盖的范围我们就可以进行输入替换。
按 I进入插入模式进行输入,输入后按ESC回到命令模式,光标所覆盖的范围也被我们输入的内容所替换了。
2.3 vim的配置
在目录 /etc/ 下,有个名为 vimrc 的文件,这是系统中公共的 vim 配置文件,对所有用户都有效。

而在每个用户的根目录下,都可以建立私有的配置文件,命名为 .vimrc 。
然后执行:
bash
vim .vimrc
进入后我们就可以输入内容进行 vim 配置。
具体的配置选项可以根据个人喜好进行搜索配置。
对于"懒人"可以在 shell 中输入下面的指令进行一站式配置(只支持 CentOS,且不建议在 root 账户下执行)。
bash
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
三、gcc / g++ 编译器
3.1 编译时的四个阶段
没深层了解过编译的人,可能觉得编译是一个"点一下按钮的过程",但其实在底层,一段代码要变成一个可执行程序,需要经历四个阶段。
3.1.1 预处理
这个阶段主要是处理那些以 # 开头的指令。
-
动作: 宏替换、头文件展开、条件编译、去注释。
-
操作: 使用
-E选项。告诉gcc:预处理完了就停下来,别往下做了。 -
命令:
bashgcc -E code.c -o code.i -
结果: 生成
.i文件。你会发现这个文件变得特别大,因为头文件都被塞进来了。
3.1.2 编译
这时编译器会检查你的语法对不对。
-
动作: 检查代码规范性、语法错误,确定无误后将代码翻译成汇编语言。
-
操作: 使用
-S选项。 -
命令:
bashgcc -S code.c -o code.s -
结果: 生成
.s文件,里面全是mov,push,add之类的汇编指令。
3.1.3 汇编
电脑看不懂汇编,这一步就是将它转换为 1和 0。
-
动作: 把汇编指令转换为机器可以识别的二进制目标代码。
-
操作: 使用
-c选项。 -
命令:
bashgcc -c code.s -o code.o -
结果: 生成
.o二进制文件(Object File)。这时候打开这个文件就是一堆乱码。
3.1.4 链接
这是最后一步,你的程序可能调用了别人写的库(比如 printf)。
-
动作: 将所有
.o文件和系统库文件整合在一起,生成最终的可执行文件。 -
命令:
bashgcc code.c -o code -
结果: 最终得到
code(或者是 Windows 下的.exe),这时候就可以直接运行它了。
如果你觉得这四个选项很难记,可以试试这个
Esc记忆法(对应电脑键盘左上角的Esc键):
-E:对应.i(预处理)-S:对应.s(编译)-c:对应.o(汇编)在实际开发中,我们通常直接运行
gcc code.c -o code一步到位。但在调试或研究底层逻辑时,分布编译是有必要的。
当我们将以上代码都执行一次,文件中就会有以下图片中的各种文件。

最后一步进行链接然后执行文件就可以了。

3.2 动态链接 / 静态链接
上文我们 .o 目标文件已经生成了,为什么还要链接一下呢?
那么接下来我们就来拆解一下编译过程最关键的一步:链接 ,以及它背后的动态链接 和静态链接。
3.2.1 为什么要链接
想象一下,你在写C语言时用了 printf ,但你的 .c 文件里只有 #include<stdio.h>(这只是个声明),并没有 printf 具体怎么实现的二进制代码。
链接的作用 就是去系统库里找到 printf 的实现代码,把它和你写好的 .o 文件连接在一起,变成一个完整的可执行程序。
在 Linux 世界里,链接分为两种派系,它们各有优劣:
3.2.2 静态链接
-
原理: 把库文件的代码全部拷贝到你的可执行文件中。
-
后缀: Linux 下通常是
.a,Windows 下是.lib。 -
优点:
- 独立性强: 生成的程序不依赖外部库,带到哪跑到哪。
2.速度快: 运行时不需要去找库,自行效率稍高。
- 独立性强: 生成的程序不依赖外部库,带到哪跑到哪。
-
缺点:
- 浪费空间: 如果 100 个程序都静态链接了
printf,那磁盘和内存里就有 100 份printf的副本。 - 更新麻烦: 库文件一旦升级,所有相关的程序都得重新编译。
- 浪费空间: 如果 100 个程序都静态链接了
3.2.3 动态链接
- 原理: 程序运行时并不包含库代码,而是存了一个地址。只有在程序运行到那一行,才会去共享库调用。
- 后缀: Linux 下通常是
.so,Windows 下是.dll。 - 优点:
- 节省资源: 多个程序可以共享内存里的同一库。
- 维护方便: 升级库文件,不需要重新编译程序。
- 缺点: 依赖环境,如果目标电脑上没装过对应的
.so库,程序就跑不起来。
说白了,静态链接 就像是出门旅游自带所有的干粮;
动态链接就像是拿着美团团购券去目的地扫码吃饭。
3.3 查看链接方式
-
file命令:

像这样输入
file code,就会看到dynamically linked的字样,说明就是动态链接。 -
ldd命令:

相这样输入
ldd code,它就会列出这个程序运行所需的所有动态库路径。一般我们的云服务器,C / C++的静态库并没有安装,可以采用如下方法安装:
bash# CentOS yum install glibc-static libstdc++-static -y
四、自动化构建------ makefile / Makefile
(
makefile和Makefile是一个意思,m是大写还是小写都可以。)
4.1 什么是 make / Makefile
Makefile: 是一个文本文件,它定义了一系列的规则,告诉编译器哪些文件先编译,哪些后编译,那些需要重新编译。make:是一个命令工具,用来解释并执行Makefile中的指令。
4.2 依赖关系与依赖方法
一个 Makefile 的基本逻辑由两部分组成:
- 依赖关系:你要生成谁(目标文件),它由谁组成(源文件)。
- 依赖方法:具体执行什么命令来生成它。
bash
code:code.c
gcc -o code code.c
第一行就是依赖关系,code 的生成依赖于 code.c,第二行就是依赖方法,code.c 是执行什么指令生成 code。
- 在依赖方法前面的必须是
Tab键,不能是空格,否则会报missing separator错误。make默认只执行Makefile中的第一个目标。- 如果
Makefile中写了依赖某个文件,但磁盘上找不到,make会直接报错退出。
4.3 .PHONY

这是 makefile 里的一个代码。

当我们执行两次 make指令时,在第二次执行就会出现 make: 'code' is up to date的提示,但是我同样执行了两次 clean指令,并没有出现像 make指令一样的提示,这是为什么?
一般我们这种 clean的目标文件,我们将它设置为伪目标 ,用 .PHONY修饰。
伪目标的特性:可以总是被执行。
那么 .PHONY的工作原理是什么呢?
我们来看下面这张图片:

我们知道:文件 = 内容 + 属性
注意一下图片中黄框圈的内容:
Modify:内容变更,时间更新。Change:属性变更,时间更新。Access:指文件最近一次被访问的时间。
所以当我们更改文件的内容时,Modify的时间就会更改,.PHONY就是根据源文件和可执行文件的Modify的时间进行对比 ,如果源文件的修改时间早于可执行文件,说明代码没动过,make为了效率就不会重复编译。
这就是为什么我们要用.PHONY。被它修饰的目标(如clean)会忽略时间戳对比,无论如何都会被执行。
4.4 make 的推导机制
bash
code:code.o
gcc code.o -o code
code.o:code.s
gcc -c code.s -o code.o
code.s:code.i
gcc -S code.i -o code.s
code.i:cdoe.c
gcc -E code.c -o code.i
看上面这段代码,如果要生成 code,它发现需要 code.o,但是没有 code.o,它就会向下寻找生成code.o的规则。
这种层层查找,直到找到最原始的 .c文件并开始逆向执行的过程,就是make的推导机制。
4.5 扩展语法
bash
BIN=code.exe # 定义变量
CC=gcc
#SRC=$(shell ls *.c) # 采用shell命令行方式,获取当前所有的.c文件名
SRC=$(wildcard *.c) # 或者使用wildcard函数,获取当前所有的.c文件名
OBJ=$(SRC:.c=.o) # 将SRC的所有同名.c替换成为.o后形成目标文件列表
LFLAGS=-o # 链接选项
FLAGS=-c # 编译选项
RM=rm -rf # 引入命令
$(BIN):$(OBJ)
@$(CC) $^ $(LFALGS) $@ # $@:代表目标文件名,$^:代表依赖文件列表
@echo "linking ...$^ to $@"
%.o:%.c # %.c:展开当前目录下的所有.c文件,%.o:同时展开同名.o
@$(CC) $(FLAGS) $< # %<:对展开的依赖.c文件,一个一个的交给gcc
@echo "compling ...$< to $@" # @:不回显命令
.PHONY:clean
clean:
$(RM) $(OBJ) $(BIN) # $(RM):替换,用变量内容替换它
.PHONY:test
test:
@echo $(SRC)
@echo $(OBJ)
五、版本控制器 Git
5.1 什么是 Git
作为一位开发者,你是否经历过:代码改乱了想回退找回却找不到备份?由于不小心删掉一个文件导致整个工程崩溃?或者和队友合作时,代码覆盖来覆盖去,最后谁也跑不通?
这时候,Git就像救世主一样降临了。
Git是一个分布式的版本控制系统。
你可以把它想象成一个功能极其强大的"云存储"系统。它不仅能记录你每一次代码的改动(谁改的、改了什么、什么时候改的),还能让你随时随地"穿越"回代码地任何一个历史版本。
5.2 Git 三大核心分区
- 工作区: 就是你电脑里实实在在能看到的文件夹,你在这里敲代码、删文件。
- 暂存区: 这是一个"缓冲地带"。你改好了代码,先用
git add把它放进暂存区,表示:"这一版我打算提交了"。 - 版本库: 当你执行
git commit,暂存区的内容就会被正式存入版本库。这里记录了项目的完整历史。
5.3 使用 Git
Git指令:
| 命令 | 作用 | 博主白话 |
|---|---|---|
git clone [url] |
克隆远程项目 | "把别人的代码库原封不动的搬到我电脑上。" |
git init |
初始化仓库 | "从现在起,Git你给我盯着这份文件夹!" |
git add [文件名] |
添加到暂存区 | "这些改动我都确认过了,准备打包。" |
git commit -m "消息" |
提交到本地仓库 | "存个档,顺便写个备注:我修改了哪个Bug。" |
git status |
查看当前状态 | "看下还有哪些代码没存,心里有个底。" |
git log |
查看历史记录 | "翻翻我的'代码笔记',看看以前都干了啥。" |
git push |
推送到远程 | "把我的本地存档传到GitHub / Gitee上去。" |
六、调试器 gdb / cgdb
6.1 -g 选项
程序的发布方式有两种,debug和release模式,Linux gcc/g++出来的二进制程序,默认是release模式。
要用gdb调试,必须在源代码生成的二进制程序的时候,加上-g选项,如果没有添加,程序无法被调试。只有加上这个参数,编译器才会把调试信息(比如变量名、行号等)塞进可执行程序。
6.2 gdb 和 cgdb
6.2.1 gdb
gdb虽然强大,但它是纯命令行的。你敲一行命令它动一下,最大的问题是你无法直观地看到完整的源代码,很容易"迷路"。
6.2.2 cgdb
简单来说,cgdb是gdb的一个轻量级可视化前端。它不仅完美继承了gdb所有的底层逻辑和命令,还附带了一个极度舒适的代码可视化分屏窗口。
-
特点
- 分屏显示(自带语法高亮) :屏幕上半部分显示你的代码,下半部分是
gdb的命令交互区。当前运行到了哪一行,代码窗口里会有一个高亮的箭头指着它。 - 纯键盘的
vim体验 :cgdb的操作逻辑深度致敬了vim,完全不需要鼠标,双手不用离开键盘主键盘区。
- 分屏显示(自带语法高亮) :屏幕上半部分显示你的代码,下半部分是
-
模式切换
用好
cgdb的核心,在于理解它的两个窗口/两种模式 。启动命令和gdb一样:cgdb ./code。ESC键------进入"代码窗口"(上方)
按下ESC键后,光标会跳到上面的代码区。
可以用j / k来上下滚动浏览代码。
找到你想打断点的那一行,直接按下空格键,断点就打上了,(代码行旁会多出一个红色标记),再按一次空格即可取消。i键------进入"命令窗口"(下方)
按下i(insert)键后,光标回到下方的gdb交互区。
6.3 常见指令
l(list):显示源代码,从上次位置开始,每次列出10行。l[函数名]:列出指定函数的源代码。l[文件名:行号]:列出指定文件的源代码。r(run):从程序开始连续执行。n(next):单步执行,不进入函数内部,相当于逐过程F10。s(step):单步执行,进入函数内部,相当于逐语句F11。b(break) [文件名:行号]:在指定行号设置断点。b[函数名]:在函数开头设置断点。info b:查看当前所有的断点信息。finish:执行到当前函数返回,然后停止。p(print):打印表达式的值。p[变量]:打印指定变量的值。set var[变量=值]:修改变量的值。c(continue):从当前位置开始连续执行程序。d(delete)breakpoints:删除所有断点。d(delete)breakpoints n:删除序号为n的断点。disable breakpoints n:禁用序列号为n的断点。enable breakpoints n:启动序列号为n的断点。info breakpoints:查看当前设置的断点列表。display[变量名]:跟踪显示指定变量的值。undisplay[编号]:取消对指定编号的变量的跟踪显示。until n:执行到n行。bt(backtrace):查看当前执行栈的各级函数调用及参数。info locals:查看当前栈帧的局部变量值。watch[变量名] :执行时监视一个表达式(如变量)的值。如果监视的表达式在程序运行期间的值发生变化,gdb会暂停程序的执行,并通知使用者。b[行号/函数名]if[条件表达式]:添加条件断点,如果条件表达式成立,则调试停止。condition[断点编号] [条件表达式]:给已有的断点追加 / 修改条件。quit:退出gdb调试器。
好了,到这里我们的Linux中基本开发工具的使用也讲完了,感谢大家的观看!!!
