linux开发环境及工具
我们之前了解了linux的基础操作和基本的概念,还是无法在linux中完成一些开发工作的,接下来我为大家介绍我们常用的开发工具。
yum–Linux下的软件包管理器
我们如何下载软件呢?
-
下载程序的源代码,自己编译,从而得到可执行程序
但是这样很麻烦呀,所以我们直接下载编译好的软件包。
一般通过软件包管理器进行获取软件包,直接进行安装。 -
linux中我们可以下载rpm安装包,但是没有人为我们解决依赖关系的问题
依赖关系是指程序的运行依赖操作系统中的文件。其中有的程序因为操作系统的更新无法使用。
- yum就是一款软件包管理器,类似于app store之类的应用商店,它帮助我们解决了依赖关系。我们安装yum的客户端,请求yum软件服务器进行下载软件安装包。并在我们本地安装。
其中需要注意的是:centos中任何时刻,只允许一个yum进行安装
我们了解了yum这个工具后,再来看看他在我们系统中的具体信息吧!
首先我们在 /etc/yum.conf 中我们可以看到yum的配置文件。
这个配置文件对我们来说是不重要的
我们需要了解的是yum源的配置,这样我们才可以下载更多的东西。
/etc/yum.repos.d
在这个路径下,我们可以看到我们的yum源
当我们安装一些软件有问题的时候,我们需要关注一下源的问题。
如果源有问题,需要我们手动配置源。
在更改默认源的时候,我们最好用cp命令把原来的源备份一下,以免发生无法挽回的问题。
Epel这个源是第三方源,我们需要自己安装更新一下。
sudo yum install -y epel-release
这里介绍两个参数
sudo:因为安装软件的时候需要将文件拷入到操作系统文件中,完成依赖关系的配置,所以需要提升权限。
-y:在下载和安装的过程中,安装程序会请求我们是否继续,我们需要输入y/n,这时候加上-y这个参数,就完全自动安装了。
当我们想要卸载一个软件的时候,我们的命令是
sudo yum remove xxx
这样一来,对于yum软件我们就了解差不多了。
Vim开发工具 --Linux下的IDE
vim是一款linux下的多模式编辑器,也是vi的升级版本。他是一款非常强大的软件,当我们熟练使用后,效率一定是飞一样的感觉。
vim的使用
上文提到,vim是一款多模式的编辑器,那他究竟有多少模式呢?
我们可以在vim底行中输入:help vim-modes
可以看到12种模式。
我们这里介绍3种最主要的模式,也是我们最常使用的模式。
分别是
Normal mode 普通模式(命令模式)
Insert mode 插入模式
last line mode 末行模式
我们在具体了解他们是干什么之前,需要先看看他们三个是如何相互切换的。
我们需要知道,我们一打开vim,默认直接出于正常模式。
当我们从正常模式切换到插入模式时
a、i、o三个字符都可以,那他们存在的意义是什么呢?
a:是在光标所在的位置的下一个位置进行插入
i:是在光标的位置进行插入
o:在光标所在行的下一个位置进行插入
在插入模式中,就相当于写代码了,这里并没有什么特殊的指令。
当我们从插入模式要退回正常模式,我们只需要按Esc就可以了。
那我们想从插入模式直接切换到底行模式怎么做呢?
这样的操作是不被允许的。我们只能先退到正常模式进行切换。
正常模式是插入模式和底行模式的中转站。
我们从正常模式切换到命令行,就输入:就好了。
我们要了解的底行命令有以下几个:
:w —保存写入的数据
:wq — 保存并退出
:q! — 强制退出
下来看看正常模式的命令集:
这里有如此多的命令,那么我们其实很多都用不到,我们最常用的是以下几个:
末行模式的命令集
同样的,我们也不会全都使用,以下是常用的几个指令:
vim的基础配置
我们总是看到别人的vim很豪华呀,什么都有,而我们却是一片漆黑上几个白白的字母。那就需要自己配置以下啊。
这里就不教大家如何一行一行配置vim了,
我们告诉大家配置文件的位置在每一个用户的工作目录下,我们看隐藏文件,.vimrc就是配置文件了。
这里要告诉大家,每一个用户都在自己的目录下有自己的配置文件,大家相互之间配置都是不一样的,哪怕是root。
有的人不存在.vimrc这个目录,那你自己touch一个就好了,这里不影响。
除了这些基础的配置,还有很多插件可以插入vim,让他锦上添花。
但是都是很麻烦的,我是直接请求别人给我了一个自动配置的软件,我们一键下载一键配置,如果有需要的同学可以私信我哦。
关于vim的操作,一定要多多的使用,你会感谢自己的努力的。
gcc和g++ --Linux下的编译器
gcc、g++背景
首先我们了解,gcc是编译c语言的软件,g++是编译c++的软件
其中g++是gcc的扩展,并不是两款完全相互独立的软件。
所以他们的参数选项都是一样的。
了解这两款软件前,我们首先需要知道什么是编译器:把文本代码编译成可执行二进制程序
二进制程序不用多数了吧。计算机的所有硬件都是只支持0、1两路的。
C程序的基本翻译过程
1、预处理
操作:
-E : 只进行预处理 生成对应的 . i文件,里面包含了预处理之后的信息。
-o : 指定生成的临时文件,一般为 .i 文件
例如: gcc -E tset.c -o test.i
预处理主要包含以下几个内容:
-
头文件展开:把头文件的内容拷贝到我们的.c文件中。那我们从哪里找的头文件呢?这是因为在编译器下载安装时,自动下载了很多库和头文件,路径对于编译器来说并不是难事。
-
宏替换
-
条件编译:预处理符。动态的裁剪代码。
如果这份代码需要在linux和windows环境下同时编译,那么这时候可以使用条件编译屏蔽对方代码。
如图我们可知,当OS这个宏定义成0的时候,我们只执行windows的代码,当我们改为1的时候,那就执行linux的代码。
其中我们在.i文件中可以清楚的看到,不满足条件编译的代码直接被裁剪掉了。
那么我应该如何改OS呢?除了打开文件,还有一条指令:
gcc test.c -D OS =1
这条命令就把宏修改了。 -
去注释
总结:
这时候这个.i文件还是c语言程序吗?这个问题是不是有点诡异
答案是:是
它变成了一份更加干净的c语言程序。
当然除了这些内容,还有其他的操作,我们暂且不谈。
2、编译
编译是把C的代码编译成为汇编代码
操作:
-S 执行完预处理、编译后 ,停下来 ,并生成 .s 文件
-o 可以指定生成的临时文件
我们可以从.c文件开始编译,也可以从.i 文件开始编译。
我们可以看到.i文件中800多行的文件,经过编译过程后,仅为20多行。
3、汇编
操作:
-c 生成 .o 二进制目标文件,但还不能执行
这里的汇编可不是真的进行汇编,而是将汇编语言翻译成二进制文件,这里的二进制文件叫做可重定向目标文件,当然这里的重定向和操作系统中的重定向不是一个概念。
可重定向目标文件:它不是真正的可执行文件,还需要进行链接,链接的过程叫做完成重定向。之后才是真正的可执行目标文件。
我们的代码中调用了 printf这个函数,那我们不知道print的实现到底在哪里?其实它在C库函数中。我们这里通过汇编生成的test.o 还需要链接,把我们的函数调用和库里、头文件里的实现关联起来,才能生成真正的完整的代码
4、链接
操作:
gcc 不加任何参数 ,默认就是链接过程 ,生成可执行文件。
同时也可以 -o ,进行可执行文件的指定。
链接的本质:就是将自己调用过程和具体的实现过程关联起来。
这时候我们介绍一个命令:
ldd test
其中test是我们的可执行文件,我们通过这条命令可以查看执行程序所依赖的库。
我们可以看到一个 .so 结尾的文件 ,这里就是linux下的动态库后缀
.a 是Linux的静态库
windows中, .dll是动态库 .lib 是静态库
一般库的命名:libname.xxx.a(.so) 其中库的名字就是 中间的name
当我们用file命令查看文件属性时可以看到
这里就是一个动态库链接。
总结:
- 一般我们不需要使用以上那么多参数 就是常规的 gcc test.c -o test 直接生成可执行就好了
- ESc:分别是对应了预处理、编译、汇编、链接(链接不需要参数)
- iso:对应的文件的后缀
既然提到了动静态库,我们来大概理解一下什么是动静态库
理解动静态库
我们今天为以后的基础io部分做铺垫
首先我们知道我们常用的库有C库C++库 ,等等很多
那为什么要有库呢? 我们来直接告诉大家
1、减少当前开发的工作量
2、并行开发,库开发和应用层开发相互分工明确。这样效率高,业务独立,有说不尽的好处。
都有什么库 ?
动态库( . so) : 动态链接
静态库(. a) : 静态链接 ,进行拷贝
如何理解动态链接和静态链接?
我们做一个比方,当我们程序运行过程中有三个步骤
计算 打印 计算
动态链接:我们要执行打印过程的时候,我们调用的是其他库里的函数。那么这个时候程序找到动态库,执行动态库中的实现方法,结果再返还给我们的程序。
静态链接:我们要使用一个库的方法,我们在编译过程中,直接把内容拷贝到我们的可执行程序中,直接运行。
两个库的优缺点
动态链接
优点:省空间:省磁盘空间、省内存空间
缺点:依赖动态库,导致程序的可移植性变差。一个库丢失,可能引起大量依赖此库的程序。
静态链接
优点:不依赖第三方库,可移植性好
缺点:体积大,重复率高,浪费磁盘,浪费内存,加载速度慢。
当然没有绝对的好与绝对的坏,我们应该结合应用场景。系统中一般采用的是动态链接的方法,省空间啊。
gcc生成的可执行程序默认是动态链接
如果我们想要修改一下链接方式,我们可以执行这条命令
gcc -static 把动态链接变为静态链接
这里我们看到我们的两个可执行文件的大小差距有多大。差100倍。
如果这时候再去执行ldd命令,是不起作用的,因为ldd只能查看动态链接的文件。我们只能通过file 去查看文件属性。
gdb – Linux下的调试的神器
众所周知程序的发布方式有两种
- debug – 程序本身会被加入很多的调试信息,以便于我们调试开发
- release – 不会添加任何信息,不可被调试,但是进行大量优化
他们都是可以被正常运行的。
gcc中,默认生成的可执行程序是release 版本的,不可以被调试,想要去调试需要加入 -g 这个参数,使它以debug方式发布,这样我们才能用gdb调试。
这里我们可以看到两个文件的大小有不小的差异。
再给大家介绍一个指令,通过它可以看到代码的调试信息
readelf -S test_g | grep debug
这里可以小小的总结一下:
linux默认发布的可执行程序是动态链接+release
-static —>> 变成静态
-g —>> 变成debug 版本
gdb操作
gdb的操作可不像vs中,那么可视化,想要熟练的使用和理解,需要不断的练习掌握
gdb指令也很多,我们主要用到的是这些:
当然还有更全的
Linux项目自动化构建工具-make/Makefile
我们经常使用的vs工具,使我们忽略了文件之间的关系,文件是如何进行编译和链接的,他把我们的源文件一步到位直接生成了可执行文件。
在linux中,我们需要自己进行操作,我们先编译谁,什么和什么之间有依赖关系等等。
我们先来touch三个文件,两个源文件一个头文件。
我们在头文件中进行包含库和条件编译,这里我们解释一下条件编译的手法
如果没有定义头文件,那我们自己定义,最后结束endif
我们来如何编译呢?
-
gcc -o mytest main.c test.c
我们没有写入头文件,为什么呢?因为编译器在编译的时候,在第一步预处理的过程中已经展开了。
我们编译的时候不需要写他,我们只要保证编译器能够自动找到.h文件就行了。
一般情况下.h在和我们的源文件相同的目录下,也是我们的习惯,gcc很容易就可以找到了。
我们可以做一个小实验,把头文件移到上级目录,再次进行编译,会发生什么呢?
mu test.h … 重新编译一下,很明显报错了,找不到所示的文件。
除了我们当前目录下的.h,我们还需要库中的头文件,这里编译器会自动找到它,并进行展开。
一般是在 / usr / include的目录下
这样我们再来理解一下两种包头文件的方式
include " " 这是在当前文件目录下进行搜索头文件
inlcude < > 这是在全局搜索,一般会去到标准库中搜索
很明显了,<> 是 " " 的 包含。全部用<>很明显大材小用了。 -
第二种编译方式,我们先把所有的源文件全部生成目标文件 .o 加 “ -c” 参数。
然后再进行对 .o文件的链接(不可执行、可重定向的文件)。
第二种方法是不是有点麻烦了,本来一步到位的事情,现在非要两步来操作
这里我们进行一下解释:
第一:
我们再vs生成可执行文件的时候,都是一次生成一个可执行文件。
那这个时候,我有100个源文件,我要把前70个源文件生成一个可执行,把后20个生成一个可执行,把前十个和
后十个生成一个可执行。
就是要一次生成好多个可执行文件。
很明显再vs中是不容易实现的,但是再linux中是完全可行的。把所有文件生成 -c xxx.o,把我们需要指定的文件进行链接就好了。
那你会问,我把他们的源文件分组编译不就好了吗?我创好几个工程,这样当然是可以的,但是请往下看。
第二:
如果使用源文件直接进行分组的编译,我们有100个源文件,我们已经编好了。我们现在要修改其中的一个源文件。
那这个时候,我们需要把这100个源文件重新进行编译。
如果使用两步操作,先生成 .o 再去 链接。我们不需要再去编译其他的源文件,只需要把已经修改的源文件进行编译成.o
然后把它们重新连接一下就好了。编译的效率是很高的。
举一个直观的例子:从头编译一个大项目所有的源文件,可能需要2-3个小时。但是其中链接部分的时间只需要0.1s就可以完成。
好了 ,接下来我们进入我们的正题:make和makefile
首先我们要了解到:是否熟练使用make和makefile工具是衡量一个程序员是否具备大型工程能力的重要指标。
其中make 是一个命令 makefile是一个文件。我们一般搭配使用
第一步:我们先touch一个makefile ,其中m可以大写可以小写
里面写入我们的依赖关系和依赖文件
第二步:make
这里我们理解一些依赖关系和依赖方法
图中mytest :test.o 就是我们的依赖关系,下面第二行的具体命令就是我们的依赖方法
依赖关系中 冒号左边 的叫做 目标文件 ,右边的叫做依赖文件。
根据他们的命名都很好理解。
我们想要生成的目标文件 需要依赖右边的依赖文件。
然后在依赖方法中,运用命令和依赖文件进行命令操作,这样我们就能获得我们的目标文件。
我们再来解释一下图中的具体代码:
我们想要生成 mytest 可执行文件 ,需要 有test .o 文件进行 第二行的gcc 编译链接的命令。
那么test.o 又需要test .s 这个文件 ,用gcc -c 去编译test .s 文件
test.s 有需要 test .i ,gcc -S test.s 编译生成 test .i 文件
test .i 需要 test.c ,gcc -E 编译test .c 生成test.i
然后一步一步在回去,其实是递归那种味道。
还有一点图中 .PHONY 是一个关键字之类的东西,它使右边的命令变成一个伪目标 。
伪目标的依赖方法总是被执行的。我们make命令只能进行一次,当我们加上.PHONY就可以无限次运行
clean这个目标文件不需要依赖任何文件。
意味着,一般情况,我们clean可以无限次clean。make只能一次。
当然这种方式也只适用于文件比较少的情况,还有进阶的方案:
版本控制神器–git与github && gitee
版本控制的简单版本理解
我们先来理解一下版本控制的概念:
今天我们需要写一份代码,第二天上交给老师,老师说代码有问题需要修改,我们回家开始在原来的代码上进行修改。
第二次拿去,老师说值得优化,你回家又改那份代码。第三次,老师说还没有之前好,你还是把第一次的代码给我吧?我帮你弄弄。
这时候你人傻了,我第一次的代码我也没有啊。然而这样的情况在我们release一个程序的时候,是很常见的。
这时候我们就需要改进了,我们学会了版本控制的概念。
版本控制就是在修改代码前,先拷贝一份,在这份拷贝版上进行修改,并写上修改日志。这样我清楚的知道每一版的问题,
我们也有能力交出每一份有需求的代码
我们把这个控制版本的软件就叫做git。
Git和GitHub
理解:
上文提到的思维只是git很小的一部分,我们不只是用它来进行每一版的修改并保存下来这样的版本控制功能,他还有
分支管理和多人协作的功能。
分支管理、多人协作:
现在有一份代码,老师说你没有能力去修改这样的问题,你于是找了一个大佬帮助你,大佬在你的版本控制的日志中,选择了一个版本,下载到大佬的电脑中并给你修改。修改完之后,他又穿回给你的版本控制的链中并更新了日志,这叫做合并分支。这一系列操作叫做分支操作、多人协作。git支持这样的功能。
当然还有电脑坏了的场景,其中github就可以把你所有的代码上传到云,你的合作对象不仅仅是你的同学你的同事,通过网络把所有人都链接起来,文件也会更加安全。
git是一个去中心化的分布式工具
去中心化:没有客户端和服务端的概念。两边都是一样的。
分布式:多端存储;你本地有仓库,远端也有仓库。致使我们的代码更安全、存储效率更高。
历史背景
linux的参与者很多,那么他们的职责、任务该怎么划分。他们写好程序该如何合并。代码的修改、版本更新、删除,都需要我们去修改。起初这都是托瓦兹本人进行操作。从早到晚天天干这见事情。
当然,当时的市面上有很多付费的版本控制和自动合并的工具,托瓦兹不愿意用。但有一家公司的老板是一个有开源精神的骑士,他把软件免费贡献给linux社区中。但是linux的开发者都是五湖四海的顶级工程师,他们在强烈的好奇心的驱使下,对人家的付费软件进行破解。结果被公司发现撤销了使用权。
托瓦兹于是开始写这样的软件,历时2-3周,他写出了一个软件,并对其进行开源,这时候又吸引了一大批程序员的加入,经过不断的完善,git出世。
git基础命令
- git clone
- git add
- git commit -m ‘’
- git push
- git log
- git status