Linux基础开发工具
# 软件包管理器-yum
在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序。但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装。软件包和软件包管理器, 就好比 "App" 和 "应用商店" 这样的关系。
yum
(Yellow dog Updater, Modified)是Linux下非常常用的一种包管理器. 主要应用在Fedora, RedHat, Centos等发行版上。
# 查看软件包
yum list
示例搜索lrzsz
lrzsz.x86_64 0.12.20-36.el7 @base
- 软件包名称: 主版本号.次版本号.源程序发行号-软件包的发行号.主机平台.cpu架构.
- "x86_64" 后缀表示64位系统的安装包, "i686" 后缀表示32位系统安装包. 选择包时要和系统匹配.
- "el7" 表示操作系统发行版的版本. "el7" 表示的是 centos7/redhat7. "el6" 表示 centos6/redhat6.
- "base" 表示的是 "软件源" 的名称
# 安装软件包
yum install xxx
# 卸载软件包
yum remove xxx
# 编辑器-vim
vim/vi都是多模式编辑器,不同的是vim是vi的升级版本,它不仅兼容vi的所有指令,而且还有一些新的特性在里面。例如语法加亮,可视化操作不仅可以在终端运行,也可以运行于x window、 mac os、windows。
# 三种模式
vim的三种模式,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
- 正常/普通/命令模式(Normal) 控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode
- 插入模式(Insert) 只有在Insert下,才可以做文字输入,按「ESC」键可回到命令行模式。
- 末行模式(last line) 文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。
在命令模式下,shift + : 即可进入该模式。
要查看你的所有模式:打开vim,底行模式直接输入:help vim-modes
# 基本操作
- [正常模式]切换至[插入模式]:输入i/a/o
- [插入模式]切换至[正常模式]:Esc
- [正常模式]切换至[末行模式]:Shift + ; == :
- [末行模式]切换至[正常模式]:Esc
- 退出vim及保存文件:在[正常模式]下,进入[末行模式],再按 wq 即可退出并保存
# 命令模式命令集
【移动光标】
- 按「k」:光标上移。
- 按「j」:光标下移。
- 按「h」:光标左移。
- 按「l」:光标右移。
- 按「$」:移动到光标所在行的行尾。
- 按「^」:移动到光标所在行的行首。
- 按「gg」:移动到文本开始。
- 按「Shift + g」:移动到文本末尾。
- 按「n + Shift + g」:移动到第n行行首。
- 按「n + Enter」:当前光标向下移动n行。
- 按「w」:光标从左到右,从上到下的跳到下一个字的开头。
- 按「e」:光标从左到右,从上到下的跳到下一个字的结尾。
- 按「b」:光标从右到左,从下到上的跳到上一个字的开头
【删除】
- 按「x」:删除光标所在位置的字符。
- 按「nx」:删除光标所在位置开始往后的n个字符。
- 按「X」:删除光标所在位置的前一个字符。
- 按「nX」:删除光标所在位置的前n个字符。
- 按「dd」:删除光标所在行。
- 按「ndd」:删除光标所在行开始往下的n行。
【复制粘贴】
- 按「yy」:复制光标所在行到缓冲区。
- 按「nyy」:复制光标所在行开始往下的n行到缓冲区。
- 按「yw」:将光标所在位置开始到字尾的字符复制到缓冲区。
- 按「nyw」:将光标所在位置开始往后的n个字复制到缓冲区。
- 按「p」:将已复制的内容在光标的下一行粘贴上。
- 按「np」:将已复制的内容在光标的下一行粘贴n次。
【剪切】
- 按「dd」:剪切光标所在行。
- 按「ndd」:剪切光标所在行开始往下的n行。
- 按「p」:将已剪切的内容在光标的下一行粘贴上。
- 按「np」:将已剪切的内容在光标的下一行粘贴n次。
【撤销】
- 按「u」:撤销。
- 按「Ctrl + r」:恢复刚刚的撤销。
【大小写切换】
- 按「~」:完成光标所在位置字符的大小写切换。
- 按「n~」:完成光标所在位置开始往后的n个字符的大小写切换。
【替换】
- 按「r」:替换光标所在位置的字符。
- 按「R」:替换光标所到位置的字符,直到按下「Esc」键为止。
【更改】
- 按「cw」:将光标所在位置开始到字尾的字符删除,并进入插入模式。
- 按「cnw」:将光标所在位置开始往后的n个字删除,并进入插入模式。
【翻页】
- 按「Ctrl + b」:上翻一页。
- 按「Ctrl + f」:下翻一页。
- 按「Ctrl + u」:上翻半页。
- 按「Ctrl + d」:下翻半页。
# 底行模式命令集
【行号设置】
- 「set nu」:显示行号。
- 「set nonu」:取消行号。
【保存退出】
- 「w」:保存文件。
- 「q」:退出vim,如果无法离开vim,可在「q」后面跟一个「!」表示强制退出。
- 「wq」:保存退出。
【分屏指令】
- 「vs 文件名」:实现多文件的编辑。
- 「Ctrl + w + w」:在正常模式下光标在多屏幕下进行切换。
【执行指令】
- 「! + 指令」:在不退出vim的情况下,可以在指令前面加上「!」就可以执行Linux的指令,例如查看目录、编译当前代码等。
# 简单配置vim
在目录 /etc/ 下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效。而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为:.vimrc
- /root目录下,通常已经存在一个.vimrc文件,如果不存在,则创建之。
- 切换用户成为自己执行 su ,进入自己的主工作目录,执行 cd ~打开自己目录下的.vimrc文件,执行 vim .vimrc
常用配置选项,用来测试:
- 设置语法高亮:
syntax on
- 显示行号:
set nu
- 设置缩进的空格数为4:
set shiftwidth=4
- ...
# 编译器-gcc/g++
gcc和g++
分别是GNU的C和C++的编译器,gcc和g++在执行编译的时候一般有以下四个步骤:
- 预处理(头文件展开、去注释、宏替换、条件编译)
- 编译(C/C++代码翻译成汇编语言)
- 汇编(汇编代码转为二进制目标代码)
- 链接(将汇编过程产生的二进制代码进行链接)
# gcc/g++语法
语法:gcc/g++ 选项 文件
选项:
-E
只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面-S
编译到汇编语言不进行汇编和链接-c
编译到目标代码-o
文件输出到文件-static
此选项对生成的文件采用静态链接-g
生成调试信息,GNU调试器可利用该信息-shared
此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库-w
不生成任何警告信息。-Wall
生成所有警告信息
# 过程
预处理:
gcc -E test.c -o test.i
- -E选项的作用是让gcc/g++在预处理结束后停止编译过程
- -o选项是指目标文件,
xxx.i
文件为已经过预处理的原始程序
编译:
gcc -S test.i -o test.s
- 用户可以使用-S选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码
- -o选项是指目标文件,
xxx.s
文件为已经过翻译的原始程序
汇编:
gcc -c test.s -o test.o
- 汇编阶段是把编译阶段生成的
xxx.s
文件转成目标文件 - 使用-c选项就可以得到汇编代码转化为
xxx.o
的二进制目标代码了
链接:
gcc test.o -o test
- gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件
- 若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out
链接的本质:我们调用库函数的手如何与标准库链接的?
# 动态库和静态库
- 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也 就不再需要库文件了。其后缀名一般为“.a”
- 动态库在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时 链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态 库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件。 gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证
动态链接:优点:省空间(磁盘的空间,内存的空间),bin体积小,加载速度快;缺点:依赖动态库,程序可移植性较差。
静态链接:优点:不依赖第三方库,程序的可移植性较高;缺点:浪费空间。
# 调试器-gdb
# gdb使用须知
程序发布方式: 1、debug版本:程序本身会被加入更多的调试信息,以便于进行调试。 2、release版本:不会添加任何调试信息,是不可调试的。
# gdb命令集
【进入gdb】
指令:gdb 文件名
【调试】
- 「run/r」:运行代码(启动调试)。
- 「next/n」:逐过程调试。
- 「step/s」:逐语句调试。
- 「until 行号」:跳转至指定行。
- 「finish」:执行完当前正在调用的函数后停下来(不能是主函数)。
- 「continue/c」:运行到下一个断点处。
- 「set var 变量=x」:修改变量的值为x。
【显示】
- 「list/l n」:显示从第n行开始的源代码,每次显示10行,若n未给出则默认从上次的位置往下显示.。
- 「list/l 函数名」:显示该函数的源代码。
- 「print/p 变量」:打印变量的值。
- 「print/p &变量」:打印变量的地址。
- 「print/p 表达式」:打印表达式的值,通过表达式可以修改变量的值。
- 「display 变量」:将变量加入常显示(每次停下来都显示它的值)。
- 「display &变量」:将变量的地址加入常显示。
- 「undisplay 编号」:取消指定编号变量的常显示。
- 「bt」:查看各级函数调用及参数。
- 「info/i locals」:查看当前栈帧当中局部变量的值。
【断点】
- 「break/b n」:在第n行设置断点。
- 「break/b 函数名」:在某函数体内第一行设置断点。
- 「info breakpoint/b」:查看已打断点信息。
- 「delete/d 编号」:删除指定编号的断点。
- 「disable 编号」:禁用指定编号的断点。
- 「enable 编号」:启用指定编号的断点。
【退出gdb】
- 「quit/q」:退出gdb。
# 项目自动化构建工具-make/makefile
# 引入
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的 规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂 的功能操作。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编 译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
# 依赖关系和依赖方法
- 依赖关系: 文件A的变更会影响到文件B,那么就称文件B依赖于文件A。
例如,test.o文件是由test.c文件通过预处理、编译以及汇编之后生成的文件,所以test.c文件的改变会影响test.o,所以说test.o文件依赖于test.c文件。
- 依赖方法: 如果文件B依赖于文件A,那么通过文件A得到文件B的方法,就是文件B依赖于文件A的依赖方法。
例如,test.o依赖于test.c,而test.c通过gcc -c test.c -o test.o指令就可以得到test.o,那么test.o依赖于test.c的依赖方法就是gcc -c test.c -o test.o
# 多文件编写
例如,编写一个进度条小程序:
.
├── Makefile
├── progress
├── progress.cpp
├── progress.h
└── test.cpp
2
3
4
5
6
Makefile文件:
test:test.cpp progress.cpp
g++ -o progress test.cpp progress.cpp # 不需要头文件
.PHONY:clean
clean:
rm -rf progress
2
3
4
5
progress.cpp文件:
#include"progress.h"
#include <iostream>
#include <iomanip>
#include <chrono>
#include <thread>
#include <string>
void progresson() {
const int totalSteps = 100;
std::string proc(totalSteps, ' ');
const std::string symbols = "\\|/-";
for (int i = 0; i <= totalSteps; ++i) {
proc[i] = '#';
std::cout << "[" << proc << "]" << "[" << std::setw(3) << i << "%]" << "[" << symbols[i % 4] << "]\r" << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(60));
}
std::cout << std::endl;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19