1. 在 Linux 下安装软件 , 一个通常的办法是下载程序的源代码 , 并进行编译 , 得到可执行程序 .2. 但是这样太麻烦了 , 于是有些人把一些常用的软件提前编译好 , 做成软件包 ( 可以理解成 windows 上的安装程序) 放在一个服务器上 , 通过包管理器可以很方便的获取到这个编译好的软件包 , 直接进行安装 .3. 软件包和软件包管理器 , 就好比 "App" 和 " 应用商店 " 这样的关系 .4. yum(Yellow dog Updater, Modifified) 是 Linux 下非常常用的一种包管理器 . 主要应用在 Fedora, RedHat, Centos等发行版上 .
注:
1. 软件包名称 : 主版本号 . 次版本号 . 源程序发行号 - 软件包的发行号 . 主机平台 .cpu 架构 .2. "x86_64" 后缀表示 64 位系统的安装包 , "i686" 后缀表示 32 位系统安装包 . 选择包时要和系统匹配 .3. "el7" 表示操作系统发行版的版本 . "el7" 表示的是 centos7/redhat7. "el6" 表示 centos6/redhat6.4. 最后一列 , os 表示的是 " 软件源 " 的名称 , 类似于 " 小米应用商店 ", " 华为应用商店 " 这样的概念 .
注:
1. 安装软件时由于需要向系统目录中写入内容 , 一般需要 sudo 或者切到 root 账户下才能完成 .2. yum 安装软件只能一个装完了再装另一个 . 正在 yum 安装一个软件的过程中 , 如果再尝试用 yum 安装另外一个软件, yum 会报错 .
那我们如何卸载软件呢?依然是一条简单的命令
sudo yum remove lrzsz
注:如果不想在安装与卸载时手动输入y/n来确定,只需要在install/remove后加上-y或者-n即可
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入 Insert mode 下,或者到 last line mode
只有在 Insert mode 下,才可以做文字输入,按「 ESC 」键可回到命令行模式。该模式是我们后面用的最频繁的编辑模式。
文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下, shift+: 即可进入该模式。
在我们输入vim code.c后进入vim中
在此模式下退出vim有如下一些选项
: w (保存当前文件)
: wq ( 输入「 wq 」 , 存盘并退出 vim): q! ( 输入 q!, 不存盘强制退出 vim)
即切换模式方式如下
锚点操作
gg:定位光标到最开始行
shift+g(G):定位光标到最结尾行n+shift+g(nG):定位光标到任意行
shift+$:定位光标到当前行结尾
shift+^:定位光标到当前行开始
w,b:光标按照单词进行行内跨行进行移动(w向后, b向前)
h,j,k,l:左,下,上,右
ctrl+ww:在不同窗口切换光标复制粘贴
(n)yy:复制光标所在行(n行)
(n)dd:剪切、删除
(n)p:粘贴(n重复行)到光标所在行下一行u:撤销
ctrl+r:恢复撤销
替换
shirt+~:大小写转换
(n)r:对光标字符+之后的所有字符进行批量化替换
shirt+r(R):替换模式,对内容进行整体替换-->第四种模式(还是esc键退出)(n)x:对光标字符之后的字符进行删除
「 w 」 : 在冒号输入字母「 w 」就可以将文件保存起来「q」:按「q」就是退出,如果无法离开 vim ,可以在「q」后跟一个「!」强制离开 vim 。「 wq 」:一般建议离开时,搭配「 w 」一起使用,这样在退出的时候还可以保存文件。「vs XXX」: 在当前窗口打开并编辑一个名为XXX的文件
我们曾经在之前了解过一段代码从文件到可执行程序需要经过:预处理、编译、汇编和链接几大步骤,在这里我们做详细的阐述,以下面这段代码为例
#include
#define MAX 20
int main()
{
#ifdef DEBUG
printf("debug mode\n")
#else
printf("release mode\n");
#endif
printf("MAX: %d\n", MAX);
printf("hello world!\n");
printf("hello world!\n");
//printf("hello world!\n");
//printf("hello world!\n");
return 0;
}
对于这段C语言代码,我们可以直接使用gcc对其进行编译
gcc code3.c -o code3
编译完成后,会生成一个该代码的可执行文件code3(文件名由-o选项后的名字确定),运行该文件有
在预处理阶段,大致会进行四个步骤
a. 去注释
b. 头文件展开
c. 条件编译
d. 宏替换
在这里我们使用
gcc -E code3.c -o code3.i
这行命令的意思是告诉gcc,从现在开始进行程序的翻译,将预处理工作做完就停下来,不要往后走了。我们查看它的内容,并作对比
可以发现, 此时上述几个步骤已经完成。在此部分可能会有些许疑惑,为什么会存在条件编译这个东西?它有什么存在价值吗?
其实它大有价值,有些软件在使用时分为专业版(付费)与社区版(白嫖),在对软件进行升级时,并不需要对两个版本的软件进行维护,只需要维护专业版的软件即可,在维护完成后只需要通过条件控制来进行不同的条件编译,就能做到裁减掉专业版的部分功能,然后就能给出更新的社区版。
在这里我们使用
gcc -S code3.i -o code3.s
这行命令的意思是告诉gcc,从现在开始进行程序的翻译,将编译工作做完,就停下来。此过程生成汇编,我们查看内容有
可以看到,经过编译后,文件就成为了汇编语言,便于进行后续的操作。
在这里我们使用
gcc -c code3.s -o code3.o
这行命令的意思是告诉gcc,从现在开始进行程序的翻译,将汇编工作做完,就停下来。这里产生的.o文件叫做可重定位目标二进制文件,简称目标文件。此目标文件虽然已经转化为机器可识别的二进制序列,但是仍然不能直接运行,需要经过链接后才可以运行。在这里,我们不能再使用vim等识别文本的编辑器打开,可以使用xxd查看
在链接过程,我们使用
gcc code3.o -o code3
此过程将可重定位目标二进制文件,和库进行链接形成可执行程序,此时该文件便可以运行了
有人可能会好奇链接是如何进行的?
其实,链接将目标文件和库进行链接,而库为我们提供了一些方法的实现,而在Linux中一切皆为文件,因此库在linux中也是文件,且分为动态库与静态库,在Linux中动态库与静态库的后缀分别为.so与.a,而在windos中它们的后缀分别为.dll与.lib。那既然库分为动态库和静态库,那么目标文件和库如何进行链接呢?
在这里有两种链接方式,一个是动态链接,另一个则是静态链接。动态链接就是在某一个地方存在着一些方法,当你需要使用它们时,直接跳转到那里使用,在使用完后再跳转出来,整个过程需要做的就只是调用动态库;而静态链接是在需要使用它们时,将它们的内容拷贝到自己的代码中,而不用频繁的跳转。举一个例子,动态链接就相当于想上网时,选择到网吧去,在上网后直接离开,而静态链接则是选择到一家电脑店去买一台电脑放置在自己家中。
可以看到,如果动态库被删除那么会影响到所有与它有动态链接关系的代码,而静态库则没有这方面的担忧。这也就决定了含有静态链接的文件大小肯定大于动态链接的文件,那么接下来我们就来验证一下是否是这样的(在使用gcc编译形成可执行程序时,默认采用的是动态链接,如果要进行静态链接需要增加-static选项,即如下)
我们可以明显看到,使用静态链接生成的可执行文件的大小远远大于使用动态链接形成的可执行文件。此外,如果在库中没有动态库而只有静态库的话,那么在生成文件时也会使用静态链接。那么既然有静态链接和动态链接,那么又该如何选择呢?
动态链接
优点:因为使用同一个共享库,因此可以有效的节省空间(如磁盘空间,内存空间,网络空间等)
缺点:一旦动态库缺失,各个程序都将无法运行
静态链接
优点:不依赖库,各个程序可以独立运行
缺点:体积大,消耗资源较多
首先,我们要知道make是一个命令,makefile则是一个文件
这里我们先创建一个简单的makefile文件
然后在命令行中直接使用make指令就可以产生对应的可执行文件
而使用make clean则可以清除对应的文件
在这个文件里面由红框选中的部分显示了依赖关系,而蓝框选中的部分显示了依赖方法,那什么事依赖关系和依赖方法呢?
依赖关系:在 Makefile 中,可以通过定义目标和依赖关系来描述文件之间的依赖关系。依赖关系指定了某个目标所依赖的文件或目标,表示该目标需要在其依赖项更新后重新生成。
依赖方法:通过定义依赖关系中的命令,可以指定生成目标所需的编译规则和方法。依赖方法是在依赖关系中使用的命令,用于生成目标的过程。
通俗来说,依赖关系就相当于在缺少生活费时,给父亲打电话说:“爸,我是你儿子”,来表明关系,但是仅仅说明关系是不行的,还需要怎么做(即依赖方法),这时候就要说:“你给XXX卡号打生活费”,这样才能达到目的。
通过定义依赖关系和依赖方法,Makefile 能够根据文件之间的依赖关系和生成规则,自动判断哪些文件需要重新生成,从而实现高效的编译和构建过程。 (注:这里clean不需要依赖关系)
在makefile文件中可以使用$@代替冒号左边的文件,$^代替冒号右边的文件,即
此外我们还可以在指令前加上@从而使该语句隐藏
运行如下
接下来举一个完整的实现路径
我们make可以发现
这里的运行结果并不是我们所想的情况,其实在这里它的运行逻辑如下:
先执行第一行的内容,在这里code3需要通过code3.o来产生,而这里没有code3.o,因此它会向下执行,在下一行的内容中code3.o需要通过code3.s来产生,而这里没有code3.s,就这样一直执行到最后一行,到最后一行时产生了对应文件后,又向上递归产生之前的文件,这样就造成了上方的结果
当我们在执行完make后,再次执行make会出现无法执行的结果,即
那么它是如何判断一个文件是否能够被make出来的呢?其实,在这里他是根据文件的时间属性来确定的,查看文件的时间属性指令为 stat code3.c ,查看之后有
可以发现在文件的时间属性中有Acess(访问)、Modify(修改内容)和Change(修改文件属性)三种,一般来说,在修改了文件的内容后,文件的属性也会跟着被修改,而系统会根据新旧时间的对比来判断文件是否可以被执行,我们可以通过使用touch来更新文件属性,即
此时我们再次执行make就可以执行了
由此我们可以发现,makefile中的指令并不是总会被执行的,那要是我们想要强行执行需要怎么做呢?答案是我们可以在依赖关系的目标文件前加上一个.PHONY,他所修饰的目标称为伪目标,即
但是在实际中我们并不总是希望目标文件被执行,而是对clean这个操作希望被执行,因此一般makefile文件如下
我们可以使用
git --help
来查看自己是否安装了git,安装之后查看如图所示
如果没有的话,可以使用下面的命令安装git
yum install git
有了git之后我们就可以将自己的所写的代码远程推送到网络仓库中,接下来就让我们看看如何远程推送
首先我们需要在远端创建一个仓库,在这里我们使用gitee举例,首先我们需要创建一个仓库
随后我们点击并复制自己仓库的地址
这之后,我们在自己的对应的文件夹中输入如下指令
git clone https://gitee.com/xuanxuan-qujiu-pavilion/test-warehouse.git
然后是add命令,即
git add .
这之后是commit命令,这一步需要上传备注(即这段代码有什么用或是干什么的),即
git commit -m "进度条相关代码"
运行有,
最后一步就是push命令
git push
有
注:在进行git add操作时可能会出现以下情况
此时就需要我们手动配置初始文件,即
首先我们需要知道,程序的发布方式有两种,分别是debug模式和release模式,而在Linux中使用 gcc/g++编译出来的二进制程序默认是release模式,而在release模式中我们是无法进行调试的,在这里我们先直接使用gcc编译
接下来可以使用
readelf -S code | grep -i debug
来查看debug调试信息,在这里查看
可以发现,直接使用gcc编译出来的可执行文件是无法进行调试的,因为它没有对应的debug文件,要想调试,必须在源代码生成二进制程序的时候, 加上 -g 选项,即
gcc -o code_debug code.c -g
此时我们再查看debug信息,有
此时,我们就可以使用gdb开始调试了
我们可以使用
gdb filename
来进入gdb模式,即
退出则可以使用
ctrl + d
或
quit(q)
在这里,我们使用下面这段代码举例
#include
int Add(int x, int y)
{
int sum = x + y;
return sum;
}
int main()
{
int a = 5;
int b = 1;
int c = Add(a, b);
printf("%d", c);
return 0;
}
当l后加上行号时就会显示filename该行附件源代码,每次列10行。
举个例子
当l后加上函数名时,就会列出某个函数的源代码。
在输入之后,gdb会记住上次输入的指令,我们再使用l指令后它会沿着上次的位置往下列,即
输入r后,就可以运行程序到断点处(没有的话直接运行到结束),举个例子
无断点
有断点
使用next我们可以逐过程调试
就以上面为例,使用next后有
可以看到他直接运行到了下一条指令处
使用step可以逐语句调试
举例有
在14行时使用step指令可以直接进入函数内部
我们可以使用b + 行号来在某一行设置断点
举几个例子
也可以使用b+函数名在该函数的开始设置断点,即
我们可以用info来查看对应信息
比如可以使用info+break来查看断点信息
也可以使用info+breakponits查看当前设置了哪些断点
还可以使用info+locals来查看当前栈帧局部变量的值
我们可以使用finish来执行到当前函数的返回,然后等待命令
我们可以使用print来打印表达式的值,通过表达式可以修改变量的值或者调用函数,也可以使用p+变量名 来打印变量值
我们可以使用set var + 修改对象与结果 来修改变量值,即
我们使用它表示从当前位置开始连续而非单步执行程序(即运行到下一个断点处)
对断点我们可以有如下这些操作
delete breakponits: 删除所有断点
delete breakponits n: 删除编号为n的断点
举个例子
disable breakpoints:禁用断点
enable breakpoints:启用断点
举个例子
我们可以使用display+变量名来跟踪查看一个变量,每次停下来都显示它的值
举个例子
同样地我们也可以使用undisplay来取消对先前设置的那些变量的跟踪(这里需要使用序号来取消追踪)
可以使用until+行号来跳至该行
这里可以使用breaktrace(bt)来查看各级函数的调用及参数
即