最近項目需求,需要在Linux下開發C++相關項目,經過一番摸索,簡單總結了一下如何通過VS Code進行編譯調試的一些注意事項。
關于VS Code在Linux下的安裝這裡就不提了,不管是CentOS還是Ubuntu,如果不懂且搜Q足夠的情況下,你會解決的。
在Windows下,如果你用Visual Studio進行開發,C/C++的編譯器一般采用微軟提供的MSBuild;在Linux下C/C++的編譯器大多采用gcc/g++。既然要在Linux下進行C++開發,很有必要了解一下g++編譯器的一些基本知識。
假設我現在有一個最簡單的C++檔案:
接下來如何編譯呢?簡單來說分成兩步:先編譯,再連結
啟動終端,進入root模式,安裝gcc和g++
Ubuntu:
CentOS:
輸出結果是一個hello.o檔案,這是編譯過程的生成的中間檔案。-c 表示隻編譯,不連結。
輸出結果是一個hello.out檔案,這是最終的可執行檔案。-o 表示輸出檔案,hello.o是上一步生成的.o檔案。
當然,如果第2、3步是可以合并執行,直接執行指令
然而第2、3步分開執行是有意義的,後面會講到。
最後執行以下hello.out驗證一下輸出結果呗
實際開發過程中當然不可能隻有一個cpp這麼簡單,有時候會有非常多的.h和.cpp檔案互相配合,那麼上面直接通過g++編譯可執行檔案就沒那麼簡單了。我們需要借助Make這個強大的項目建構工具,幫助我們建構群組織項目代碼。
假設現在有如下3個檔案:hw2.cpp、solution.h和solution.cpp
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
可以看到這個簡單例子包括頭檔案引用、定義和實作分離等情況,如果直接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如何編譯和連結程式。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
先來解釋一下makefile的基本文法規則:
target是一個目标檔案,可以是Object File,也可以是執行檔案,還可以是一個标簽;
prerequisites是要生成那個target所需要的檔案或是目标;
command是make需要執行的指令(任意的Shell指令)。
說白了就是target這一個或多個目标,依賴于prerequisites清單中的檔案,其執行規則定義在command裡。如果prerequisites清單中檔案比target要新,就會執行command,否則就跳過。這就是整個make過程的基本原理。
那麼,我們回頭看看上面定義的makefile檔案,我們解釋一下每兩行的作用
target是build,依賴于hw2.o 和 solution.o,執行的指令是 g++ -o build hw2.o solution.o
意思是通過g++連結hw2.o和solution.o,生成可執行檔案build,prerequisites有兩個.o檔案,是因為代碼裡hw2引用了solution.h。
target是hw2.o,依賴于hw2.cpp和solution.h,執行指令是g++ -g -c hw2.cpp
意思是通過g++編譯hw2.cpp檔案,生成hw2.o檔案,g++指令中 -g 表示生成的檔案是可調試的,如果沒有-g,調試時無法命中斷點。
同上,編譯solution.cpp檔案,生成solution.o檔案。
這裡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步執行最終目标
看一下執行結果
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
由于makefile檔案中加了-g這一選項,于是可以通過gdb進行調試,并且會命中斷點,這裡感興趣可以再了解一下gdb的使用。
接下來我們要說到如何通過VS Code進行調試。
首先安裝完VS Code之後,還需要安裝一下擴充cpptools,請自行完成。
點選菜單 檢視-> 調試,或直接快捷鍵ctrl + shift + D
點選設定圖示,在彈出的選擇環境中選擇C++(GDB/LLDB),會自動建立一個launch.json檔案
顧名思義,laucn.json的作用是告訴VS Code如何執行啟動任務,也就是我們要把什麼檔案啟動起來,在上述例子中顯然是build這個可執行檔案了。修改一下json檔案中波浪線的program節點,改成${workspaceRoot}/build,其餘的暫時不變
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
接着我們嘗試一下F5,開始調試,結果可以看到報了一個缺少build檔案的錯誤。原因是我們還沒執行make編譯出可執行檔案呢。我們在launch.json檔案中,添加一個preLaunchTask的節點,并設定值為“build”。注意這裡的build不是指可執行檔案build,而是一個名為build的任務!
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
再嘗試F5,會提示一個資訊:
點選配置任務運作程式,并選擇Others, 會自動生成一個tasks.json檔案,這個檔案的作用就是告訴launch或者編譯器需要執行什麼操作。顯然我們這裡要執行make指令,修改tasks.json為如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIml2ZuQWZzUTOhljM0cTO2ATOwATNxMWM1EWYxEjY5ADNlFTNfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.gif)
其中tasks節點是一組任務,注意到其中一個名為build的任務,這就是launch.json檔案中指定的preLaunchTask,表明在啟動可執行程式之前,會先執行一下preLaunchTask即這裡的build任務,重新make一下代碼,更新可執行程式之後再啟動。
當然也可以指運作tasks這些任務而不啟動可執行程式,直接ctrl + shift + B,在VSC的console裡可以看到和終端執行一樣的輸出:
執行完後,項目中會多出.o和build檔案
關于VS Code的launch.json和tasks.json中更多節點的含義,參考
<a href="https://code.visualstudio.com/docs/editor/debugging" target="_blank">https://code.visualstudio.com/docs/editor/debugging</a>
<a href="https://code.visualstudio.com/docs/editor/tasks" target="_blank">https://code.visualstudio.com/docs/editor/tasks</a>
接着設定好斷點之後F5,就可以進入斷點調試了
--------------------------------------------------------------------------------------------------------------------------------------------------
本篇總結了gcc/g++和make/makefile的基礎知識,以及在Linux下使用VS Code進行調試開發的方法,希望對正在挖坑的同學有所幫助,坑避免一個是一個。