要在Linux操作系统中开发,要学会使用Linux操作系统下的环境基础开发工具。
yum工具是Linux操作系统(centos)下的软件商店。
查看要下载的软件:
yum list | grep 软件名
查看sl软件的信息(下图为查询出来的部分信息):
下载并安装软件:
sudo yum -y install 软件名
使用超级用户安装sl软件:
卸载软件:
sudo yum -y remove 软件名
尝试删除sl软件:
由于是普通用户,删除失败,需要使用超级用户的身份来卸载。
使用超级用户卸载该软件:
由于没有使用-y选项,需要输入y确认卸载该软件。
卸载成功。
yum作为软件商店必须知道软件的下载地址,这些下载地址一般被存储在配置文件中,这些配置文件就成为yum源。
进入yum源所在的目录下查看:
查看yum源:
yum源的更新:
关于软件
vim是Linux操作系统下内置的多模式编辑器。
在Linux下输入vim:
输入shift+: 然后输入q退出vim。
命令模式
打开vim时所处的模式就是命令模式,命令模式下是无法输入的。
用vim打开一个空文件,不进行任何操作,所处的是命令模式:
插入模式
插入模式下可以进行进行文本编辑。
底行模式
底行模式用于对文件中的指定内容执行保存、查找或替换等操作。
shift+:
即可进入插入模式。替换模式
替换模式下光标所在的字符会被替换成键盘输入的字符。
shift+r
即可进入插入模式。视图模式
视图模式针对的是块编辑,也就是选定某一块区域,连续的,快速的,高效的编辑文本。
ctrl+v
即可进入视图模式。视图模式下批量注释:
视图模式下批量取消注释:
set nu / set nonu
/要搜索的指定内容
– 查看下一个匹配,按下n,跳转到上一个匹配,按下shift+n!执行的命令
%s/替换前的字段/替换后的字段/g
vs 要打开的文件
– 按住ctrl并且快速按两下w切换光标到其他文件复制光标所在的若干行代码: (n)yy
– 如果使用yy指令复制代码前不输入数字,就代表复制当前行。
在光标所在行的下一行粘贴先前复制的若干行代码: (n)p
– 如果使用p指令粘贴代码前不输入数字,就代表在光标所在行的下一行粘贴一次。
撤销上一步操作: u
– 在底行模式下输入w保存的修改依旧可以撤销。
撤销上一次撤销: ctrl+r
– 在底行模式下输入w保存的修改依旧可以撤销。
剪切当前行所在的若干行代码: (n)dd
– 剪切的若干行代码可以使用(n)p
命令进行粘贴, 只进行剪切不进行粘贴相当于删除操作。
跳转到文本的最后一行: shift+g / G
跳转到文本的第一行: gg
跳转到文本的指定行行: n shift+g / n G
跳转到当前行文本的开始: shift+$
跳转到当前行文本的结尾: shift+^
以单词为分割向前跳转一次: b
以单词为分割向后跳转一次: w
快速大小写切换: shift+~
– 按下一次后会将光标所在的字符进行大小写切换,并且光标会自动移动到下一个位置。
将包括光标所在位置后的若干个字符替换成指定的字符: (n)r 要替换的指定字符
将包括光标及光标往右的若干个字符删除: (n)x
将包括光标及光标往左的若干个字符删除: (n)X
光标的位置移动: h(左)j(下)k(上)l(右)
在目录/etc/下面,有个名为vimrc的文件,这是系统中公共的配置文件,对所有用户都有效。
在每个用户的主目录/home/xxx下,都可以自己建立私有的配置文件,命名为“.vimrc”,这是该用户私有的配置文件,仅对该用户有效。
例如,普通用户在自己的主目录下建立了“.vimrc”文件后,在文件当中输入set nu指令并保存,下一次打开vim的时候就会自动显示行号。
vim的配置比较复杂,某些vim配置还需要使用插件,建议不要自己一个个去配置。比较简单的方法是直接执行以下指令(想在哪个用户下让vim配置生效,就在哪个用户下执行该指令,不推荐直接在root下执行):
curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh
然后按照提示输入root密码:
然后等待安装配置,最后手动执行source ~/.bashrc即可。
配置完成后,自动补全、行号显示以及自动缩进等功能就有了。
gcc/g++分别是用于编译C语言和C++的编译器,gcc和g++的使用方式(指令)相同。
程序的完整编译
gcc [-o 要生成的文件名] 要编译的文件
说明: gcc 文件名
就可以完成文件的编译在当前目录下生成名为a.out可执行程序,加上-o可以指定生成的程序的文件名。
程序的分布编译
程序编译的完整过程:
对文件进行预处理
gcc -E 要处理的文件名 [-o 要生成的文件名]
说明: 建议将生成的文件命名为.i后缀的文件。
对test.c文件进行预处理生成test.i文件:
test.i是由test.c预处理所得的,因此会将test.c的头文件展开使得代码行数变多,并且还会进行宏替换和条件编译和去除注释,因此在test.i文件中看到不到宏定义、条件编译和注释,此时文件内容还是C语言。
对文件进行编译
gcc -S 要处理的文件名 [-o 要生成的文件名]
说明: 建议将生成的文件命名为.s后缀的文件,可以对预处理的结果文件进行操作,也可以对源文件进行操作。
对预处理得到test.i文件进行编译得到test.s文件:
test.s是由test.i编译所得的,编译时会将C语言代码转化成汇编语言。
对文件进行汇编
gcc -c 要处理的文件名 [-o 要生成的文件名]
说明: 建议将生成的文件命名为.o后缀的文件,可以对预处理的结果文件、编译的结果文件进行操作,也可以对源文件进行操作。
对编译得到test.s文件进行汇编得到test.o文件:
test.o是由test.s汇编所得的,汇编时会将编译所得文件转化成不可执行的二进制代码。
对文件进行链接
文件的链接没有特殊的命令选项,只使用程序的完整编译的指令,Linux系统内置了C语言的库,编译器会自动完成链接过程。
查看可执行程序连接时使用的库
ldd 可执行程序文件名
ldd查看可执行程序连接的库:
动态库和静态库
编译器链接的库分为静态库和动态库。
静态库: 链接静态库时,会将静态库中对应的代码拷贝至可执行程序中,因此链接静态库的程序占用的空间较大,但是如果静态库消失了不影响程序的执行,静态库一般以.a为后缀。
动态库: 链接动态库时,会将动态库中对应的代码的地址拷贝至可执行程序中,因此动态链接的程序占用内存较小,但是如果静态库消失了程序就无法正常执行了,动态库一般以.so为后缀。
静态库:
优点:不依赖库,可以独立执行,程序的可移植性较高。
缺点:占用较大空间。
动态库:
优点:占用较小的空间,多个程序可以共同使用动态共享库的代码。
缺点:依赖库,不可以独立执行,程序的可移植性较低。
通过file指令查看程序的链接情况:
可以看到mytest可执行程序使用的是动态链接,使用的是共享库。
gcc [-o 要生成的文件名] 要编译的文件 -static
说明: 如果没有安装C语言静态库,可以执行yum install -y glibc-static
来安装,同样的可以执行yum install -y libstdc++-static
安装C++静态库。
在gcc编译是加上-static命令选项可以获得静态链接的程序:
可以看到mytest-static使用的是静态链接,并且文件大小大于动态链接的mytest可执行程序。
Makefile文件能够实现自动化编译功能的工具。
说明: Makefile文件需要创建在要编译的源文件的目录下。
Makefile的组成
Makefile由依赖关系和依赖方法组成的自动化编译工具。
依赖关系
依赖关系是用于指明目标文件和源文件的关系说明。
依赖方法
依赖方法是用于指明通过源文件得到目标文件的执行方法。
在目录下创建一个test.c源文件和Makefile(makefile)文件:
在Makefile文件中对于test.c文件建立如下依赖关系和依赖方法:
写好Makefile文件后,输入make命令执行Makefile文件:
执行make命令后,会自动在Makefile文件中查看依赖关系进行自动化编译,由于mytest依赖于test.o, test.o依赖于test.s, test.s依赖于test.i, test.i依赖于test.c的依赖关系,因此执行的依赖方法是和Makefile依赖关系的顺序相反的。
.PHONY关键字
.PHONY关键字是Makefile文件用于标识伪目标文件,使得依赖关系对应的依赖方法能够总是被完成。
对一个Makefile文件多次执行make命令:
通常多次执行make命令时只有第一次执行会成功,后续执行时,会报文件已经是最新的的错误信息,此时只需要将要完成的依赖关系使用.PHONY关键字标识即可让该依赖关系对应的依赖方法总是被完成,修改Makefile为如下内容:
make可以连续多次执行,不受限制:
通常.PHONY关键字用于目标文件的清理:
执行make clean指令,指定执行clean的依赖方法对应的依赖方法:
说明:
make指令识别不能多次执行的原理
make指令识别不能多次执行是通过对比源文件最后一次修改时间和可执行程序生成的时间,如下:
通过stat指令查看文件的创建和修改时间:
对已有文件touch可以修改文件的修改时间:
all关键字
all 是一个常用的关键字,用于定义一个名为 “all” 的目标。all 目标通常被用作默认目标,也就是在执行 make命令时,如果没有指定目标,默认会执行 all 目标。
为了更好的说明all关键字的作用,准备如下源文件test1.c、test2.c内容如下:
建立makefile文件,内容如下:
all:mytest1 mytest2
mytest1:test1.c
gcc -o mytest1 test1.c
mytest2:test2.c
gcc -o mytest2 test2.c
.PHONY:clean
clean:
rm -f mytest1 mytest2
输入make指令:
由于all目标的依赖关系需要mytest1、mytest2,因此make指令自动向下寻找mytest1、mytest2的依赖关系和依赖方法进行执行,完成多文件一次性自动化编译。
输入make clean一次性完成多个程序的清除:
gdb是Linux系统下的调试器。
为了方便进行调试,准备如下代码:
#include
int AddToTop(int top)
{
printf("enter the func\n");
int sum = 0;
for (int i=0; i <= top; i++)
{
sum += i;
}
printf("quit the func\n");
return sum;
}
int main()
{
int top = 100;
printf("the sum is %d\n", AddToTop(top));
return 0;
}
准备makefile文件,内容如下:
mytest:test.c
gcc -o mytest test.c -g -std=c99
.PHONY:clean
clean:
rm -f mytest
说明:
准备好代码和makefile文件后进行编译形成可执行程序,为了确保可执行程序有调试信息,使用readelf - S mytest | grep debug
查看:
使用gdb启动对程序的调试:
查看代码指令: l(list) + 数字 --从对应行开始显示代码。
从第一行开始显示代码:
由于gdb会记录上一次的命令,因此输入回车即可继续显示下面的代码:
打断点指令: b(breakpoint) + 数字/源文件:函数名 – 在代码的对应行打上断点。
在代码的18行打上断点:
查看已有断点指令: info b(breakpoint)。
部分信息说明:
运行程序指令: r(run) – 如果有断点会运行到断点处停止,没有断点会运行到程序结束位置。
运行程序至断点处:
再查看断点信息,断点信息中记录了断点被命中一次:
删除断点指令: d(delete) + 断点编号 – 删除对应断点编号的断点。
删除断点编号为1的断点:
关闭断点指令: disable breakpoint 断点编号。
关闭断点编号为2的断点:
说明: Enb信息列为n表示断点关闭,y为断点打开。
启动断点指令: enable breakpoint 断点编号。
启动断点编号为2的断点:
逐过程执行代码指令: n(next)。
run执行程序后进行输入next逐过程执行代码:
逐语句执行代码指令: s(step)。
run执行程序后进行输入s逐语句执行代码:
通过bt指令可以查看函数调用结构:
监视变量指令: p/display 变量名 – p为显示一次,dispaly为常显示,undisplay+编号取消常显示。
监视变量的值:
取消编号为1的常显示:
跳转代码指令: until + 数字 – 在函数体,将代码跳转至对应行。
在AddToTop函数中跳转至第10行:
完成当前函数的执行指令: finish – 直接完成当前函数的执行。
直接完成AddToTop函数的执行,并且得到返回值:
跳转到下一个断点的位置指令: c(continue)。
退出gdb指令: quit。