在 VS Code 中使用 C++ 與 WSL

在本教學中,您將設定 Visual Studio Code,以便在 Windows Linux 子系統 (WSL) 上的 Ubuntu 中使用 GCC C++ 編譯器 (g++) 與 GDB 偵錯工具。GCC 代表 GNU Compiler Collection;GDB 是 GNU 偵錯工具。WSL 是執行於 Windows 內的 Linux 環境,它直接在機器硬體上運行,而非在虛擬機器中執行。

注意:本教學的大部分內容也適用於直接在 Linux 機器上使用 C++ 與 VS Code。

Visual Studio Code 透過 WSL 擴充功能,支援直接在 WSL 中進行開發。我們建議採用這種 WSL 開發模式,其中所有的原始程式碼檔案與編譯器都託管於 Linux 發行版中。若需更多背景資訊,請參閱 VS Code 遠端開發

完成本教學後,您將能建立並設定自己的 C++ 專案,並探索 VS Code 文件以深入了解其豐富的功能。本教學並不教授 GCC、Linux 或 C++ 語言本身。關於這些主題,網路上有許多優質的學習資源。

如果您遇到任何問題,歡迎在 VS Code 文件儲存庫中為本教學提出 Issue。

先決條件

若要成功完成本教學課程,您必須執行下列步驟

  1. 安裝 Visual Studio Code

  2. 安裝 WSL 擴充功能

  3. 安裝 Windows Linux 子系統 (WSL),然後使用該頁面上的連結來安裝您選擇的 Linux 發行版。本教學使用 Ubuntu。在安裝過程中,請記住您的 Linux 使用者密碼,因為安裝其他軟體時會用到它。

設定您的 Linux 環境

  1. 開啟 WSL 的 Bash shell。如果您安裝的是 Ubuntu 發行版,請在 Windows 搜尋方塊中輸入「Ubuntu」,然後在結果清單中點選它。若是 Debian,則輸入「Debian」,依此類推。

    Ubuntu in Start Menu

    Shell 會顯示命令提示字元,預設包含您的使用者名稱與電腦名稱,並將您置於家目錄中。對於 Ubuntu,看起來如下所示

    Bash Shell

  2. 建立一個名為 projects 的目錄,並在該目錄下建立一個名為 helloworld 的子目錄

    mkdir projects
    cd projects
    mkdir helloworld
    
  3. 雖然您將使用 VS Code 來編輯原始程式碼,但您將在 Linux 上使用 g++ 編譯器來進行編譯。您也將在 Linux 上使用 GDB 進行偵錯。這些工具在 Ubuntu 中並非預設安裝,因此您必須自行安裝。幸運的是,這項任務相當簡單!

  4. 從 WSL 命令提示字元中,首先執行 apt-get update 以更新 Ubuntu 套件清單。過舊的發行版有時會干擾安裝新套件的操作。

    sudo apt-get update
    

    如果您願意,可以執行 sudo apt-get update && sudo apt-get dist-upgrade 來下載系統套件的最新版本,但根據您的網路速度,這可能需要更長的時間。

  5. 從命令提示字元中,透過輸入以下內容來安裝 GNU 編譯器工具與 GDB 偵錯工具

    sudo apt-get install build-essential gdb
    
  6. 透過定位 g++ 與 gdb 來驗證安裝是否成功。如果 whereis 命令沒有傳回檔案名稱,請嘗試再次執行更新命令。

    whereis g++
    whereis gdb
    

注意:如果您是直接在 Linux 機器上工作而非在 WSL 中,上述安裝 g++ 編譯器與 GDB 偵錯工具的設定步驟同樣適用。在 helloworld 專案中執行 VS Code,以及編輯、建置與偵錯的步驟都是一樣的。

在 WSL 中執行 VS Code

導覽至您的 helloworld 專案資料夾,並從 WSL 終端機使用 code . 啟動 VS Code

cd $HOME/projects/helloworld
code .

您會看到關於「安裝 VS Code Server」的訊息。VS Code 正在 Linux 端下載並安裝一個小型伺服器,桌面版的 VS Code 隨後將與其通訊。接著 VS Code 將啟動並開啟 helloWorld 資料夾。檔案總管會顯示 VS Code 現已在 WSL 環境中執行,標題列顯示為 WSL: Ubuntu

File Explorer in WSL

您也可以從狀態列辨識遠端環境。

Remote context in the Status bar

如果您點選狀態列上的「遠端」項目,將會看到適合該工作階段的遠端命令下拉式選單。例如,如果您想結束在 WSL 中執行的工作階段,可以從下拉式選單選擇 關閉遠端連線 (Close Remote Connection) 命令。從 WSL 命令提示字元執行 code . 將會重新啟動在 WSL 中執行的 VS Code。

code . 命令在當前工作資料夾中開啟了 VS Code,該資料夾即成為您的「工作區」。隨著您進行本教學,您將會看到工作區中 .vscode 資料夾下產生了三個檔案

  • c_cpp_properties.json(編譯器路徑與 IntelliSense 設定)
  • tasks.json(建置指示)
  • launch.json(偵錯工具設定)

新增原始程式碼檔案

在檔案總管標題列中,選取新增檔案按鈕,並將檔案命名為 helloworld.cpp

New File title bar button

安裝 C/C++ 擴充功能

一旦您建立檔案且 VS Code 偵測到它是 C++ 語言檔案,如果尚未安裝,您可能會收到安裝 Microsoft C/C++ 擴充功能的提示。

C++ extension notification

選擇 安裝 (Install),並在擴充功能檢視中出現按鈕時選擇 需要重新載入 (Reload Required),以完成 C/C++ 擴充功能的安裝。

如果您已在本機 VS Code 安裝了 C/C++ 語言擴充功能,您需要前往擴充功能檢視 (⇧⌘X (Windows, Linux Ctrl+Shift+X)) 並將這些擴充功能安裝到 WSL 中。選擇 在 WSL 中安裝 (Install in WSL) 按鈕,然後選擇 需要重新載入 (Reload Required),即可將本機安裝的擴充功能安裝到 WSL 中。

Install in WSL button

新增 hello world 原始程式碼

現在請貼上這段原始程式碼

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
   vector<string> msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"};

   for (const string& word : msg)
   {
      cout << word << " ";
   }
   cout << endl;
}

現在按下 ⌘S (Windows, Linux Ctrl+S) 來儲存檔案。請注意,您剛新增的檔案會出現在 VS Code 側邊欄的「檔案總管」檢視(⇧⌘E (Windows, Linux Ctrl+Shift+E))中。

File Explorer

您也可以勾選「檔案」主選單中的「自動儲存」,啟用自動儲存功能來自動儲存檔案變更。

最左側的活動列讓您可以開啟不同的檢視,例如 搜尋 (Search)原始檔控制 (Source Control)執行 (Run)。您稍後將會在本教學中查看 執行 檢視。您可以在 VS Code 使用者介面文件中找到關於其他檢視的更多資訊。

探索 IntelliSense

在您新的 helloworld.cpp 檔案中,將滑鼠游標懸停在 vectorstring 上以查看類型資訊。在宣告 msg 變數後,開始輸入 msg.,就像呼叫成員函式時那樣。您應該會立即看到一個自動完成清單,顯示所有成員函式,以及一個顯示 msg 物件類型資訊的視窗。

Statement completion IntelliSense

您可以按下 Tab 鍵來插入所選的成員;接著,當您加入左括號時,您將會看到該函式所需參數的相關資訊。

執行 helloworld.cpp

請記住,C++ 延伸模組會使用您電腦上安裝的 C++ 編譯器來建置您的程式。在嘗試於 VS Code 中執行及偵錯 helloworld.cpp 之前,請務必先安裝 C++ 編譯器。

  1. 開啟 helloworld.cpp 使其成為作用中檔案。

  2. 按下編輯器右上角的執行按鈕。

    Screenshot of helloworld.cpp and play button

  3. 從系統偵測到的編譯器清單中,選擇 g++ 建置並偵錯使用中檔案 (g++ build and debug active file)

    C++ debug configuration dropdown

您只需要在第一次執行 helloworld.cpp 時選擇編譯器。此編譯器將設定為 tasks.json 檔案中的「預設」編譯器。

  1. 建置成功後,您的程式輸出將會出現在整合式的「終端機」中。

    screenshot of program output

您第一次執行程式時,C++ 延伸模組會建立 tasks.json,您可以在專案的 .vscode 資料夾中找到它。tasks.json 用於儲存建置設定。

您新的 tasks.json 檔案應該類似於下方的 JSON:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "shell",
      "label": "C/C++: g++ build active file",
      "command": "/usr/bin/g++",
      "args": ["-g", "${file}", "-o", "${fileDirname}/${fileBasenameNoExtension}"],
      "options": {
        "cwd": "/usr/bin"
      },
      "problemMatcher": ["$gcc"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "detail": "Task generated by Debugger."
    }
  ]
}

注意:您可以在 變數參考中進一步了解 tasks.json 變數。

command 設定指定要執行的程式;在此情況下為 g++。args 陣列指定將傳遞給 g++ 的命令列引數。這些引數必須依照編譯器預期的順序指定。

此任務告知 g++ 取得使用中檔案 (${file})、進行編譯,並在當前目錄 (${fileDirname}) 下建立一個與使用中檔案名稱相同但無副檔名 (${fileBasenameNoExtension}) 的可執行檔,以我們的範例而言,結果會產生 helloworld

label 值是您在工作清單中看到的名稱;您可以隨意命名。

detail 值是您在任務清單中看到的任務描述。強烈建議重新命名此值,以便與類似任務進行區分。

從現在起,播放按鈕將讀取 tasks.json 來判斷如何建置並執行您的程式。您可以在 tasks.json 中定義多個建置工作,而標記為預設的工作將由播放按鈕使用。如果您需要變更預設編譯器,可以執行「工作:設定預設建置工作」。或者,您也可以修改 tasks.json 檔案,透過取代該區段來移除預設值。

    "group": {
        "kind": "build",
        "isDefault": true
    },

取代為

    "group": "build",

修改 tasks.json

您可以透過使用類似 "${workspaceFolder}/*.cpp" 而非 "${file}" 的引數,修改您的 tasks.json 來建置多個 C++ 檔案。這將會建置當前資料夾中的所有 .cpp 檔案。您也可以透過將 "${fileDirname}/${fileBasenameNoExtension}" 取代為硬編碼的檔名(例如 'helloworld.out')來修改輸出檔名。

偵錯 helloworld.cpp

若要偵錯您的程式碼:

  1. 回到 helloworld.cpp 使其成為作用中檔案。
  2. 透過點擊編輯器邊界或在目前行上使用 F9 來設定中斷點。 helloworld.cpp 中斷點截圖
  3. 從播放按鈕旁的下拉式選單中,選取 Debug C/C++ File播放按鈕下拉式選單截圖
  4. 從系統偵測到的編譯器清單中,選擇 C/C++: g++ build and debug active file(您只需在第一次執行或偵錯 helloworld.cpp 時選擇編譯器)。 C++ 偵錯設定下拉式選單

播放按鈕有兩種模式:執行 C/C++ 檔案 (Run C/C++ File)偵錯 C/C++ 檔案 (Debug C/C++ File)。它將預設為上次使用的模式。如果您在播放按鈕中看到偵錯圖示,您可以選擇播放按鈕來進行偵錯,而無需選擇下拉式選單項目。

探索偵錯器

在開始逐步執行程式碼之前,讓我們花點時間留意使用者介面的幾項變更

  • 整合式終端機會出現在原始碼編輯器的底部。在「偵錯輸出」索引標籤中,您會看到指出偵錯工具正在執行中的輸出。

  • 編輯器會反白顯示第 12 行,這是您在啟動偵錯工具之前設定的中斷點。

    Initial breakpoint

  • 左側的「執行與偵錯」檢視會顯示偵錯資訊。您稍後會在教學課程中看到範例。

  • 在程式碼編輯器的頂部,會出現一個偵錯控制面板。您可以透過抓取左側的點將其移至畫面其他位置。

    Debugging controls

如果您的工作區中已有 launch.json 檔案,播放按鈕在判斷如何執行與偵錯 C++ 檔案時會讀取該檔案。如果您沒有 launch.json,播放按鈕將會即時建立一個暫時的「快速偵錯」設定,完全省去了 launch.json 的需求!

逐步執行程式碼

現在您已準備好開始逐步執行程式碼。

  1. 點擊或按下偵錯控制面板中的「跳過 (Step over)」圖示。

    Step over button

    這將會推進程式執行到 for 迴圈的第一行,並跳過 msg 變數建立與初始化時所呼叫的 vectorstring 類別內部的所有函式呼叫。請注意側邊 變數 (Variables) 視窗中的變化。

    Debugging windows

  2. 再次按下「跳過」以推進到程式中的下一個陳述式(跳過初始化迴圈所執行的所有內部程式碼)。現在,「變數」視窗會顯示迴圈變數的相關資訊。

  3. 再次按下 不進入函式 (Step over) 來執行 cout 陳述式。(請注意,C/C++ 擴充功能在最後的 cout 執行之前,不會將任何輸出列印到 偵錯主控台 (Debug Console)。)

  4. 如果您願意,可以持續按下逐步跳過,直到向量中的所有單字都列印到主控台為止。但如果您感到好奇,請嘗試按下逐步執行 (Step Into) 按鈕,以逐步追蹤 C++ 標準函式庫中的原始程式碼!

    Breakpoint in gcc standard library header

    若要回到您自己的程式碼,一種方法是持續按下「跳過」。另一種方法是在您的程式碼中設定中斷點:切換至程式碼編輯器中的 helloworld.cpp 索引標籤,將插入點放在迴圈內 cout 陳述式的某處,然後按下 F9。左側裝訂邊會出現一個紅點,表示已在此行設定中斷點。

    Breakpoint in main

    然後按下 F5 從標準程式庫標頭中的目前行開始執行。程式執行將會在 cout 處中斷。如果您願意,可以再次按下 F9 來取消中斷點。

    當迴圈完成時,您可以在整合終端機的 偵錯主控台 (Debug Console) 索引標籤中看到輸出結果,以及由 GDB 輸出的一些其他診斷資訊。

    Debug console display

設定監看式 (Watch)

若要在程式執行時追蹤變數的值,請為該變數設定 監看 (Watch)

  1. 將插入點放置在迴圈內。在 監看 (Watch) 視窗中,點選加號並在文字方塊中輸入 word,這是迴圈變數的名稱。現在,當您逐步執行迴圈時,請查看監看視窗。

    Watch window

  2. 若要在執行於中斷點暫停時快速查看任何變數的值,您可以將滑鼠指標懸停在該變數上。

    Mouse hover

接下來,您將建立一個 tasks.json 檔案,以告知 VS Code 如何建置 (編譯) 程式。此任務將呼叫 g++ 編譯器,從原始程式碼建立可執行檔。

請務必在編輯器中開啟 helloworld.cpp,因為下一個步驟會使用編輯器中的使用中檔案作為背景資訊來建立建置任務。

使用 launch.json 自訂偵錯

當您使用執行按鈕或 F5 進行偵錯時,C++ 擴充功能會即時建立動態偵錯設定。

在某些情況下,您會希望自訂偵錯設定,例如指定在執行階段傳遞給程式的參數。您可以在 launch.json 檔案中定義自訂偵錯設定。

若要建立 launch.json,請從執行按鈕下拉式選單中選擇 新增偵錯設定

Add debug configuration play button menu

接著您會看到各種預先定義偵錯設定的下拉式選單。選擇 g++ build and debug active file

C++ debug configuration dropdown

VS Code 會建立一個 launch.json 檔案,看起來會像這樣

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "C/C++: g++ build and debug active file",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}/${fileBasenameNoExtension}",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "/usr/bin/gdb",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "C/C++: g++ build active file"
    }
  ]
}

在上述 JSON 中,program 指定了您要偵錯的程式。此處將其設定為使用中檔案資料夾 ${fileDirname} 與無副檔名的使用中檔名 ${fileBasenameNoExtension}。如果 helloworld.cpp 是使用中檔案,則這將會是 helloworldargs 屬性是一個在執行階段傳遞給程式的引數陣列。

預設情況下,C++ 延伸模組不會在您的原始程式碼中新增任何中斷點,且 stopAtEntry 值設定為 false

stopAtEntry 值變更為 true,以讓偵錯工具在您開始偵錯時於 main 方法停下。

從現在起,當您啟動程式進行偵錯時,執行按鈕與 F5 都會讀取您的 launch.json 檔案。

C/C++ 設定

如果您想要更精確地控制 C/C++ 延伸模組,可以建立一個 c_cpp_properties.json 檔案,這將允許您變更設定,例如編譯器路徑、包含路徑、C++ 標準(預設為 C++17)等。

您可以透過從命令選擇區(⇧⌘P (Windows, Linux Ctrl+Shift+P))執行 C/C++: Edit Configurations (UI) 命令來查看 C/C++ 設定 UI。

Command Palette

這會開啟 C/C++ 設定頁面。當您在此處進行變更時,VS Code 會將其寫入 .vscode 資料夾中名為 c_cpp_properties.json 的檔案。

Command Palette

您僅需要在您的程式包含不在工作區或標準程式庫路徑中的標頭檔時,才需要修改 Include path 設定。

Visual Studio Code 會將這些設定放置在 .vscode/c_cpp_properties.json。如果您直接開啟該檔案,它應該會長得像這樣

{
  "configurations": [
    {
      "name": "Linux",
      "includePath": ["${workspaceFolder}/**"],
      "defines": [],
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "c11",
      "cppStandard": "c++17",
      "intelliSenseMode": "clang-x64"
    }
  ],
  "version": 4
}

關閉 WSL 工作階段

當您在 WSL 中的工作完成後,可以使用主要 檔案 (File) 功能表與命令選擇區 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 中提供的 關閉遠端連線 (Close Remote Connection) 命令來關閉遠端工作階段。這將會重新啟動在本機執行的 VS Code。您可以透過從 檔案 (File) > 開啟最近的檔案 (Open Recent) 清單中選擇帶有 [WSL] 字尾的資料夾,輕鬆重新開啟您的 WSL 工作階段。

後續步驟

  • 探索 VS Code 使用者指南
  • 查閱 C++ 擴充功能總覽
  • 建立新的工作區,將您的 .json 檔案複製到其中,為新的工作區路徑、程式名稱等調整必要的設定,然後開始編寫程式碼吧!
© . This site is unofficial and not affiliated with Microsoft.