前言
在上一篇文章中我们学习了Linux权限,相信大家对于Linux有了更深的了解,(还不清楚的朋友可以去看我的上一篇文章https://blog.csdn.net/be_a_struggler/article/details/125994876)既然我们已经对Linux的一些指令以及权限熟悉了以后,那么做的第一件事情肯定是要去写代码了,今天我们就来讲一讲在Linux下的几款开发工具,同时会对他们进行详细的介绍,帮助大家更好地上手,一起来看看吧。
一.Linux编辑器-vim使用
vi/vim的区别简单点来说,它们都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window、 mac os、windows。在这里我们统一按照vim进行讲解。
1.vim的基本概念
文章中我们讲解vim的三种模式(其实有好多模式,目前掌握这3种即可),分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下: a.正常/普通/命令模式(Normal mode) 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode b.插入模式(Insert mode) 只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。 c.末行模式(last line mode) 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift+: 即可进入该模式。 要查看你的所有模式:打开vim,底行模式直接输入 :help vim-modes 我们这里一共有12种模式:six BASIC modes和six ADDITIONAL modes 下面带大家实操一下: 若是直接 vim 文件名可以直接创建一个文件。(如果文件不存在的话) 在底行模式下: w 写入 w! 强制写入 q 退出 q! 强制退出 ! 强制
2.vim命令模式命令集
yy: 将当前光标所在行复制(需要先把光标移动到要复制的一行) nyy: 复制n行 p: 粘贴 np: 粘贴n次 (例如:1000p:粘贴1000次) dd: 将当前光标所在行剪切(删除+复制) ndd: 剪切n行 u: 撤销历史操作 ctrl + g(G): 反撤销 注意: 撤销与反撤销vim一旦关掉再重新打开的时候就不能再撤销vim 之前操作了。 gg: 光标直接定位到文件的最开始 shift + g(G): 光标定位到文件的结尾 n + shift + g: 将光标定位到文件的任意行(n为行数) shift+4($): 光标定位到当前行的结尾 shift+6(^) : 光标定位到当前行的最开始 w: 以单词为单位,进行光标的向前移动 b: 以单词为单位进行光标的向后移动 说到向前向后的问题,这里还是要说明一下,在Linux中,有一套专门的前后左右移动的键位,虽然大家有的人键盘上是有上下左右键的,但是个人比较推荐大家去使用这套键位。 shift + ~: 大小写切换 shift+r: 进入替换模式(esc退出)(替换多个字符时推荐使用) 这时候会将光标所在位置的字符替换成你所敲的字符 r + 键盘敲的字符: 替换光标所在的字符为所敲字符(替换单个字符时推荐使用) 区别: shift+r 与 r+字符 不同的是上面的shift+r是进入替换模式,进入后直接敲字符就可以,而这条指令是每次替换都要r+敲的字符,比较麻烦 n+r+键盘敲的字符: 从光标位置开始到后面的共n个字符全部被替换为你所敲的字符。(n为数字) x or X: 删除光标所在的字符,先删除光标之后的字符,若后面没有字符了再删除前面的字符 nx: 删除n个字符
3.vim底行模式命令集
set nu: 打开行号 set nonu: 取消行号 vs 文件名: 分屏操作(读源代码时常用,比如你要参考另一个程序的代码来编写自己的代码) 分屏后的命令: ctrl +w +w: 光标切屏,将光标从一个文件切换到另一个文件。 如果想要退出分屏的话还是要切换到底行模式,其他的操作与我们上面讲的在底行模式下的操作相同。 在底行模式下: w 写入 w! 强制写入 q 退出 q! 强制退出 ! 强制
**!指令:**可不用退出vim执行对应Linux命令 具体看下图,在这里我们可以直接在vim下使用ls指令,也可以编译并执行我们所写的代码和程序。
4.简单的vim配置
配置文件的位置 在目录 /etc/ 下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效。 而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:“.vimrc”。例如,/root目录下,通常已经存在一个.vimrc文件,如果不存在,则创建之。 切换用户成为自己执行 su ,进入自己的主工作目录,执行 cd ~ 打开自己目录下的.vimrc文件,执行 vim .vimrc 常用配置选项以及使用插件 1.设置语法高亮: syntax on 2.显示行号: set nu 3.设置缩进的空格数为4: set shiftwidth=4 要配置好看的vim,原生的配置可能功能不全,可以选择安装插件来完善配置,但前提是用户是你要配置的用户,其实这里的配置选项有非常多,主要看自己需要什么,大家可以去网上搜一下,这里就不多做阐述了。
二.Linux编译器-gcc/g++使用
gcc是一个专门用来编译链接C语言的编译器。 g++是一个专门用来编译链接C++的编译器。
1.背景知识
1.预处理(进行宏替换) 2.编译(生产汇编) 3.汇编(生成机器可识别代码) 4.链接(生成可执行文件或库文件)
2.gcc如何完成
格式: gcc [选项] 要编译的文件 [选项] [目标文件]
a.预处理(进行宏替换)
预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E test.c –o test.i 选项“-E”: 该选项的作用是 从现在开始进行程序的翻译,如果预处理完成,则停下来!(预处理后依旧是C语言) 选项“-o”: 是指目标文件,“.i”文件为已经过预处理的C原始程序。 如果只有gcc -E test.c的话,就会将预处理的结果打印在显示器上,加了-o选项后就可以让结果写入test.i文件中。(说白了就是存入一个新的文件中) 在上面实例中其实也可以是别的顺序,主要的是 -o后面一定要跟的是形成的目标文件就可以。 我们先用C语言写一个程序test.c,然后对其进行预处理、编译、汇编、链接等过程。 在这里我们对test.c进行预处理,并将其内容写入到新的文件test.i中。 观察上图的内容,左边是test.c文件,右边是test.i文件,可以看到经过预处理以后短短的23行代码变成了859行,这是因为在预处理阶段将stdio.h文件展开了,然后就是进行了宏替换,M直接被替换为了100,而我们所做的注释在预处理阶段就已经全都没有了,条件编译最后也只剩了一条语句。这就是我们进行预处理后的全部内容。 补充: 这里大家可能不明白条件编译是什么,简单理解就是如果是DEBUG模式下就打印debug,如果是RELEASE模式下就打印release。
b.编译(生成汇编)
在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。 实例: gcc –S test.i –o test.s “-S”: 从现在开始进行程序的翻译,如果编译完成,就停下来。 在这里我们可以看到我对test.i文件进行了编译的工作,同时也生成了test.s文件,这其中都是一些汇编代码,可能大多数人都看不懂,其实没有关系,大家也不需要看懂这些内容,只需要了解一下明白有这么一个过程就可以了。
c.汇编(生成机器可识别代码)
汇编阶段是把编译阶段生成的“.s”文件转成目标文件。 “-c”: 从现在开始进行程序的翻译,如果汇编完成,就停下来。 实例: gcc –c test.s –o test.o 通过图中的内容我们发现test.o文件确实生成了,但是这个内容就更加的令人费解了,其实这里出现乱码是因为这个文件中是以二进制的方式存储信息的,所以我们会看知道这一个情景,但是我们的电脑可以明白二进制代码的含义。
d.链接(生成可执行文件或库文件)
gcc test.o -o test 进行链接操作,生成test可执行文件。 在上图中我们就可以看到最后的输出结果与我们所写的代码想要的结果一致,至此就完成了可执行文件形成的全部过程。
e.重要概念
在这里还要涉及到一个重要的概念:函数库。 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实现“printf”函数的呢? 答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。 你的C程序,是脱离不开C库文件的! 函数库一般分为静态库和动态库两种 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”。 动态库: 与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。 gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。 gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。
在这里我们就来看一下我们生成的文件所依赖的库文件,这里可以看出我们使用的是动态库。
f.动态链接vs静态链接
动态链接: 将库中我要的方法的地址,填入我的可执行程序中,建立关联!(节省资源) 静态链接: 将库中方法的实现,真的拷贝到我们的可执行程序中。(占用资源) 补充: 我们平时所说的方法,过程以及方法的实现和方法的声明,这里的方法和过程指的其实就是函数。 在这里我们可以看到使用静态链接和使用动态链接形成的两个可执行文件的大小有着非常明显的差异,使用静态链接形成的文件要大很多。
三.Linux项目自动化构建工具-make/Makefile
背景: 1.会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力 2.一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。 3.makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。 4.make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。 5.make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
原理: make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么,
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件。
- 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。
- 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
- 根据上面的关系以此类推,知道所有需要的文件都生成,然后再用 hello.o 文件声明make的终极任务,也就是执行文件hello了。
- 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。(拖中华红框的内容就很好的证明了这一点,并且还生成了相应的文件)
- 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
- make只管文件的依赖性,即:如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦
项目清理: 1.工程是需要被清理的 2.像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的: 总是会根据依赖关系,执行依赖方法!。 习惯: clean设置.PHONY。 下面我们来实操一下,让大家理解的更加透彻一些。 在这里我们先创建一个Makefile,然后写入我们想要的内容。 这里将Makefile写好以后,我们直接执行make指令,就会根据Makefile中的依赖关系和依赖方法形成我们想要的目标文件hello,make默认自顶向下扫描Makefile,遇到了第一个依赖关系就执行,这也是我们在Makefile中写入hello和hello.c的依赖关系和依赖方法,输入make直接就能执行的原因,然后如果我们要执行项目清理,就要说明一下,即 make clean。 下面为了证明make自顶向下扫描的原理,我们在测试一下: 这里直接make的话就只会清理项目,并不会生成hello文件,若是要生成需要我们说明一下。 注意: 这里还有一个现象,就是我们多次输入执行make指令,但是它给了我们一个提示:make: `hello’ is up to date,这是因为我们hello目标文件在生成以后就没有再被修改了,所以他会提示我们hello文件已经是最新的了,但是我们一直执行 make clean就没又出现这个现象,这就是我们上面提到的总是会被执行 即不管有没有,我总是可以被执行的。 依赖关系: 上面的文件hello,它依赖hello.c 依赖方法: gcc hello.c -o hello就是与之对应依赖方法。 补充: 大家这时候可能又会有一个疑问:为什么make指令会报错,那么我修改了文件之后是不是就又能再次执行make命令了? 事实是可以的。但是这里其实还有一些知识点,makefile是如何得知,我的可执行程序是最新的? 答案: 是根据文件的最近修改时间来的!!! 大家可以输入 stat 文件名 来查看关于文件最近被修改的时间。 对于Access的补充: Access不是每次修改文件的时候就会修改,而是在一段时间之后就会自动修改。 可执行程序与原文件比较文件的最近修改时间来判断是否需要重新编译程序(根据文件的最近修改时间) 有了以上内容做铺垫以后相信大家对于Makefile有了一个更深的了解,下面我们就来证明一下这个内容。 在下图我们看到直接make的话还是无法生成新的hello目录文件,那我我们对文件进行一下touch,更新一下时间,大家可以看到这里就成功地执行了make指令,生成了新的目标文件hello。 关于make与Makefile我们只是用了一个hello.c文件举了例子,但是大家知道我们平时在写项目的时候肯定不只有一个.c文件,下面我们就来举一个多文件的例子。
Linux第一个小程序进度条
在做这个小程序之前我们要补充一些新的知识。 这个相信大家已经清楚了,那么我们再来看一个东西,我把源代码更改一下。将hello world后面的\n去掉。 这时候大家可能会非常的疑惑,为什么会出现这种情况呢?不是应该先执行printf么? 下面我们来揭晓答案: 其实这里确实是先执行printf的,在C语言中的执行顺序都是从上往下依次执行,这里出现这种情况的原因就要涉及到缓冲区的内容。 那么这就很好的解释了这里出现上面现象的原因,那么我们再来证明一下说的到底对不对。 大家可以看这里,我又添加了一条语句,这个语句的作用是让显示器设备立刻刷新,将缓冲区中的内容打印在屏幕上,这里与前面我们举的例子对比,就会立刻打印出hello world!然后再sleep;很好地验证了我们的解释。
这戏内容我们了解了以后再看下面的一个内容: 这里问大家一个问题,换行和回车有什么区别呢? 看到这里大家可能都懵了,这能有什么区别??? 其实是有很大的区别的,我们一起来看看吧。 换行: 其实就是字面换行的意思,但是光标并不是直接回到下一行的开头,而是直接到下一行与之对应的位置 回车: 回车就是直接回到光标所在这一行的最开始的位置。 我们平时在C语言中用的“\n”,其实默认包含了换行回车两个过程。
在这里我们看一下使用了’\r’后程序的运行结果,根据源代码我们想到的是这里将会打印六行内容,并且i的值一直在发生变化,但是最后什么也没有打印,这就是因为有 \r 造成的结果,我们知道输出的内容会先保存在缓存区中,不会立刻被打印出来,而\r又会使光标不断地回到最开始的位置,所以一直到最后光标回到了最开始的位置,这时候就不会将以上的内容打印出来,所以这里是什么也看不到的。
当我们修改了代码以后,加入了fflush()函数,就能立刻让结果输出了,并且在这里会形成一个倒计时,而且只会输出一条语句。这种情况也是与\r有关系的,与前面所讲的原理一样,这里我们就不再多说了。
进度条打印 这里我们就成功的完成了进度条小程序,但是还要注意一点就是我们的字体不要太大,否则可能容纳不了进度条的大小,出现不必要的错误。
四.Linux软件包管理器yum
为了让大家更好地理解,我在本主题后面附了一张图,大家看完下面的什么是软件包内容后可以直接去看图片进行学习。
1.什么是软件包
在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过软件包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装. 软件包和软件包管理器, 就好比 “App” 和 “应用商店” 这样的关系. yum(Yellow dog Updater, Modified)是Linux下非常常用的一种软件包管理器. 主要应用在Fedora, RedHat,Centos等发行版上。
2.关于rzsz
这个工具用于 windows 机器和远端的 Linux 机器通过 XShell 传输文件. 安装完毕之后可以通过拖拽的方式将文件上传过去。
3.注意事项
关于 yum 的所有操作必须保证主机(虚拟机)网络畅通!!!
4.查看软件包
通过 yum list 命令可以罗列出当前一共有哪些软件包. 由于包的数目可能非常之多, 这里我们需要使用 grep 命令只筛选出我们关注的包. 注意事项: 1.软件包名称: 主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构. 2.“x86_64” 后缀表示64位系统的安装包, “i686” 后缀表示32位系统安装包. 选择包时要和系统匹配. 3.“el7” 表示操作系统发行版的版本. “el7” 表示的是 centos7/redhat7. “el6” 表示 centos6/redhat6. 4.最后一列, base 表示的是 “软件源” 的名称, 类似于 “小米应用商店”, “华为应用商店” 这样的概念
5.如何安装软件
sudo yum install 软件名称 yum 会自动找到都有哪些软件包需要下载, 这时候敲 “y” 确认安装.出现 “complete” 字样, 说明安装完成 注意事项: 1.安装软件时由于需要向系统目录中写入内容, 一般需要 sudo 或者切到 root 账户下才能完成. 2.yum安装软件只能一个装完了再装另一个. 正在yum安装一个软件的过程中, 如果再尝试用yum安装另外一个软件, yum会报错.
6.如何卸载软件
sodu yum remove 软件名称
五.Linux调试器-gdb的使用
1.背景
1.程序的发布方式有两种,debug模式和release模式 2.Linux gcc/g++出来的二进制程序,默认是release模式,所以无法直接被调试 3.要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项 (该程序是debug方式发布的)
2.命令介绍及使用方法
gdb + 文件名: 进入调试 quit: 退出gdb gdb会记录最近一条命令,如果命令无变化,直接回车。 进入调试后的第一步肯定是要看到我我们的代码了,这时候就又需要一条指令 在介绍下面的指令的时候我会介绍单个的字母,后面会跟它的全称,为了方便大家在使用时直接用单个的字母就可以了。 l(list): 以系统自己的方式显示源代码。默认一次显示十行,按回车键可以向下翻阅代码 l+0: 直接从第0行的位置显示源代码 r: 开始调试,如果没有设置断点,直接运行结束! b 行号: 给特定的行号打断点 info b: 查看断点(断点的编号) d 断点编号: 删除断点 c(continue): 运行至下一个断点处停下来! disable/enable +断点的编号: 使能(关闭和打开)断点 n(next): 逐过程 s(step): 逐语句 p + 变量名: 打印变量内容 display + 变量名: 设置长显示,在每次执行语句时都会显示变量的内容。(多用于循环) undisplay+编号: 取消对应编号变量的长显示 until + 行数: 跳转到指定行,不建议函数间的跳转,建议函数内的跳转。 finish: 将当前函数跑完就停下来 set var 变量名称=数值 : 循环中对特定变量进行修改
关于gdb的使用我们就先讲解到这里,其是在gdb中的指令还有很多,但是我们目前写代码的话只需要掌握这些就足够了。
总结
关于Linux开发工具我们就已经全部讲解完毕了,你是不是也有所收获呢? 学习Linux的开发工具及其指令无非就是多敲,多练,熟悉了以后这些指令都不在话下。最近的时间基本上都在整理这些开发工具的内容,为了能让大家更清楚的明白其中的意思也是精心的去截图,整理,如果我所讲的内容对你有用的话,记得给波三连呦!!你们的支持就是我最大的动力。
|