【Linux】基础开发工具的简单使用——yum/vim/gcc/gdb/make/git

yum —— 软件包管理器

我们平时经常在手机或电脑(Windows)上的应用商店下载各种软件,点击下载,进度条就开始走,下载完成,我们的手机或电脑上就多了一个安装包,然后执行安装包就开始安装。

实际上,安装包很大,而软件商店APP却很小,这是为什么呢?

软件商店其实就是一个软件包管理器,通过网络建立起你和服务器之间的联系,你通过它来操作,它来帮你去服务器上下载软件包,下载完成之后再由你来执行安装。

Linux 下如果没有图形化界面,我们该怎么操作呢?

有一个古老的方法就是下载程序的源代码进行编译,得到可执行程序。但这样太麻烦了,为什么不能像应用商店那样,把程序打包起来放服务器上,通过应用商店来下载呢。

所以 yum 就应运而生了。

下面简单介绍一下 yum 最简单的三种用法。这些都有一个大前提,那就是网络必须是畅通的

yum list —— 查看软件包

输入yum list 指令之后会以 list 的形式将能下载的软件包列出来:

image-20221013191010578

打印出的信息分三列。

第一列是软件包的名称,其中像 x86_64 表示这是64位系统的安装包,32位系统的安装包后缀为 i686 ,下载时要和系统匹配。

第二列则分别是主版本号.次版本号.源程序发行号-软件包的发行号.主机平台,其中 el7 表示的是 CentOS7 或者是 Redhat7 ,像 el6 表示的就是 CentOS6Redhat6

最后一列则是软件源,例如某个应用是来自小米应用商店。

而这个指令把所有能安装的包全都列出来了,

而我们要查找的不过是某一个,

所以我们需要的是按关键字检索,

所以 grep 就派上用场了:

image-20221013192503426


yum install —— 安装软件

通过命令 sudo yum install filename 即可安装软件,

但很多情况下我们都是以普通用户登录的,

而安装程序一般是要涉及系统层面的操作,

所以普通用户是没办法安装的,

需要切成 root 或通过 sudo 进行权限提升操作。

需要注意的是,yum 不能像我们的应用商店那样同时下载多个软件,只能一个个安装。

安装过程中可能会让输入 y/n 选项确认安装,-f 选项则可以跳过询问强行安装。

下面是一个简单的安装例子:

image-20221016181626988


yum remove —— 卸载软件

sudo yum remove filename

其中 sudo 是权限提升,因为卸载也要涉及系统层面的操作,所以需要权限提升。

可以加 -f 选项,是强制卸载的意思,中间就不会再有询问你是否继续卸载的提示。

filename 就是我们要卸载的文件名。

一个简单的卸载例子:

image-20221016181331212


vim —— 文本编辑器

首先明确一个概念,我们平时写代码是在编辑器上写的,编译代码那是编译器的事情。

vim 是基于 vi 编辑器,增添了许多新特性的一款强大的文本编辑器。

vim 有三种常用模式:正常模式(normal mode)、插入模式(insert mode)和底行模式(last line mode),也叫命令模式(command mode)。

一开始进入 vim 之后是正常模式:

image-20221016182403883

我们如果想写代码的话按 i 键或 insert 键进入插入模式才可进行正常写入:

image-20221016182508148

写完代码想要退出的话按用 esc 键回退到正常模式,然后 shift + : 进入底行模式:

image-20221016182723158

此时光标在底行,输入 wq 为保存退出,输入 w 为保存,输入 q 为退出, !q 表示强制退出。

以上是 vim 最基本最简单的编写代码的操作。

下面介绍一下正常模式下的一些操作方法。


正常模式

正常模式下我们是无法随意编辑的,需要按 i 键或 insert 键切入插入模式。

正常模式下我们也没办法直接退出,需要先回到正常模式,再进入底行模式输入相关命令。

所以可以把正常模式简单描述为一个二叉树的节点,插入模式和底行模式是这个节点的两个子节点。

而在正常模式下可以进行很多操作,下面简单介绍一些常用的操作:

  • 我们可以通过键盘上的上下左右键进行光标的移动,但原始的 vim 是通过小写字母模式下的 h、j、k、l 分别完成光标的 左、下、上、右 移动的。
  • shift + g:光标移动到文本的最后
  • gg:光标移动到文本的开头
  • $(可能需要配合 shift 键使用):光标移动到所在行的行尾
  • ^(可能需要配合 shift 键使用):光标移动到所在行的行首
  • w:光标移动到下一个单词的开头
  • e:光标移动到下一个单词的末尾
  • b:光标回退到上一个单词的开头
  • 数字n+shift+g:光标跳转到第n行的行首
  • x:删除光标处的字符
  • 数字n+x:删除光标所在位置往后的n个字符(包含自己)
  • shift+x:删除光标前面的一个字符
  • 数字n+shift+x:删除光标前面的n个字符
  • dd:删除光标所在行
  • 数字n+dd:删除光标所在行下面的n行(包含自己)
  • yw:赋值光标所在处到行尾的字符
  • 数字n+yw:复制光标所在处后n个字符
  • yy:赋值光标所在行
  • 数字n+yy:复制光标所在行下的n行
  • p:粘贴
  • 数字n+p:连续粘贴n次
  • u:撤销上一次操作
  • ctrl+r:撤销上一次撤销

另外,很多场景下可能还要用到批量化操作:

image-20221018103534352

对于批量化选择,可以在正常模式下用 ctrl + v 进入V-BLOCK 模式,然后通过 h、j、k、l 键进行上下左右移动完成批量化选择。

对于批量化注释,可以在选中要批量化操作的区域之后按 大写的i,然后敲下两个 // (针对C/C++),完成之后 esc 退出即可:

vim批量化注释

对于批量化删除,可以在选中区域之后,按 小写d 进行删除:

vim批量化删除

对于批量化复制,选中之后按 小写y 即可。


底行模式

esc 回退到正常模式下通过 shift+: 组合键可以进入底行模式。

在底行模式下也有诸多命令,这里简单介绍几种:

  • q:退出

  • q!:强制退出

  • w:保存

  • wq:保存退出

  • e filename:打开文件 filename 进行编辑

  • r filename:在当前文件中写入文件 filename 的内容

  • vs:再开一个窗口,窗口下仍为当前文件,通过大写的H、L完成两个窗口之间的切换

  • vs filename:再开一个窗口,窗口下为文件 filename ,通过大写的H、L完成两个窗口之间的切换

  • set nu:显示行号

  • s/old string/new string:将当前行第一个 old string 替换为 new string

  • s/old string/new string/g:将当前行的所有 old string 替换为 new string

  • %s/old string/new string/g:将当前文件中的所有 old string 替换为 new string

  • x1,x2s/old string/new string/g:将 x1x2 行的所有 old string 替换为 new string

  • 5,10 m 15:将5-10行的内容剪切到15行下面

  • 5,10 co 15:将5-10行的内容复制到15行下面


vim配置

在目录 /etc 下面有一个 vimrc 文件,在该文件中可以通过命令对 vim 进行配置,配置对所有用户都有效。

在每个用户的主目录下,也可以建立各自的 vimrc 文件,命名为 .vimrc ,用户可以在这个文件里面通过输入各种命令进行配置。

vim 的配置选项数不胜数,大家可以在网上多查一下,根据需要设置。


gcc/g++ —— C/C++编译器

现在我们写好了一个C/C++代码,该怎么把它变成一个可执行程序呢?

很简单,编译生成可执行程序就完事了。

Linux 提供的 gcc/g++ 编译器,从名字来看就知道,前者是编译C语言代码的,后者是编译C++代码的,当然因为C++兼容C语言,所以也能编C。

假如我写了一个 test.c 文件,直接 gcc test.c 编译,就能生成一个 a.out 可执行文件,这是 gcc 最简单的用法。

当然如果不想默认生成 a.out ,也可以自己指定,只需要加一个 -o 选项:gcc test.c -o test

但它的功能远不于此。

我们知道,C语言代码在生成可执行程序之前会经历预编译、编译、汇编、链接四个阶段。

至于四个阶段做了什么这里不是重点,就不祥谈了。

重点是我们可以通过 gcc 的一些选项观察到这些阶段。


预编译 —— -E 生成 .i 文件

经过预编译阶段会生成 .i 文件,我们可以通过 -E 选项,让编译器在执行完预编译阶段之后就停下来:gcc -E test.c -o test.i

image-20221018135809265

可以用 cat 指令查看一下 test.i ,看看编译器在预编译阶段做了些什么:

image-20221018140803469

一个十几行的代码变成了八百多行,实际上就是进行了头文件展开,当然还有宏替换和注释删除。


编译 —— -S 生成 .s 文件

经过编译阶段会生成 .s 文件,这时C语言代码就被翻译成了汇编代码。

我们可以通过 -S 选项,让编译器在执行完编译阶段后就停下来:gcc -S test.c -o test.s

image-20221018140321570

可以用 cat 指令查看一下确实是翻译成了汇编代码:

image-20221018140412502


汇编 —— -c 生成 .o 文件

汇编阶段就是把此前翻译得到的汇编代码再次翻译,生成机器可识别的二进制文件,文件后缀为 .o

我们可以通过 -c 选项让编译器执行完汇编阶段就停下:gcc -c test.c -o test.o

image-20221018141254991

我们可以使用 od 命令查看生成的 .o 文件,这里是以八进制展示的:

image-20221018141430886


链接

经过汇编生成的 .o 文件虽然是二进制语言,可以被机器识别,但仍无法执行:

image-20221018142045127

因为还缺少最后一步 —— 链接。

test.c 文件中,我们调用了 printf 函数,但这个函数我们并没有定义,头文件 stdio.h 中仅仅也是对函数进行了声明,那最后该函数是如何执行的呢?

这就是链接阶段所做的动作了。

链接,是实现程序和库的链接,而这里要链接的,就是C语言的函数库。

在目录 /usr/lib64 下有这样一个文件:

image-20221018143422666

这个实际上就是C语言的函数库,而这里面才有我们所调用的函数的实现。

而在链接阶段,gcc 会到这个系统默认的搜索路径下面去寻找 printf 函数的实现,这样我们的程序调用的 printf 才得以执行。

这就好比我写作业遇到不会的题了,就跑去翻习题详解,这就是一种链接,作业和答案的链接。


动态链接

这样的一种链接方式叫动态链接,执行程序时遇到第三方库的文件跑去库里找对应的实现,边运行边链接。

而动态链接的库就是动态库,动态库在 Windows 下一般是以 .dll 为后缀,也有部分以 .lib 为后缀,在 linux 下则是以 .so 为后缀,以 lib 为前缀,比如上面的 libc.so

很明显,printf 函数执行的时候我要去链接,而链接的这个过程实际上就减慢了执行效率,而且通过动态链接生成的程序可移植性也不好,如果机器上没有相应的动态库,那程序就无法运行。

当然,动态链接也有不少的优点。因为要跑去远程链接,所以要链接的文件信息和我的可执行程序是各自独立的,这样一来缩小了可执行程序的占用空间;二来降低了耦合度;三来方便了开发,写一个动态库可以让多个程序共用,而且程序后续的维护更新也不需要对程序进行二次编译,只需要更新一下动态库即可;四来实现了进程间的资源共享,进程链接时由于动态库已经被加载到了内存中,另一个进程同时链接时就不需要再次加载了。

gcc 如果不加以指定的话,生成的可执行程序默认就是动态链接的:

image-20221018145243235


静态链接

与动态链接相对的就是静态链接。

因为 gcc 默认生成的可执行程序是动态链接的,如果想改为静态链接则可以使用选项 -staticgcc test.c -o test -static

image-20221018145620240

我们这里因为没有对应的静态库所以就失败了。

C语言标准静态库的安装可以使用命令:sudo yum install glibc-static,这时再编译一下:

image-20221018154556356

这时我们观察到了一个现象,就是静态链接的程序比动态链接的程序大得多。

这是因为静态链接会把静态库和程序打包起来,程序执行时就不需要跑去动态库链接,因此程序就大得多。

这样做有什么好处呢?

因为不需要远程连接了,进程链接时不需要加载动态库了,执行效率会相对高,而且程序不依赖于库就可以执行,可移植性大大提高。

但这样也带来了不少缺点,程序的空间会大大增加,另外,当程序维护更新时,动态链接的程序直接更新动态库即可,而静态链接的程序更新后必须重新编译,降低了开发体验。

另外,静态库是以 .a 为后缀的。


除了上面介绍的几个选项,gcc 还有一个选项 -g

linux 默认生成的可执行程序是没办法调试的,相当于是 release 版本。

-g 选项是生成调试信息,就相当于在 debug 模式下编译,这样生成的程序是可以调试的。

以上介绍的所有选项,对 g++ 同样适用。


gdb —— C/C++调试器

上面说了,gcc 有一个 -g 选项是生成调试信息,有了这个调试信息我们就可以对程序进行调试,而 gdb 就是 linux 下的调试工具。

首先先生成具有调试信息的程序:

image-20221018155920873

可以看到程序的大小相比默认生成的程序要大,说明确实有调试信息。

下面就介绍一下 gdb 的使用。

  • gdb filename:开始调试程序:

image-20221018160901092

  • ctrl d 或 quit/q:退出调试

image-20221018160929802

  • list/l + 行号(可省略):打印源代码

image-20221018161145164

  • list/l + 函数名:列出指定函数的源代码

  • next/n:逐语句执行,遇到函数不会跳到函数内部

  • step/s:逐过程执行,遇到函数会跳转到函数内部

  • break/b + 行号:在指定行打断点

image-20221018161647149

  • info/i break/b:查看断点信息

image-20221018161752131

  • delete/d break/b num:删除断点num

image-20221018162453411

  • disable break/b num:禁用断点num

image-20221018162601001

  • enable break/b num:启用断点num

image-20221018162703043

  • print/p + 变量名:打印变量的值

image-20221018162834031

  • diplay + 变量名:跟踪查看某变量,每次执行后都会打印该变量的值

image-20221018163039011

  • undisplay + 变量名:取消对某变量的追踪

  • run/r:从开始执行至下一断点

  • continue/c:从当前位置执行至下一断点

  • until + 行号:跳转至指定行

  • finish:执行到当前函数返回处

image-20221018163631836

  • breaktrace/bt:查看当前函数调用情况

image-20221018164002684

  • info/i locals:查看当前栈帧(正在执行的函数)局部变量的值

image-20221018164137815


make/Makefile —— 项目自动化构建工具

make 是一个指令,Makefile 是一个文件

先通过一个例子来见识一下它是做什么的:

首先创建一个Makefile文件:touch Makefile

vim 编辑 Makefile 文件:

image-20221018165341718

保存退出之后使用 make 命令执行一下:

image-20221018165458052

通过这个简单的例子我们发现通过 make 一次性完成了对多个文件的编译,且这多个文件有依赖关系。

实际上,当我们创建项目的时候,总是有多个源文件,最简单的就是函数的声明和定义分离,这样生成解决方案的时候要对多个源文件按一定顺序进行编译,这样是不是太麻烦了呢?所以 make/Makefile 就是帮我们完成这个工作的。

解释一下 Makefile 文件内代码的意义:

test:test.o:表示 test 文件依赖于 test.o 文件,具体是怎么依赖的呢?

就是下面这行gcc test.o -o test

上面这行我们称之为依赖关系,下面这行我们称之为依赖方法

知道了这个,我们再了解一下 make 是怎么工作的:

首先 make 会在当前目录下找名为 Makefile/makefile 的文件,

进入文件之后,不加以指定的话 make 会将从上至下第一个文件作为目标文件,上面的 test 就是目标文件。

然后根据目标文件的依赖关系,如果目标文件所依赖的文件不存在,则以依赖文件为目标文件,去寻找新目标文件的依赖关系,以此类推…个人感觉类似于递归。

在执行过程中,如果有一层关系断掉了,可能是因为依赖文件不存在,也可能是因为依赖方法有问题,那 make 就会报错,并结束执行。

需要注意,

我们说不加以指定的话 make 会以第一个文件作为最终的目标文件,那怎么指定让 make 以其他文件作为目标文件呢?也很简单,make + filename 就好了:

image-20221018171338728

如此,对于多文件项目就可以通过一个 make 构建完成了。

会构建项目,当然也要会清理项目:

vim 编辑 Makefile 文件:

image-20221018172325379

其中 .PHONY 是生成一个伪目标,即没有依赖关系的目标,这样它会有一个特性,总是可以被执行。

怎么理解总是可以被执行呢?像上面的 make 生成一次解决方案后,如果不对源码进行修改,再次 make 就不会执行:
image-20221018172246321

而伪目标则可以无限执行:

image-20221018172434812

保存退出后 make clean 执行:

image-20221018171622808

这样就完成了项目的清理。

上面说 make 会将从上至下第一个文件作为目标文件,

如果想一次编译多个没有依赖关系的文件需要make + filename

那么有了.PHONY,我们还可以这么做:

.PHONY:all
all: test1 test2
test1:
	gcc -o test1 test1.c
test2:
	gcc -o test2 test2.c

.PHONY:clean
clean:
	rm -f test1 test2

git —— 项目托管到远程仓库

这里只简单介绍一下具体步骤。

  1. 首先检查系统装没装gitgit --version:

    image-20221018173649806

    如果没装的话需要先安装:sudo yum install git

  2. 创建远程仓库,这里以 Gitee 为例,可以自行设置一下初始化仓库和模板:

    image-20221018173855264

  3. 创建完成后将远程仓库地址克隆到本地git clone URL

    image-20221018174210965

  4. 将想上传的文件存在本地目录中,通过三板斧上传即可。

  5. git add filename

    image-20221018174606118

  6. git commit . -m "log"

    image-20221018175120209

    这一步是提交改动,. 代表是当前目录,-m “log” 是提交日志,log 是日志内容,这个不可省略。

  7. git push

    image-20221018175341445

    这一步是同步到远程仓库,需要输入账号密码,完成这一步后就可以在远程仓库看到上传的文件了:

    image-20221018175431070

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LeePlace

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值