Linux下C++/C的编译调试
这几天因为任务的原因我需要在ubuntu下编写程序。因此恶补了许多linux程序编写的知识。我分以下几个方面总结我所学的知识。
- gcc,g++,make命令的使用
- gdb 调试
- VScode的使用
- cmake使用
gcc,g++,make命令的使用
从大学接触程序设计开始就一直依赖IDE,使用了VC6.0,Visual Studio 2010,Pycharm,eclipse。但是从来不清楚这些文件是如何转换成计算机可运行的程序。在Linux环境中这些事情都要由程序员来处理,让我对程序编译的过程更加的清楚。
对于C++程序(C也是类似的,只是相应的g++命令要换成gcc命令),我们假设有一个main.cpp文件,这个程序含有main函数且不依赖其它的文件。编译命令
g++ main.cpp -o main
-o的目的是为生成的可执行文件添加文件名,如果没有这个生成的可执行文件名为a.out。
现在假设有三个文件main.cpp, class1.h, class1.cpp。其中main.cpp是主函数,使用类class1生成对象,也包含了class1的头文件(#include"class1.h"
)。如果存在调用其它文件,直接使用g++是不可行的。因为g++会连续执行编译链接,应该先对每个文件编译成目标文件(.o)再链接起来,命令是
g++ -c main.cpp -o main.o
g++ -c class1.cpp -o class1.o
g++ main.o class.o -o main
这种方法对C文件只是把g++换成gcc。可是对于频繁编译的场景,每次都输入这些命令太累了,所以就有了make命令。make命令可以编译一个文件,但是要舍去文件后缀名,例如编译无依赖的main.cpp,命令:
make main
对于有依赖的项目要编写Makefile文件。这个文件没有后缀名,文件名就是Makefile。我们把这个文件放在项目的根目录下,在根目录的命令行下输入make
就可以编译了。现在我们看看这个文件怎么制作:
main : main.o class1.o
gcc main.o class1.o -o main
main.o : main.cpp
gcc -c main.cpp -o main.o
class1.o : class1.cpp
gcc -c class1.cpp -o class1.o
clean:
rm -i *.o main
第一句说明了文件依赖关系,main可执行文件需要main.o, class1.o才能生成,接着回车换行加一个制表符后是编译main的命令行。注意makefile文件的编写和实际的编译过程是相反的。
gdb调试
理解了文件的编译过程我们还要明白程序在linux环境下是如何用命令行调试的。
如果一个程序需要调试,那么编译时需要将源代码也编译进程序中。我们以无依赖的main.cpp为例:
g++ main.cpp -o main -g
注意后面要加-g,否则不能调试。我们输入命令:gdb main
进入gdb的环境中,命令行会出现
hchen/test> gdb tst <---------- 启动GDB
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-suse-linux"...
(gdb)
我们可以使用以下命令调试
命令 | 功能 |
---|---|
b | 设置断点,例:b 12 在第12行设置断点,b main 在main函数第一句设断点 |
s | 逐条执行,进入函数 |
n | 单条语句执行,不进入函数 |
d | 清除断点,d 1 清楚1号断点,d 清楚所有断点 |
r | 开始运行程序 |
q | 离开gdb环境 |
finish | 从当前函数中跳出 |
p | 显示数值,p sum 显示sum变量的值 |
c | 继续执行 |
其实IDE就是对这些命令的封装,但我们不应该忘记程序是怎么从代码生成的。 |
VScode的使用
有了命令行编译和调试的经验,VScode就方便理解了。因为VScode没有Visual Studio那么傻瓜,编译和调试过程必须通过json文件来设置,其中必须要和g++,gcc,make,gdk命令打交道。这里不细讲这个过程,有兴趣可以看在linux中使用VS code编译C++项目。这里我讲一下自己在学习中遇到的错误。
首先VScode是一个项目对应一个工作目录。这一点和pycharm不一样。在pycharm中我可以在目录project下建立project1,project2等等,且仅加载目录project为当前工作目录,这样不会影响编译。但VScode的编译需要通过makefile,不建议在工作目录建立多个项目的子目录,最好工作目录下就一个项目。
VScode并没有对编译调试过程完全封装,可以说只是使用json标记了编译调试中的参数,实际还是使用g++,make,gdb方法。我们先建立launch.json文件,修改program属性值从{workspaceRoot}变为{workspaceRoot}/main。这里main是最终用gdb调试的可执行程序的名字。
有了launch.json只是声明了gdb调试了步骤,但是编译还是要自己编写Makefile文件,调用make命令。为了避免每次调用make命令,可以在launch.json中添加"preLaunchTask": "build"来生成tasks.json文件,说明调试前的编译任务。推荐使用命令行版本,简单,容易理解。注意这里的build只是命令的名字,可以自定义,但是要和tasks.json中匹配才可以。
综上,我们向VScode制定了gdb的调试目标和make的编译目标,调试过程和其他IDE是相似的。剩下的就是makefile的编写,这个工作要靠cmake来帮我们做了。
cmake使用
推荐文章在 linux 下使用 CMake 构建应用程序,简单易懂。我个人理解cmake与make:cmake可以不同环境中的项目,自动测试编译器的特性,多文件管理,找库调包更方便。但要配置好也是很费劲的。