【菜鳥玩Linux開發】在Linux中使用VS Code編譯調試C++項目

最近項目需求,須要在Linux下開發C++相關項目,通過一番摸索,簡單總結了一下如何經過VS Code進行編譯調試的一些注意事項。linux

關於VS Code在Linux下的安裝這裏就不提了,不論是CentOS仍是Ubuntu,若是不懂且搜Q足夠的狀況下,你會解決的。ios

一. 前置知識——gcc/g++的編譯連接過程

在Windows下,若是你用Visual Studio進行開發,C/C++的編譯器通常採用微軟提供的MSBuild;在Linux下C/C++的編譯器大多采用gcc/g++。既然要在Linux下進行C++開發,頗有必要了解一下g++編譯器的一些基本知識。json

假設我如今有一個最簡單的C++文件:windows

1 #include <iostream>
2 using namespace std;
3 int main() {
4     cout << "Hello, world!!!!" << endl;
5     return 0;
6 }

接下來如何編譯呢?簡單來講分紅兩步:先編譯,再連接函數

1. 安裝g++編譯器

啓動終端,進入root模式,安裝gcc和g++工具

Ubuntu:ui

xxx@xxx:~$ sudo apt-get install build-essential

xxx@xxx:~$ gcc --version
xxx@xxx:~$ sudo apt-get install g++-4.8
xxx@xxx:~$ g++ --version

CentOS:spa

[xxx@xxx ~]$ su
[xxx@xxx ~]# yum install gcc
[xxx@xxx ~]# gcc --version
[xxx@xxx ~]# yum install gcc-g++
[xxx@xxx ~]# g++ --version

2. 編譯hello.cpp

[xxx@xxx ~]$ g++ -c hello.cpp

輸出結果是一個hello.o文件,這是編譯過程的生成的中間文件。-c 表示只編譯,不連接debug

3. 連接hello.o生成hello.out

[xxx@xxx ~]$ g++ -o hello.out hello.o

輸出結果是一個hello.out文件,這是最終的可執行文件。-o 表示輸出文件,hello.o是上一步生成的.o文件。3d

固然,若是第二、3步是能夠合併執行,直接執行命令

[xxx@xxx ~]$ g++ -o hello.out hello.cpp

然而第二、3步分開執行是有意義的,後面會講到。

4. 運行hello.out

最後執行如下hello.out驗證一下輸出結果唄

[xxx@xxx ~]$ ./hello.out

二. 構建項目

實際開發過程當中固然不可能只有一個cpp這麼簡單,有時候會有很是多的.h和.cpp文件相互配合,那麼上面直接經過g++編譯可執行文件就沒那麼簡單了。咱們須要藉助Make這個強大的項目構建工具,幫助咱們構建和組織項目代碼。

假設如今有以下3個文件:hw2.cpp、solution.h和solution.cpp

1 /* solution.h */
2 class Solution {
3 public:
4     void Say();
5 };
1 /* solution.cpp */
2 #include <iostream>
3 #include "solution.h"
4 void Solution::Say(){
5    std::cout << "HI!" << std::endl;
6 }
1 /* hw2.cpp */
2 #include "solution.h"
3 int main () {
4     Solution sln;
5     sln.Say();
6     return 0;
7 }

 

能夠看到這個簡單例子包括頭文件引用、定義和實現分離等狀況,若是直接g++ -o hw2.out hw2.cpp將會報未定義引用的錯誤:

[xxx@xxx ~]$ g++ -o hw2.out hw2.cpp
/tmp/ccIMYTxf.o:在函數‘main’中:
hw2.cpp:(.text+0x10):對‘Solution::Say()’未定義的引用
collect2: 錯誤:ld 返回 1

 

這時Make就該大顯身手了。

首先咱們還須要瞭解一下makefile。

在項目的根目錄下建立一個makefile文件,以告訴Make如何編譯和連接程序。

1 build : hw2.o solution.o
2     g++ -o build hw2.o solution.o #注意前面必須是tab,不能是空格
3 hw2.o : hw2.cpp solution.h
4     g++ -g -c hw2.cpp
5 solution.o : solution.h solution.cpp
6     g++ -g -c solution.cpp
7 clean :
8     rm hw2.o solution.o build

 

先來解釋一下makefile的基本語法規則:

target ... : prerequisites ...
  command    #注意前面是tab

target是一個目標文件,能夠是Object File,也能夠是執行文件,還能夠是一個標籤;

prerequisites是要生成那個target所須要的文件或是目標;

command是make須要執行的命令(任意的Shell命令)。

說白了就是target這一個或多個目標,依賴於prerequisites列表中的文件,其執行規則定義在command裏。若是prerequisites列表中文件比target要新,就會執行command,不然就跳過。這就是整個make過程的基本原理。

 

那麼,咱們回頭看看上面定義的makefile文件,咱們解釋一下每兩行的做用

1 build : hw2.o solution.o
2     g++ -o build hw2.o solution.o

target是build,依賴於hw2.o 和 solution.o,執行的命令是 g++ -o build hw2.o solution.o

意思是經過g++連接hw2.o和solution.o,生成可執行文件build,prerequisites有兩個.o文件,是由於代碼裏hw2引用了solution.h。

 

3 hw2.o : hw2.cpp solution.h
4      g++ -g -c hw2.cpp

target是hw2.o,依賴於hw2.cpp和solution.h,執行命令是g++ -g -c hw2.cpp

意思是經過g++編譯hw2.cpp文件,生成hw2.o文件,g++命令中 -g 表示生成的文件是可調試的,若是沒有-g,調試時沒法命中斷點。

 

5 solution.o : solution.h solution.cpp
6     g++ -g -c solution.cpp

同上,編譯solution.cpp文件,生成solution.o文件。

 

7 clean :
8     rm hw2.o solution.o build

這裏clean不是一個可執行文件,也不是一個.o文件,它只不過是一個動做名字,相似於label的做用,make不會去找冒號後的依賴關係,也不會自動執行命令。若是要執行該命令,必須在make後顯示指出整個動做的名字,如make clean。

 

好了,接下來講一下make的工做原理。在默認的方式下,咱們只需輸入make,則發生瞭如下行爲:

a. make在當前目錄下找名爲makefile或Makefile的文件;

b. 若是找到,它會找文件中的第一個target,如上述文件中的build,並做爲終極目標文件;

c. 若是第一個target的文件不存在,或其依賴的.o 文件修改時間要比target這個文件新,則會執行緊接着的command來生成這個target文件;

d. 若是第一個target所依賴的.o文件不存在,則會在makefile文件中找target爲.o的依賴,若是找到則執行command,.o的依賴必是.h或.cpp,因而make能夠生成 .o 文件了

e. 回溯到b步執行最終目標

 

看一下執行結果

[xxx@xxx ~]$ make
g++ -g -c hw2.cpp
g++ -g -c solution.cpp
g++ -o build hw2.o solution.o #注意前面必須是tab,不能是空格
[xxx@xxx ~]$ ./build 
HI!
[xxx@xxx ~]$

 

因爲makefile文件中加了-g這一選項,因而能夠經過gdb進行調試,而且會命中斷點,這裏感興趣能夠再瞭解一下gdb的使用。

接下來咱們要說到如何經過VS Code進行調試。

 

三. 在VS Code中編譯調試

首先安裝完VS Code以後,還須要安裝一下擴展cpptools,請自行完成。

 

點擊菜單 查看-> 調試,或直接快捷鍵ctrl + shift + D

 

點擊設置圖標,在彈出的選擇環境中選擇C++(GDB/LLDB),會自動建立一個launch.json文件

顧名思義,laucn.json的做用是告訴VS Code如何執行啓動任務,也就是咱們要把什麼文件啓動起來,在上述例子中顯然是build這個可執行文件了。修改一下json文件中波浪線的program節點,改爲${workspaceRoot}/build,其他的暫時不變

 

 1 {
 2     "version": "0.2.0",
 3     "configurations": [
 4         {
 5             "name": "C++ Launch",
 6             "type": "cppdbg",
 7             "request": "launch",
 8             "program": "${workspaceRoot}/build",
 9             "args": [],
10             "stopAtEntry": false,
11             "cwd": "${workspaceRoot}",
12             "environment": [],
13             "externalConsole": true,
14             "linux": {
15                 "MIMode": "gdb"
16             },
17             "osx": {
18                 "MIMode": "lldb"
19             },
20             "windows": {
21                 "MIMode": "gdb"
22             }
23         },
24         {
25             "name": "C++ Attach",
26             "type": "cppdbg",
27             "request": "attach",
28             "program": "${workspaceRoot}/build",
29             "processId": "${command.pickProcess}",
30             "linux": {
31                 "MIMode": "gdb"
32             },
33             "osx": {
34                 "MIMode": "lldb"
35             },
36             "windows": {
37                 "MIMode": "gdb"
38             }
39         }
40     ]
41 }

接着咱們嘗試一下F5,開始調試,結果能夠看到報了一個缺乏build文件的錯誤。緣由是咱們還沒執行make編譯出可執行文件呢。咱們在launch.json文件中,添加一個preLaunchTask的節點,並設置值爲「build」。注意這裏的build不是指可執行文件build,而是一個名爲build的任務!

 1 {
 2     "version": "0.2.0",
 3     "configurations": [
 4         {
 5             "name": "C++ Launch",
 6             "type": "cppdbg",
 7             "request": "launch",
 8             "program": "${workspaceRoot}/build",
 9             "args": [],
10             "stopAtEntry": false,
11             "cwd": "${workspaceRoot}",
12             "environment": [],
13             "externalConsole": true,
14             "preLaunchTask": "build", 15             "linux": {
16                 "MIMode": "gdb"
17             },
18             "osx": {
19                 "MIMode": "lldb"
20             },
21             "windows": {
22                 "MIMode": "gdb"
23             }
24         },
25         {
26             "name": "C++ Attach",
27             "type": "cppdbg",
28             "request": "attach",
29             "program": "${workspaceRoot}/build",
30             "processId": "${command.pickProcess}",
31             "linux": {
32                 "MIMode": "gdb"
33             },
34             "osx": {
35                 "MIMode": "lldb"
36             },
37             "windows": {
38                 "MIMode": "gdb"
39             }
40         }
41     ]
42 }

再嘗試F5,會提示一個信息:

點擊配置任務運行程序,並選擇Others, 會自動生成一個tasks.json文件,這個文件的做用就是告訴launch或者編譯器須要執行什麼操做。顯然咱們這裏要執行make命令,修改tasks.json爲以下:

 1 {
 2     "version": "0.1.0",
 3     "command": "make",
 4     "showOutput": "always",
 5     "tasks": [
 6         {
 7             "taskName": "clean"
 8         },
 9         {
10             "taskName": "build", 11             "problemMatcher": {
12                 "owner": "cpp",
13                 "fileLocation":  ["relative", "${workspaceRoot}"],
14                 "pattern": {
15                     "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
16                     "file": 1,
17                     "line": 2,
18                     "column": 3,
19                     "severity": 4,
20                     "message": 5
21                 }
22             }
23         }
24     ]
25 }

其中tasks節點是一組任務,注意到其中一個名爲build的任務,這就是launch.json文件中指定的preLaunchTask,代表在啓動可執行程序以前,會先執行一下preLaunchTask即這裏的build任務,從新make一下代碼,更新可執行程序以後再啓動。

固然也能夠指運行tasks這些任務而不啓動可執行程序,直接ctrl + shift + B,在VSC的console裏能夠看到和終端執行同樣的輸出:

執行完後,項目中會多出.o和build文件

 

關於VS Code的launch.json和tasks.json中更多節點的含義,參考

https://code.visualstudio.com/docs/editor/debugging

https://code.visualstudio.com/docs/editor/tasks

 

接着設置好斷點以後F5,就能夠進入斷點調試了

 

 --------------------------------------------------------------------------------------------------------------------------------------------------

 

本篇總結了gcc/g++和make/makefile的基礎知識,以及在Linux下使用VS Code進行調試開發的方法,但願對正在挖坑的同窗有所幫助,坑避免一個是一個。

相關文章
相關標籤/搜索