linux (4) 基础开发工具
前言:
大家周末愉快呀~今天来整理一下linux中用到的一些开发工具,不过我们会在这里说的主要是vim,gcc,makefile这三个。
正文:
vim编辑器:
模式切换:

自己画的图,虽然丑了些,不过我们还是可以发现:
①:无论在什么模式,按ESC就可以切换到命令模式
②:无需额外记忆成本,切换时先回到命令模式,然后再切换到想要的模式
命令模式:
指令:
//vim所有模式不互通指令,命令模式是主要,绝大多数快捷键,移动光标,进入其他模式的快捷键全都属于命令模式
移动光标:
①.可以通过h(←) , j(↓) , k(↑) , l(→)来移动
②.ctrl+b/f(u/d): 屏幕向后/前滚动半(一)页
③.shift+$:移动到该行末尾
④.shift+^:移动到该行开头(空格不算)
⑤.w e b:w为跳转到下个单词的开头,e为跳转到下个单词的末尾,b为跳转到上个单词的开头
⑥.n(数字)+l: 向该行后面跳转n个字符
⑦. shift+g:移动到全文末尾
⑧. gg:移动到全文开头
删除文字:
①.x:删除光标所在位置的第一个字符
②.n+x:删除从光标起数的n个字符
③.X:删除光标所在位置前的一个字符(例如int,光标在t上,删除n)
④.n+X:删除光标所在位置前的n个字符
⑤.dd:删除光标所在行
⑥.n+dd:删除从光标数n行
复制:
①.yw:复制光标开始到该单词末尾的字符
②.n+yw:复制n个单词
③yy:复制光标所在行
④.n+yy:复制从光标所在行开始往下的n行
⑤.p:将缓冲区内的字符贴到光标所在位置
替换:
①.r:替换光标所在位置的字符
②.shift+r:进入替换模式,替换光标所到之处的字符(替换模式内容少,在这里就一笔带过了)
撤销:
①.u:撤销上一次命令,多次按u可撤销多次
②.ctrl+r:恢复撤销,只针对u,不能撤销别的命令
跳转:
①. n+G:跳转到第n行开头
底行模式:
指令:
跳转:
①. n:只需输入一个数字,按回车就可以跳转到第n行
查找:
①./c,从光标所在行跳转一行开始向下寻找c,并且同一行遍历顺序从左往右查找,按n寻找下一个c.
②.?c,从光标所在行向上跳转一行开始向上寻找c,同一行遍历顺序从右往左,按n寻找下一个c
这里有一个很诡异的现象:经过我自己在的演示,我发现如果用?来查找一个字符时候,例如这个例子,我把光标放在25时,开始搜索r,奇怪的是,r居然停在了21行的第一个r上(最左边的),而不是最后那个r上。而当我按回车向下一行,到了22行,我再按n,居然就到了21行的最后一个r(最右边的r上)

保存:
①. w:输入w就可以将文件保存起来
退出:
①. q:直接退出vim
②. wq:保存并退出,一般推荐用这个
如果无法完成,可以在后面加上!强制退出/保存并退出
插入模式:
//本质就和我们写代码差不多,也没什么指令,所以一笔带过了
视图模式:
指令:
①.d: 删除选中的内容
②.y:复制选中区域
③.p: 在光标位置粘贴
④.c: 删除所选内容,自动进入插入模式
例子:
加入注释:

①.进入视图模式:
②. 选中想添加的行

③:按shift+i切换到插入模式,输入//

④:按ESC回到命令模式

gcc编译器:
编译的理解:
我们知道,编译分为四步,预处理,编译,汇编,链接。
那么这四步,分别干了什么?我们一个一个来讲:
预处理:
例子:gcc –E hello.c –o hello.i
①. 宏替换
②. 删注释
③. 展开头文件
④. 条件编译
别的都好理解,条件编译是什么?
举个例子:
保护头文件:
#ifndef __HEAD_H
#define __HEAD_H
void func();
#endif
//由于宏里面没有{},所以依靠endif划定范围,处在ifdef与endif之间的代码,才受宏的控制
编译:
例子:gcc –S hello.i –o hello.s
汇编:
例子:: gcc –c hello.s –o hello.o
小demo:
这里有一个问题,为什么要转化成汇编语言?为什么要转化成二进制机械码?我们在这里讲讲这个问题:
首先,在古早时期,老手子是直接通过二进制进行写代码的,但这样太麻烦了,而且二进制,本身就不太适合人类读;所以为了阅读性,有人就发明了汇编语言,那发明了汇编语言后,可惜的是计算机只能识别二进制,不能识别汇编语言,所以在运行的时候,就要将汇编语言翻译为二进制语言,需要用到编译器,那么编译器从哪来?
这里有一个悖论,如果我用汇编写一个编译器,那这个编译器,它底层是汇编,二进制不认识,所以跑不起来,但是,我又需要一个编译器来把汇编语言转化为二进制语言,怎么办?
先用二进制写一个编译器,然后这个编译器就可以认识汇编语言,然后通过这个编译器,我再用汇编语言写一个编译器,这就实现了汇编语言写的编译器,这个过程,我们称之为编译器自举。
尽管如此,汇编语言还是太过生涩,所以后来又出现了C语言这些语言,我们就以C语言为例。那么,我们是要把C语言翻译成汇编语言,再翻译成二进制语言;还是直接把C语言翻译成二进制语言?显而易见,前者更加简单,工作量小,且安全。所以我们又进行了编译器自举,从而出现了从C语言到汇编语言的编译器
最后,我们要说的是什么呢?
结论:C语言-->汇编语言-->二进制语言,二进制语言才是计算机可以真正识别的!!!
链接:
有个问题:我既然 .o 文件,都叫可执行文件了,也翻译成了二进制,那么是不是可以直接运行了?
[tsx@VM-0-10-centos ~]$ touch haha.c
[tsx@VM-0-10-centos ~]$ vim haha.c
[tsx@VM-0-10-centos ~]$ cat haha.c
#include<stdio.h>
int main()
{
printf("好想玩原神");
return 0;
}
[tsx@VM-0-10-centos ~]$ gcc -c haha.c
[tsx@VM-0-10-centos ~]$ tree
.
|-- dira
| |-- 2026_7_18
| | |-- hehe.c
| | `-- hello.txt
| |-- dir1
| | |-- 7-23
| | |-- dir1
| | | `-- dir2
| | | |-- dir3
| | | |-- hello.txt
| | | `-- xixi
| | |-- dirb
| | |-- f267fea1643a85f1d6140c288823b506.jpg
| | |-- hello.txt
| | `-- minchao.c
| `-- yuanshen.txt
|-- haha.c
|-- haha.o
`-- install.sh
8 directories, 11 files
[tsx@VM-0-10-centos ~]$ ./haha.o
-bash: ./haha.o: Permission denied
[tsx@VM-0-10-centos ~]$ chmod u+x haha.o
[tsx@VM-0-10-centos ~]$ ./haha.o
-bash: ./haha.o: cannot execute binary file
当然不是!!!!!!
为什么?因为printf这些函数,是你自己写的吗???当然不是
这时候就有个问题:我包含头文件了啊?为什么不可以
头文件中只包含函数声明,具体的函数实现在库中
库:
库分为两种,静态库和动态库
有什么区别呢?
静态链接:我直接把需要的函数,从静态库(.a)中拷贝过来,这样链接完后我就独立了,无需库就能完成调用
动态链接:我得到一个库的地址,我在使用需要的函数时,我去动态(.so)里找,即使链接完后,依然依赖库
优缺点对比:
静态链接:消耗的空间大,启动时略微快些
动态链接:消耗的空间小,启动时略微慢些
那我们推荐哪个?动态链接!
因为相比之下,静态链接消耗的空间是动态链接的几十上百倍
[tsx@VM-0-10-centos 2026_7_18]$ gcc haha.c -o haha_static -static
[tsx@VM-0-10-centos 2026_7_18]$ gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha
|-- haha.c
`-- haha_static
0 directories, 3 files
[tsx@VM-0-10-centos 2026_7_18]$ ll
total 860
-rwxrwxr-x 1 tsx tsx 8360 Jul 25 15:09 haha
-rw-rw-r-- 1 tsx tsx 74 Jul 25 14:50 haha.c
-rwxrwxr-x 1 tsx tsx 861216 Jul 25 15:09 haha_static
如果没安装静态库,可以输入这个:
sudo yum install glibc-static
总而言之:链接就是要把所需函数对应的实现找到,并且与我的文件产生关联
make/makefile
简要介绍:
make 是工具;Makefile 是我写的配置脚本,用来指导 make 怎么编译代码
使用方法:
我们要用makefile,就要先知道两个概念,依赖关系和依赖方法:
举例理解:比如说你有个老师叫武斌,你想请假,就和武斌说:武斌啊,我是你学生!
武斌感到很奇怪,把电话挂断了......
这时,你告诉武斌说我是你的学生,这是我们之间的关系,这就是依赖关系。而我要依赖他,我要干嘛?
于是,我又给武斌打电话,我说:
武斌啊,我是你的学生!
给我请个假呗;
这时,武斌就知道了,哦~原来他想找我请假,于是他就给我开了假条,我就达成了我的目的
这里的“给我请个假”就是我的依赖方法。
说完依赖关系和依赖方法,我们接下来说说make 和 makefile,
makefile是要我自己写的,make是指令
①. 在终端输入 make,make 工具会自动在当前目录寻找 Makefile /makefile
②. 如果找不到这个文件,直接报错:make: *** No targets specified and no makefile found. Stop.
我们接下来用这个例子来讲解:
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
`-- haha.c
0 directories, 1 file
[tsx@VM-0-10-centos 2026_7_18]$ cat haha.c
#include<stdio.h>
int main()
{
printf("好想玩原神");
return 0;
}
紧接上图
我们往makefile文件里面写入
haha:haha.c
gcc haha.c -o haha
注意:这里第二行开头是一个tab的距离
[tsx@VM-0-10-centos 2026_7_18]$ touch makefile
[tsx@VM-0-10-centos 2026_7_18]$ vim makefile
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha
|-- haha.c
`-- makefile
0 directories, 3 files
[tsx@VM-0-10-centos 2026_7_18]$ ll
total 20
-rwxrwxr-x 1 tsx tsx 8360 Jul 25 15:28 haha
-rw-rw-r-- 1 tsx tsx 74 Jul 25 14:50 haha.c
-rw-rw-r-- 1 tsx tsx 32 Jul 25 15:27 makefile
[tsx@VM-0-10-centos 2026_7_18]$ ./haha
好想玩原神[tsx@VM-0-10-centos 2026_7_18]$
我们就发现,成功打印出了“好想玩原神”
但我如果要清理呢?
我们往makefile中写入:
haha:haha.c
gcc haha.c -o haha
.PHONY:clean
clean:
rm -rf haha
如此:我们再输make clean 就可以清除了
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha
|-- haha.c
`-- makefile
0 directories, 3 files
[tsx@VM-0-10-centos 2026_7_18]$ make clean
rm -rf haha
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha.c
`-- makefile
0 directories, 2 files
[tsx@VM-0-10-centos 2026_7_18]$
.PHONY:
这是什么?
在讲这个之前,我们要先讲一个小东西:
三个时间:
命令:stat
[tsx@VM-0-10-centos 2026_7_18]$ stat haha.c
File: ‘haha.c’
Size: 74 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 656881 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1001/ tsx) Gid: ( 1001/ tsx)
Access: 2026-07-25 15:08:43.889582547 +0800
Modify: 2026-07-25 14:50:54.341216280 +0800
Change: 2026-07-25 15:06:39.482960143 +0800
Birth: -
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha.c
`-- makefile
0 directories, 2 files
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ stat haha
File: ‘haha’
Size: 8360 Blocks: 24 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 795951 Links: 1
Access: (0775/-rwxrwxr-x) Uid: ( 1001/ tsx) Gid: ( 1001/ tsx)
Access: 2026-07-25 15:40:31.910107278 +0800
Modify: 2026-07-25 15:40:31.898107218 +0800
Change: 2026-07-25 15:40:31.898107218 +0800
Birth: -
①access时间:这个时间指的是最后访问文件的时间,但是!!!!我们会发现,有时候我们访问文件之后,access时间没变,这是为什么?
它是一个文件属性,如果我频繁的看文件,那么我就要频繁的把这个文件属性写进磁盘,很浪费效率,所以呢,一般是规定访问几次以后,才进行修改一次
②.modify时间:这个时间指的是修改文件内容的时间,我们在说makefile时候就看这个
③. change时间:这个时间指的是修改文件属性的时间,但我们发现,很多情况下,我改一个文件内容,change时间也会改变,为什么呢?
因为,修改文件内容之后,文件大小会发生改变,这也是文件属性!!!!所以change时间也会变
细说PHONY
如果我们已经编译了haha.c ,我再编一次,会怎么样?
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha
|-- haha.c
`-- makefile
0 directories, 3 files
[tsx@VM-0-10-centos 2026_7_18]$ make
make: `haha' is up to date.
up to date?这是什么意思
意思是,haha这个文件它的modify时间已经在haha.c之后,那么就不让它继续编了
那如果我改一下haha.c呢?
我改成这样
#include<stdio.h>
2 int main()
3 {
4 printf("好想玩原神");
5 printf("好想玩原神");
6 printf("好想玩原神");
7 printf("好想玩原神");
8 printf("好想玩原神");
9 return 0;
10 }
[tsx@VM-0-10-centos 2026_7_18]$ stat haha.c
File: ‘haha.c’
Size: 190 Blocks: 8 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 656881 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1001/ tsx) Gid: ( 1001/ tsx)
Access: 2026-07-25 15:49:51.964960826 +0800
Modify: 2026-07-25 15:49:51.961960811 +0800
Change: 2026-07-25 15:49:51.961960811 +0800
Birth: -
[tsx@VM-0-10-centos 2026_7_18]$ stat haha
File: ‘haha’
Size: 8360 Blocks: 24 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 795951 Links: 1
Access: (0775/-rwxrwxr-x) Uid: ( 1001/ tsx) Gid: ( 1001/ tsx)
Access: 2026-07-25 15:40:31.910107278 +0800
Modify: 2026-07-25 15:40:31.898107218 +0800
Change: 2026-07-25 15:40:31.898107218 +0800
Birth: -
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ tree
.
|-- haha
|-- haha.c
`-- makefile
0 directories, 3 files
[tsx@VM-0-10-centos 2026_7_18]$ ./haha
好想玩原神好想玩原神好想玩原神好想玩原神好想玩原神[tsx@VM-0-10-centos 2026_7_18]$ stat haha
File: ‘haha’
Size: 8360 Blocks: 24 IO Block: 4096 regular file
Device: fd01h/64769d Inode: 795951 Links: 1
Access: (0775/-rwxrwxr-x) Uid: ( 1001/ tsx) Gid: ( 1001/ tsx)
Access: 2026-07-25 15:50:19.910103033 +0800
Modify: 2026-07-25 15:50:18.545096088 +0800
Change: 2026-07-25 15:50:18.545096088 +0800
Birth: -
由此见得:对于没有被.PHONY修饰的,必须满足modify时间的约束,才可以执行
所以我们称.PHONY修饰的称之为“总是被执⾏”
只要我把makefile改成
.PHONY:haha haha:haha.c
gcc haha.c -o haha
.PHONY:clean
clean:
rm -rf haha
那么
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
[tsx@VM-0-10-centos 2026_7_18]$ make
gcc haha.c -o haha
这样就没有问题了
一些语法:
cat makefile
bin=haha
cc=gcc
src=$(wildcard *.c)
obj=$(src:.c=.o)
lianjie=-o
bianyi=-c
shan=rm -rf
$(bin):$(obj)
$(cc) $(lianjie) $@ $^
$(obj):$(src)
$(cc) $(bianyi) $<
.PHONY:clean
clean:
$(shan) $(obj) $(bin)
①. 普通语法声明:例如bin=haha
②. wildcard文件搜索函数:自动匹配当前目录中所有指定文件
③. $:起到一个展开变量内容的作用
④.变量后缀替换:obj=$(src:.c=.o),把src中的所有.c文件替换成.c文件
即为$(变量:旧后缀=新后缀)
⑤.$@: 代表当前的目标文件
⑥.$^: 代表当前规则全部的依赖
⑦.$<: 把依赖一个一个的展开
推导过程:
makefile寻找依赖关系时,要求可以从依赖推到目标,如果当前的依赖关系暂时不可以连通,那么我就把当前依赖关系压栈,直到目标和依赖可以串起来,当然,如果最后串不起来,那我就不工作咯
尾:
写的累死我了......这一篇字数很多呢,图是自己画的,指令是自己敲的,字也是一个一个打的,累死了......总之希望能够帮到大家,嗯......吃什么呢?
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)