Linux环境基础开发工具使用
1、Linux软件包管理器—apt
我们平时使用手机安装软件非常方便,直接打开应用商店,然后下载安装就行了。这是因为一般手机的厂商出于各种目的会给我们提供软件服务,在服务器上部署应用商店服务,我们用户访问应用商店客户端,直接在客户端下载软件然后进行安装即可。
在Linux中安装软件的方式有:
1、源代码安装。
2、rpm安装—Linux安装包
3、apt安装—解决安装源、安装版本、安装依赖问题。
使用源代码进行安装就是将程序代码给你,你需要自己编译形成可执行程序,然后运行程序安装。
使用rpm命令对rpm安装包进行安装,但是没有解决依赖问题。
使用apt,可以帮助我们解决安装版本的问题,因为你的ubuntu系统可能是22.xx,也可能是比较古老的版本,不同版本系统安装软件版本也是不同的,而且安装软件也是需要依赖的,那么这些问题apt都可以直接帮我们解决,类似手机的应用商店。
注意:使用apt软件包管理器要确保主机网络通畅,可以ping一下百度:

1)apt list可以显示出所有安装包:

2)apt list配合行过滤工具grep使用:

3)apt install安装软件:

4)apt remove删除软件:

带-y表示不需要询问直接删除。有时候安装或删除可能会有询问,带-y就不会再询问。
由于centos官方已宣布停止维护,所以这里介绍的是ubuntu下软件包管理器apt的使用。
总结就三板斧:apt list、apt install、apt remove。
centos下对应的软件包管理器是yum:yum list、yum install、yum remove。
如何配置apt源:打开 /etc/apt/sources.list.d/ubuntu.sources文件
vim /etc/apt/sources.list.d/ubuntu.sources

修改URIs即可,默认云服务器厂商都会给你配好,当然你也可以自己修改,如使用清华源、网易源等。
2、Linux编辑器—vim
vim—linux下的文本编辑器,可以用来写代码。
我们讲解vim的三种模式(其实有好多模式,目前掌握这3种即可),分别是命令模式、插入模式和底行模式。
命令模式:可以对文本内容进行复制、删除、剪切,移动光标等等操作。
插入模式:可以对文本内容进行修改。
底行模式:保存退出vim,还可以在底行模式下强制执行linux指令。

2.1、三种模式转换
命令模式->插入模式:
i:在当前光标插入
I:在当前光标所在行行首插入
a:在当前光标后面插入
A:在当前光标所在行末尾插入
o:在当前光标的下一行插入
O:在当前光标的上一行插入
插入模式->命令模式:esc
命令模式->底行模式:shift+; 本质上就是:
底行模式->命令模式:esc
2.2、底行模式下操作:
set nu:调出行号
set nonu:取消行号
w:保存
q:退出
!:强制
wq!:强制保存并退出
!ls -al:可以执行命令
/关键字:向后查找关键字,如果第一个不是想要的可以按n继续向后查找
?关键字:向前查找关键字,如果第一个不是想要的可以按n继续向前查找
2.3、移动光标
h:向左移动
l:向右移动
j:向下移动
k:向上移动
w:按照单词进行行间向后移动
b:按照单词进行行间向后移动
^:移动到当前行行首
$:移动到当前行行尾
gg:移动到第一行
shift g/G:移动到最后一行,本质上是
n shift g:移动到第n行
ctrl b:向前移动一页
ctrl f:向后移动一页
ctrl u:向前移动半页
ctrl d:向后移动半页
也可以使用小键盘的上下左右键进行移动
2.4、删除
x:删除光标所在字符
X:删除光标所在的前一个字符
nx:删除光标开始往后的n个字符
nX:删除光标之前的n个字符
dd:删除光标所在行
ndd:删除光标开始往后的n行
2.5、复制
yy:复制光标所在行
nyy:复制光标开始往后的n行
p:将通过yy复制或dd删除的内容粘贴。yy和p配合使用就是复制粘贴,dd和p配合使用就是剪切
2.6、替换
r:替换光标所在字符
nr:替换光标及之后的n个字符
shift r/R:替换模式,可以一直替换当前行字符,直到退出替换模式
shift `/~:对当前光标所在字符进行大小写转换
n~:对当前光标及之后n个字符进行大小写转换
2.7、撤销
u:撤销最近操作
ctrl r:撤销最近的撤销
2.8、多文件操作
底行模式下,vs code.c:可以打开多个文件进行多文件操作。
ctrl w w:跳转到其他文件
vim下注释多行:ctrl v移动光标,然后shift i或大写I,输入//,然后esc即可完成多行注释。
vim下删除多行注释:ctrl v移动光标,d,esc即可。
配置vim文本编辑器,可以设置自动缩进、语法高亮、背景颜色等功能,需要配置家目录下的.vimrc文件。感兴趣的可以网上搜索自己配置,嫌麻烦也可以网上找别人配置好的直接拿过来用。
3、Linux编译器—gcc/g++
gcc/g++是linux进行C语言/C++代码编译的工具。
为什么我们可以在windows上进行C/C++的开发呢?我们的系统一定要安装上C/C++开发相关的头文件、库文件。C/C++开发环境不仅是指visual studio、gcc、g++,更重要的是头文件和库文件。而我们在安装visual studio、gcc、g++的时候,默认就会安装上C/C++相关的头文件和库文件了。
我们在使用编译器对源文件进行编译的时候有以下几个步骤:
1、预处理:去注释、头文件展开、宏替换、条件编译。
2、编译:生成汇编。
3、汇编:生成机器可识别代码。
4、链接:生成可执行文件或库文件。
下面看gcc的使用:
3.1、gcc直接编译.c源文件
gcc test.c

前面说过linux并不以文件的后缀来区分文件类型,但是对于gcc/g++编译器,是以文件后缀区分的。
默认使用gcc编译源文件生成可执行程序a.out。
3.2、gcc加-o选项对生成的可执行程序命名
以下两种写法效果相同
gcc test.c -o test
gcc -o test test.c

3.3、预处理:-E选项,编译器从现在开始进行程序的翻译,将预处理工作做完就停下来,不要继续往后走。一般预处理后的文件为.i文件。
gcc -E test.c -o test.i

3.4、编译:-S选项,编译器从现在开始进行程序的翻译,将编译工作做完就停下来,不要继续往后走。一般编译后的文件为.s文件。
gcc -S test.i -o test.s

3.5、汇编:-c选项,从现在开始进行程序的翻译,将汇编工作做完就停下来。一般汇编之后形成的文件为.o文件。
gcc -c test.s -o test.o

test.o称为可重定位目标二进制文件,简称目标文件。不可以独立执行,虽然已经是二进制了,还需要经过链接才能执行。
链接:gcc test.o -o test形成可执行程序

如上,将可重定位目标二进制文件和库进行链接形成可执行程序。
链接的理解?
像我们在C语言中使用printf函数,这是库给我们提供的方法——C标准库,库本质上是一个文件,有路径。
Linux:.so为动态库,.a为静态库。
Windows:.dll为动态库,.lib为静态库。
Linux下库的命名规则:libname.so.xxx,lib后面的name是库的名字,.so表示动态库,.xxx表示版本号。
方法的实现就是在库中,库就是把.c文件经过翻译然后打包,只给你提供一个库文件,不用再给你提供很多个源文件,同时还可以达到隐藏源文件的目的。
你的软件=头文件提供方法的声明+库文件提供方法的实现+你的代码。

上面是ubuntu和centos动静态库的存储目录。下面我们可以查看ubuntu下的C的库文件:

libc.a和libc.so是C语言的静态库和动态库。
那么.o文件如何与库连接的呢?
链接分为:动态链接、静态链接。

假设你初中很努力,考上了一个好的高中,那么在进入学校之前你就知道学校是不允许带手机、电脑这种可以联网设备的,并且你去询问了你的学长,你的学长跟你说:确实不能带,但是学校北门往东走五百米,有个网吧,你可以去那里上网。过一段时间你到学校了,今天正好是周六,你把老师布置的作业1、2、3…列出来,准备一项一项完成。你先完成了物理作业数学作业,写了篇文章,然后中午吃了个饭,吃完饭你就打算去网吧玩一下,这回你就出学校北门,然后到网吧开了台电脑自己玩了会游戏,然后再返回学校休息一会继续写作业。
那么你把列出的一项一项作业完成就是可执行程序在运行,然后到了5你出去网吧玩了把游戏本质上就是你调用了系统库函数,所以跳到系统库中进行执行,网吧就是动态库,执行完之后你返回,然后继续向下执行。那么你怎么知道网吧在哪,这就是学长——编译器告诉你的。另外这个学校只有你一个人去网吧玩吗,不只有你,还有很多其他同学,所以动态库是共享库,其他程序调用了系统接口也要跳转到库函数中执行。这种方式就是动态链接。
那么这时候突然来了个帽子叔叔,发现这家网吧是黑网吧,直接查封了,那么你们就没法再去网吧玩了,网吧已经没了,这就是程序找不到动态库,那么程序就无法正常运行
动态库不能缺失,一旦对应的动态库缺失,影响的不止一个程序,可能导致很多程序都无法正常运行。
下面介绍一个指令,ldd可以用来查看可执行程序所依赖的动态库:

可以看到,我们使用的printf函数是依赖于C的动态库的。
那么之前我们说了,指令本质上也是文件,是一个可执行程序,存放在/usr/bin目录下,现在我们可以对/usr/bin目录下的某些文件查看它们所依赖的动态库:


可以看到,他们都是依赖C语言的动态库的,如果C语言动态库不在了,那么很多指令就无法运行了。

回到故事,现在这个老板转而成为一手二手电脑销售商,那么网吧已经不存在了,你在学校里面又没法玩游戏,所以这时候你向你爸求助,你爸说没事我带你去买台电脑你带进去就行,老师那边我已经打好招呼了。然后你就直接把电脑带进去学校玩了,那么某一天,帽子叔叔又找上这个老板了,但是这个老板不长记性还是没有营业执照,所以又关了。但是这时候对你有影响吗?并没有影响,因为电脑你已经买了带进去学校了,所以你该玩还是玩。
那么这时候这个销售商就是静态库,这时候是将静态库的代码拷贝到了可执行程序中,所以哪怕以后这个静态库不存在了,也不会影响程序的运行。这就是静态链接。
编译器使用静态库进行静态链接的时候,会将自己的方法拷贝到目标程序中,该程序以后不再依赖静态库。
在Linux中,编译形成可执行程序默认采用的是动态链接——提供动态库。
如果想采用静态链接的方式,需要给gcc加上-static选项:


1、如果我们没有静态库,不能加-static。
2、如果我们没有动态库,只有静态库,并且gcc可以找到,这是没问题的,gcc默认优先动态链接,然后再静态链接。-static的本质就是改变了链接的优先级,将所有链接要求全部变成静态链接。
3、我们的程序不一定纯动态或纯静态链接,可能是混合的。
动态库 VS 静态库
动态库是共享库,能有效节省资源(磁盘空间,内存空间,网络空间等)。但是动态库一旦缺失,导致各个程序都无法运行。
静态库,程序不依赖库,可以独立运行。但是体积大,消耗资源。
另外我们使用gcc默认编译出来的可执行程序是release版本的,debug版本是在形成可执行程序的时候添加debug信息,让程序可以进行调试。如果我们要发布debug版本,需要给gcc加上-g选项:

可以看到,debug版本文件是要本release版本大的,因为添加了debug信息。
g++的使用类似gcc,这里就不再赘述,大家可以自行验证。
总结gcc选项:
-E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
-S 编译到汇编语言不进行汇编和链接
-c 编译到目标代码
-o 文件输出到 文件
-static 此选项对生成的文件采用静态链接
-g 生成调试信息。GNU 调试器可利用该信息。
4、Linux调试器—gdb
gcc默认编译是以release方式发布的,无法直接调试,没有携带debug信息。
如果要以debug方式发布,需要给gcc加上-g选项。
gdb 可执行文件名:可以直接进入gdb调试,如果没有gdb请使用apt/yum自行安装。
gdb调试命令:
l/list:列出源代码,每次10行
l n:n表示行号,可以查看第n行的代码
l 函数名:可以查看函数的代码
r/run:运行程序
q/quit:退出gdb
n/next:单条执行,相当于vs的F10逐语句
s/step:进入函数调用,相当于vs的F11逐过程
b/break 行号/函数名:可以给对应行或函数打断点
info b/break:查看断点信息
d/delete breakpoint:删除所有断点
d/delete n:n为断点编号,表示删除编号为n的断点
disable n:n为断点编号,表示禁用编号为n的断点
enable n:n为断点编号,表示启用编号为n的断点
p 变量:查看变量的值,只显示一次
display 变量:跟踪查看一个变量的值,每次停下来都会显示
undisplay 编号:取消对先前设置变量的显示
until n:跳转至第n行
finish:执行完当前函数然后停下
c/continue:跳转至下一个断点处
i/info locals:查看当前栈帧局部变量的值
bt:查看各级函数调用及参数
set var:修改变量的值
5、Linux项目自动化构建工具—make/Makefile
make是一个命令,makefile是一个文件。
先来见见makefile是怎么工作的:

我们当前目录下有一个已经写好的test.c文件,现在我们创建makefile/Makefile文件,大写小写均可。然后在makefile中写入依赖关系和依赖方法,保存退出。然后我们直接make,可以发现它直接执行了gcc命令创建出了可执行程序test,然后再执行make clean,它会将test文件删除。

makefile文件是由依赖关系和依赖方法组成的。
test:test.c是依赖关系,test是我们要形成的可执行程序文件,它依赖于test.c,如果有多个源文件就在后面空格间隔开。gcc -o test test.c是依赖方法,通过依赖方法形成我们需要的可执行程序test,依赖方法前面要加上tab间隔开。
那么下面的也是类似的,clean:后面没有跟任何内容,说明它不存在依赖关系,但是它有依赖方法,就是删除test文件。那么我们执行make clean的时候,就会执行依赖方法删除文件。
下面来看一个复杂一点的makefile:


这里我们形成test需要test.o文件,但是test.o文件不存在,那么会往下找发现有test.o的依赖关系,但是test.s不存在,往下找发现有test.s的依赖关系,一直往下,发现test.c是存在的,然后形成test.i、test.s、test.o、test。可以返现这是一个栈式的结构。
也就是说,make会自动推导makefile中的依赖关系。
现在来看为什么make就是形成可执行程序,而make clean才是清理呢?
我们把他们的位置调换一下再看看:

上面可以看到,调换位置了make默认执行的就是清理了,而如果编译形成可执行程序就需要make test。
所以,make默认执行第一个依赖关系的依赖方法。
makefile中特殊符号:

$@表示形成的可执行程序test,$^表示后面的所有依赖文件,我们这里就只有test.c。
现象:当我们第一次执行make的时候能形成可执行程序,但是第二次再make的时候就不行了,这是为什么呢?
实际上文件都有时间属性,我们可以使用stat来查看:

一个空文件需不需要占据存储空间呢?答案肯定是需要的,需要存储文件创建或修改的时间,文件的名字,文件大小等信息,所以一定是需要占据存储空间的。那么文件=文件内容+文件的属性。
1、Access就是文件被访问的时间,比如你打开文件,cat阅读文件,这个时间就会被修改。但是由于访问文件是非常频繁的操作,如果每次都改的话必定会影响linux系统的性能,所以这是有对应的算法来判断是否修改的。
2、Modify就是文件被修改的时间,这里是修改文件内容的时间。
3、Change也是文件修改的时间,不过是文件属性修改的时间。
我们将这三个时间称为ACM时间。
之前我们介绍过touch命令可以创建普通文件,对于已存在的文件,touch会修改文件的ACM时间。

可以看到,touch之后文件的ACM时间都改变了。
使用touch -a/-m/-c修改文件时间:

由于touch -a修改了test的访问时间,也就是修改了文件的属性,所以Change时间也更新了。-m对应的就是Modify时间,-c对应的就是Change时间。
那么为什么引入这个文件的ACM时间呢,是因为make第二次之所以没有再次形成可执行程序,它原理就是通过判断test.c的Modify时间和可执行程序test的Modify时间。
判断最近修改时间:
如果可执行程序 新于 .c源文件的,说明不需要重新编译。
如果可执行程序 老于 .c源文件的,说明需要重新编译。
那么也就是说make会根据源文件和目标文件的新旧,来判断是不是需要重新编译。
也就是说依赖关系不一定总是执行的。
那么如果我想让依赖关系总是执行呢?
.PHONY:添加伪目标,被.PHONY修饰的总是会被执行

makefile扩展:

1、#表示注释。
2、@加在依赖方法前面表示执行依赖方法不回显。
3、%相当于通配符,%.c:当前目录下所有的.c文件展开到依赖列表中。
4、$<表示右侧的依赖文件,一个一个的交给gcc -c选项,形成同名的.o文件。

5、makefile还可以定义变量,$(bin)就相当于mythread。

6、Linux第一个小程序—进度条
我们创建几个文件,main.c用来调用进度条函数,processBar.h声明,processBar.c实现,并实现对应的makefile文件。
前置知识1:回车换行
在C语言中,我们输出字符串后面加上\n,下次就会在下一行的起始位置输出。本质上\n是涵盖了回车+换行的功能。
回车:回到当前行的起始位置。
换行:换到下一行。
\n兼具了回车+换行,如果我们只想要回车——\r。
前置知识2:缓冲区
介绍两个接口,sleep和usleep,让进程休眠。sleep是以秒为单位的,usleep是以微秒为单位的,我们可以使用man手册查看:



我们发现运行程序后,并没有立即打印出来,而是过了一段时间才打印出来。
这是因为,在sleep期间,我们输出的字符串一定被保存了起来,被保存到C语言的缓冲区中,也就是C语言维护的一段内存,然后进程结束后才将缓冲区的数据刷新输出到显示器文件。
C语言默认打开三个文件:标准输入stdin,标准输出stdout,标准错误stdout。
那么如果我们想要强制刷新需要调用fflush函数。
有了前面两个知识,我们就可以开始实现进度条了:


还可以给输出添加配色方案,感兴趣的可以网上搜索自己添加。
7、Linux下git基本使用
git是版本管理控制软件,可以在我们本地仓库进行代码管理,也可以将本地仓库代码上传到远端。
下面介绍git的基础用法:
首先我们在gitee创建本地仓库,由于github不一定访问的上,所以我们使用gitee。

我们可以选择初始化仓库,添加.gitignore实际上是一个配置文件,在.gitignore文件中出现的就不会被上传到仓库中,有时候我们不想要某些无用的文件上传到仓库中,就可以在.gitignore中进行配置。
创建好并初始化之后,我们找到仓库对应的克隆/下载:

将我圈起来的这行地址复制,然后在linux下我们输入:
git clone https://gitee.com/zeng-zhi-yong/code-under-linux.git

然后就多出了一个目录,这个目录就是我们从远端仓库直接拉下来到linux本地目录,由于里面是刚创建的所以没有代码,如果你之前有创建过仓库并且里面有代码,拉下来就是有代码的。
然后我们将写好的代码移动这个目录中:通过git add .将当前目录下新增的文件添加到临时仓库中


使用git status,我们可以看到新添加了我们写的进度条代码。
然后使用git commit -m “xxxx”,提交并写入日志信息。-m选项一定要带,然后跟上你写的日志信息。

最后使用git push推送到远端仓库:

我们还可以使用git log查看提交的信息:

总结git的几个用法:git clone、git status、git log、git add .、git commit -m “xxx”、git push。
主要就是三板斧:git add、git commit、git push。

1493

被折叠的 条评论
为什么被折叠?



