Linux:编译,调试和Makefile
一丶vim编译器
### 基本概念
模式:Vim有几种不同的模式,包括:
命令/正常/普通模式:控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode
插入模式:只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。该模式是我们后面用的最频繁 的编辑模式。
末行/底行模式:文件保存或退出,也可以进行文件替换,找字符串,列出行号等操作。 在命令模式下,shift+: 即可进入该模 式。要查看你的所有模式:打开vim,底行模式直接输入
###基本操作
进入vim,在系统提示符号输入vim及文件名称后,就进入vim全屏幕编辑画面:
$ vim test.c 不过有一点要特别注意,就是你进入vim之后,是处于[正常模式],你要切换到[插入模式]才能够输入文 字。
[正常模式]切换至[插入模式]
输入a 输入i 输入o
[插入模式]切换至[正常模式]
目前处于[插入模式],就只能一直输入文字,如果发现输错了字,想用光标键往回移动,将该字删除,可 以先按一下「ESC」键转到[正常模式]再删除文字。当然,也可以直接删除。
[正常模式]切换至[末行模式] 「shift + ;」, 其实就是输入「:」 退出vim及保存文件,在[正常模式]下,按一下「:」冒号键进入「Last line mode」,例如:
: w (保存当前文件): wq (输入「wq」,存盘并退出vim) : q! (输入q!,不存盘强制退出vim)
注意:底行模式和插入模式无法直接切换
###命令模式命令集
光标移动:
vim可以直接用键盘上的光标来上下左右移动,但正规的vim是用小写英文字母「h」、「j」、「k」、 「l」,分别控制光标左、下、上、右移一格 按
「G」:移动到文章的最后
按「 $ 」:移动到光标所在行的“行尾”
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「n l」:光标移到该行的第n个位置,如:5 l,56 l
按[gg]:进入到文本开始
按[shift+g]:进入文本末端 按「ctrl」+「b」:屏幕往“后”移动一页
按「ctrl」+「f」:屏幕往“前”移动一页
按「ctrl」+「u」:屏幕往“后”移动半页
按「ctrl」+「d」:屏幕往“前”移动半页
删除文字
「x」:每按一次,删除光标所在位置的一个字符
「n x」:例如,「6x」表示删除光标所在位置的“后面(包含自己在内)”6个字符
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符 「n X」:例如,「20X」表示删除光标所在位置的“前面”20个字符
「dd」:删除光标所在行 「n dd」:从光标所在行开始删除#行
复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「n yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「n yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完 成复制与粘贴功能。
替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
撤销上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回 复。
「ctrl + r」: 撤销的恢复,撤销上一次撤销。
更改 「cw」:更改光标所在处的字到字尾处
「c n w」:例如,「c3w」表示更改3个字
跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「nG」:例如,「15G」,表示移动光标至文章的第15行行首
###vim末行模式命令集
在使用末行模式之前,请记住先按「ESC」键确定您已经处于正常模式,再按「:」冒号即可进入末行模式。
列出行号 「set nu」: 输入「set nu」后,会在文件中的每一行前面列出行号。
跳到文件中的某一行 「n」
:「n」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15, 再回车,就会跳到文章的第15行。
查找字符 「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按 「n」会往后寻找到您要的关键字为止。 「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直 按「n」会往前寻找到您要的关键字为止。
保存文件 「w」: 在冒号输入字母「w」就可以将文件保存起来
离开vim 「q」:按「q」就是退出,如果无法离开vim,可以在「q」后跟一个「!」强制离开vim。 「wq」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
vim最后声明:Linux刚开始使用vim编译器使用起来感觉不如vs等编译器,可以搜索相关资料配置vim。
二丶gcc / g++
这里只讲方法
###使用GCC编译源代码
在终端中,使用以下命令编译hello.c
:
gcc hello.c -o hello
这里,-o
选项用于指定输出文件的名称。
###GCC编译链接过程
1. 预处理(Preprocessing)
预处理阶段主要处理源代码中的宏定义、条件编译指令等。使用以下命令查看预处理后的代码:
gcc -E hello.c -o hello.i
2. 编译(Compilation)
编译阶段将预处理后的代码转换为汇编代码。使用以下命令进行编译:
gcc -S hello.i -o hello.s
3. 汇编(Assembly)
汇编阶段将汇编代码转换为机器代码。使用以下命令进行汇编:
gcc -c hello.s -o hello.o
4. 链接(Linking)
链接阶段将编译生成的目标文件与库文件进行合并,生成可执行文件。在我们的例子中,使用以下命令进行链接:
gcc hello.o -o hello
实际上,在第一步编译源代码时,GCC已经自动完成了预处理、编译、汇编和链接的过程。以上步骤只是为了说明编译链接的整个过程。
gcc 和 g++ 在这个过程几乎一样,差别也是细微的关于库那方面的差别
三丶调试:gdb
背景
程序的发布方式有两种,debug模式和release模式
Linux gcc/g++出来的二进制程序,默认是release模式
要使用gdb调试,必须在源代码生成二进制程序的时候, 加上 -g 选项
开始使用 gdb File 退出: ctrl + d 或 quit
调试命令:
list/l 行号:显示File源代码,接着上次的位置往下列,每次列10行。
list/l 函数名:列出某个函数的源代码。
r或run:运行程序。
n 或 next:单条执行。
s或step:进入函数调用
break(b) 行号:在某一行设置断点
break 函数名:在某个函数开头设置断点
info break :查看断点信息。
finish:执行到当前函数返回,然后挺下来等待命令
print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
p 变量:打印变量值。
set var:修改变量的值
continue(或c):从当前位置开始连续而非单步执行程序
run(或r):从开始连续而非单步执行程序
delete breakpoints:删除所有断点
delete breakpoints n:删除序号为n的断点
disable breakpoints:禁用断点
enable breakpoints:启用断点
info(或i) breakpoints:参看当前设置了哪些断点
display 变量名:跟踪查看一个变量,每次停下来都显示它的值
undisplay:取消对先前设置的那些变量的跟踪
until X行号:跳至X行
breaktrace(或bt):查看各级函数调用及参数
info(i) locals:查看当前栈帧局部变量的值
quit:退出gdb
四丶Makefile
背景
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的 规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂 的功能操作 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编 译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命 令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一 种在工程方面的编译方法。 make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
###vim makefile
看图还是比较明了的,依赖文件列表也可以为空,就像clean一样,.PHONY 就像一个声明一样。
### make 和 make clean
从上往下依次看,我们这个目录中只有makefile 和 一些源文件,先执行make命令,然后系统自动执行了g++命令,再看目录下的文件,多出来 .exe文件,并且可以执行,当我们再次执行make命令时被系统告知,.exe文件是最新的,因为如果每次执行make命令都编译一次没有修改的代码并且这些代码很长,源文件很多,就会很浪费时间和空间。
紧接着我们执行了make clean命令,这里加上clean是因为make命令在读取makefile文件的时候默认从上往下读,不会执行makefile里面的所有的命令,写在前面的make就默认执行。同时注意,我们执行了多次make clean 命令,系统并没有警告,这就跟上面所说的.PHONY 有关了。
这张图中,$@ 和 $^ 其中$ 符号默认,@代表标文件 myproject.exe,^代表所有的依赖文件,文件太多不想写可用。
接下来我们可以看到makefile中一系列的目标文件,依赖文件和依赖关系,我们按照编译链接的逻辑将一整个g++ 流程拆分成 -E -S -c 得到 .i .s .o 文件,上面提到make指令从上往下读取,但在这里make指令是按顺序执行代码,实际上是make找到了.exe 需要 .o ,然后向下找 .o 发现 .o文件没用生成,就继续执行,找到了可以生成.o 文件的 .s 文件,继续向下找需要的文件,执行完成后返回上一个文件继续执行,这个过程跟栈可以说是一模一样。
###最后的makfefile
1 bin=myproject.exe
2 src=myproject.cpp
3
4 $(bin):$(src)
5 g++ -o $@ $^
6
7 .PHONY:clean
8 clean:
9 rm -f $(bin)
在makefile中可以定义变量,$ 是从bin 或者 src中提取内容 ,感觉就像指针和解引用一样,定义变量时等号两边最近的两个变量不可有空格,src可以跟多个cpp(或其他)变量,空格隔开,这种写法还是比较简单易懂的。