在 Visual Studio Code 中使用 Clang
在本教程中,您將在 macOS 上配置 Visual Studio Code 以使用 Clang/LLVM 編譯器和偵錯程式。
配置 VS Code 後,您將在 VS Code 中編譯和除錯一個 C++ 程式。本教程不教授 Clang 或 C++ 語言。對於這些主題,網上有許多很好的資源。
如果您遇到任何問題,請隨時在 VS Code 文件庫中為本教程提交問題。
先決條件
要成功完成本教程,你必須執行以下步驟
-
安裝 VS Code 的 C++ 擴充套件。您可以在“擴充套件”檢視 (⇧⌘X (Windows, Linux Ctrl+Shift+X)) 中搜索“C++”來安裝 C/C++ 擴充套件。
確保 Clang 已安裝
Clang 可能已經安裝在您的 Mac 上。要驗證它是否已安裝,請開啟一個 macOS 終端視窗並輸入以下命令:
clang --version
如果 Clang 未安裝,請輸入以下命令以安裝命令列開發者工具,其中包含 Clang:
xcode-select --install
建立 Hello World 應用
在 macOS 終端中,建立一個名為 projects
的空資料夾,您可以在其中儲存所有 VS Code 專案,然後建立一個名為 helloworld
的子資料夾,導航到其中,並透過在終端視窗中輸入以下命令在該資料夾中開啟 VS Code:
mkdir projects
cd projects
mkdir helloworld
cd helloworld
code .
code .
命令會在當前工作資料夾中開啟 VS Code,該資料夾將成為您的“工作區”。在學習本教程的過程中,將在您工作區的 .vscode
資料夾中建立三個檔案:
tasks.json
(編譯器構建設定)launch.json
(偵錯程式設定)c_cpp_properties.json
(編譯器路徑和 IntelliSense 設定)
新增一個 hello world 原始碼檔案
在“檔案資源管理器”標題欄中,選擇新建檔案按鈕並將檔案命名為 helloworld.cpp
。
貼上以下原始碼
#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)) 中。
您還可以透過選擇**檔案** > **自動儲存**來啟用自動儲存,以自動儲存您的檔案更改。您可以在 VS Code 使用者介面文件中瞭解有關其他檢視的更多資訊。
注意:當你儲存或開啟 C++ 檔案時,你可能會看到來自 C/C++ 擴充套件的關於 Insiders 版本可用性的通知,該版本可讓你測試新功能和修復。你可以透過選擇
X
(清除通知)來忽略此通知。
探索 IntelliSense
IntelliSense 是一個工具,透過新增程式碼完成、引數資訊、快速資訊和成員列表等程式碼編輯功能,幫助您更快、更高效地編寫程式碼。
要檢視 IntelliSense 的實際效果,請將滑鼠懸停在 vector
或 string
上以檢視其型別資訊。如果您在第 10 行鍵入 msg.
,您可以看到一個推薦呼叫的成員函式的完成列表,這些都是由 IntelliSense 生成的。
您可以按 Tab 鍵插入所選成員。然後,當您新增左括號時,將顯示有關該函式所需引數的資訊。
如果 IntelliSense 尚未配置,請開啟命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 並輸入**選擇 IntelliSense 配置**。從編譯器下拉列表中,選擇 Use clang++
進行配置。更多資訊可以在 IntelliSense 配置文件中找到。
執行 helloworld.cpp
請記住,C++ 擴充套件使用您在計算機上安裝的 C++ 編譯器來構建您的程式。在嘗試在 VS Code 中執行和除錯 helloworld.cpp
之前,請確保您已安裝 C++ 編譯器(如 Clang)。
-
開啟
helloworld.cpp
,使其成為活動檔案。 -
單擊編輯器右上角的播放按鈕。
-
從系統上檢測到的編譯器列表中選擇 **C/C++: clang++ build and debug active file**。
只有在第一次執行 helloworld.cpp
時,系統才會要求您選擇編譯器。此編譯器將是 tasks.json
檔案中設定的“預設”編譯器。
-
構建成功後,您的程式輸出將出現在整合的**除錯控制檯**中。
恭喜!您剛剛在 VS Code 中運行了您的第一個 C++ 程式!
理解 tasks.json
當您第一次執行程式時,C++ 擴充套件會建立 tasks.json
,它位於您專案的 .vscode
資料夾中。tasks.json
儲存構建配置。
以下是 macOS 上 tasks.json
檔案的示例:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: clang++ build active file",
"command": "/usr/bin/clang++",
"args": [
"-fcolor-diagnostics",
"-fansi-escape-codes",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
],
"version": "2.0.0"
}
注意:你可以在變數參考中瞭解有關
tasks.json
變數的更多資訊。
command
設定指定要執行的程式。在本例中,即為 clang++
。
args
陣列指定傳遞給 clang++ 的命令列引數。這些引數必須按編譯器期望的順序列出。
此任務告訴 C++ 編譯器獲取活動檔案 (${file}
),對其進行編譯,並在當前目錄 (${fileDirname}
) 中建立一個與活動檔案同名但沒有副檔名 (${fileBasenameNoExtension}
) 的輸出檔案 (-o
開關)。此過程會建立 helloworld
。
label
的值是您在任務列表中看到的內容,它基於您的個人偏好。
detail
的值是任務列表中該任務的描述。請更新此字串以將其與類似任務區分開。
problemMatcher
的值選擇用於在編譯器輸出中查詢錯誤和警告的輸出解析器。對於 clang++,$gcc
問題匹配器能產生最佳結果。
從現在起,播放按鈕將始終從 tasks.json
中讀取資訊,以確定如何構建和執行您的程式。您可以在 tasks.json
中定義多個構建任務,而標記為預設的任務將是播放按鈕使用的任務。如果您需要更改預設編譯器,可以在命令面板中執行**任務:配置預設生成任務**。或者,您可以修改 tasks.json
檔案,並透過替換以下段落來移除預設設定:
"group": {
"kind": "build",
"isDefault": true
},
替換為
"group": "build",
修改 tasks.json
您可以修改您的 tasks.json
以構建多個 C++ 檔案,方法是使用類似 "${workspaceFolder}/*.cpp"
的引數來代替 "${file}"
。這將構建您當前資料夾中的所有 .cpp
檔案。您還可以透過將 "${fileDirname}/${fileBasenameNoExtension}"
替換為硬編碼的檔名(例如 "${workspaceFolder}/myProgram.out"
)來修改輸出檔名。
除錯 helloworld.cpp
要除錯你的程式碼,
-
回到
helloworld.cpp
,使其成為活動檔案。 -
透過單擊編輯器邊欄或在當前行上按 F9 來設定斷點。
-
從播放按鈕旁邊的下拉選單中,選擇**除錯 C/C++ 檔案**。
-
從系統上檢測到的編譯器列表中選擇 **C/C++: clang++ build and debug active file**(只有在第一次執行或除錯
helloworld.cpp
時,您才會被要求選擇編譯器)。 -
您將看到任務執行,並將輸出列印到**終端**視窗。
播放按鈕有兩種模式:**執行 C/C++ 檔案**和**除錯 C/C++ 檔案**。預設是上次使用的模式。如果您在播放按鈕中看到除錯圖示,您可以選擇播放按鈕進行除錯,而無需選擇下拉選單項。
探索偵錯程式
在開始單步除錯程式碼之前,我們花點時間注意使用者介面中的幾處變化
-
整合終端出現在原始碼編輯器的底部。在**除錯控制檯**選項卡中,您會看到指示偵錯程式已啟動並正在執行的輸出。
-
編輯器會高亮顯示你在啟動偵錯程式之前設定斷點的行
-
活動欄中的**執行和除錯**檢視顯示除錯資訊。
-
程式碼編輯器頂部會出現一個除錯控制面板。你可以透過抓取左側的點來在螢幕上移動它。
單步除錯程式碼
現在你已準備好開始單步除錯程式碼。
-
在除錯控制面板中選擇**單步跳過**圖示,使
for (const string& word : msg)
語句高亮顯示。**單步跳過**命令會跳過在建立和初始化
msg
變數時呼叫的vector
和string
類中的所有內部函式呼叫。請注意**變數**視窗中的變化。msg
的內容是可見的,因為該語句已經完成。 -
再次按**單步跳過**以進入下一條語句(跳過為初始化迴圈而執行的所有內部程式碼)。現在,**變數**視窗顯示有關迴圈變數的資訊。
-
再次按**單步跳過**以執行
cout
語句。 -
如果你願意,可以繼續按單步跳過,直到向量中的所有單詞都列印到控制檯。但如果你好奇,可以嘗試按單步進入按鈕來單步執行 C++ 標準庫中的原始碼!
設定監視
您可能希望在程式執行時跟蹤變數的值。您可以透過對變數設定**監視**來實現這一點。
-
在**監視**視窗中,選擇加號並在文字框中鍵入
word
。這是迴圈變數的名稱。現在,在單步執行迴圈時檢視**監視**視窗。注意:監視變數的值僅在程式執行位於該變數的作用域內時才可用。例如,對於迴圈變數,其值僅在程式執行迴圈時才可用。
-
透過在迴圈前新增此語句來新增另一個監視:
int i = 0;
。然後,在迴圈內部新增此語句:++i;
。現在,像上一步一樣為i
新增監視。 -
當執行暫停時,您可以用滑鼠指標懸停在任何變數上以快速檢視其值。
使用 launch.json 自定義除錯
當你使用播放按鈕或 F5 進行除錯時,C++ 擴充套件會即時建立一個動態除錯配置。
在某些情況下,你可能希望自定義除錯配置,例如指定在執行時傳遞給程式的引數。你可以在 launch.json
檔案中定義自定義除錯配置。
要建立 launch.json
,請從播放按鈕下拉選單中選擇新增除錯配置。
然後您會看到一個包含各種預定義除錯配置的下拉列表。選擇 **C/C++: clang++ build and debug active file**。
VS Code 建立一個 launch.json
檔案,它看起來像這樣
{
"configurations": [
{
"name": "C/C++: clang++ build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "C/C++: clang++ build active file"
}
],
"version": "2.0.0"
}
program
設定指定您要除錯的程式。這裡它被設定為活動檔案所在的資料夾 ${fileDirname}
和活動檔名 ${fileBasenameNoExtension}
,如果 helloworld.cpp
是活動檔案,這將是 helloworld
。args
屬性是在執行時傳遞給程式的引數陣列。
預設情況下,C++ 擴充套件不會在您的原始碼中新增任何斷點,並且 stopAtEntry
的值被設定為 false
。
將 stopAtEntry
值更改為 true
,以便在開始除錯時讓偵錯程式在 main
方法處停止。
請確保 preLaunchTask
的值與 tasks.json
檔案中構建任務的 label
相匹配。
從現在開始,播放按鈕和 F5 在啟動程式進行除錯時將從你的
launch.json
檔案中讀取資訊。
新增額外的 C/C++ 設定
要對 C/C++ 擴充套件進行更多控制,請建立一個 c_cpp_properties.json
檔案,該檔案允許您更改諸如編譯器路徑、包含路徑、編譯時使用的 C++ 標準(如 C++17)等設定。
透過從命令面板 (⇧⌘P (Windows, Linux Ctrl+Shift+P)) 執行命令 **C/C++: 編輯配置 (UI)** 來檢視 C/C++ 配置 UI。
這將開啟 **C/C++ 配置**頁面。
Visual Studio Code 將這些設定放在 .vscode/c_cpp_properties.json
中。如果你直接開啟該檔案,它應該看起來像這樣
{
"configurations": [
{
"name": "Mac",
"includePath": ["${workspaceFolder}/**"],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "macos-clang-arm64"
}
],
"version": 4
}
只有當您的程式包含不在您的工作區或標準庫路徑中的標頭檔案時,您才需要修改**包含路徑**設定。
編譯器路徑
擴充套件使用 compilerPath
設定來推斷 C++ 標準庫標頭檔案的路徑。當擴充套件知道在哪裡可以找到這些檔案時,它就可以提供諸如智慧補全和**轉到定義**導航等功能。
C/C++ 擴充套件會根據在您系統上找到的內容,嘗試使用預設編譯器位置來填充 compilerPath
。compilerPath
的搜尋順序是:
- 您的 PATH 中已知編譯器的名稱。編譯器在列表中出現的順序取決於您的 PATH。
- 然後搜尋硬編碼的 Xcode 路徑,例如
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/
更多資訊,請參閱 IntelliSense 配置文件。
Mac 框架路徑
在 C/C++ 配置螢幕上,向下滾動並展開**高階設定**,並確保 **Mac 框架路徑**指向系統標頭檔案。例如:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks
故障排除
編譯器和連結錯誤
最常見的錯誤原因(例如 undefined _main
,或 attempting to link with file built for unknown-unsupported file format
等)是當您開始構建或除錯時,helloworld.cpp
不是活動檔案。這是因為編譯器試圖編譯一些不是原始碼的東西,比如您的 launch.json
、tasks.json
或 c_cpp_properties.json
檔案。
如果您看到提及“C++11 extensions”的構建錯誤,您可能沒有更新您的 tasks.json
構建任務以使用 clang++ 引數 --std=c++17
。預設情況下,clang++ 使用 C++98 標準,該標準不支援 helloworld.cpp
中使用的初始化。請確保將您的 tasks.json
檔案的全部內容替換為執行 helloworld.cpp 部分中提供的程式碼塊。
終端無法啟動以進行輸入
在 macOS Catalina 及更高版本上,您可能會遇到即使設定了 "externalConsole": true
也無法輸入的問題。一個終端視窗會開啟,但它實際上不允許您鍵入任何輸入。
該問題目前正在 #5079 中進行跟蹤。
解決方法是讓 VS Code 啟動一次終端。您可以透過在您的 tasks.json
中新增並執行此任務來做到這一點:
{
"label": "Open Terminal",
"type": "shell",
"command": "osascript -e 'tell application \"Terminal\"\ndo script \"echo hello\"\nend tell'",
"problemMatcher": []
}
您可以使用**終端** > **執行任務...** 並選擇**開啟終端**來執行此特定任務。
一旦您接受許可權請求,那麼當您除錯時,外部控制檯就應該會出現。
後續步驟
- 探索 VS Code 使用者指南。
- 回顧 C++ 擴充套件概述
- 建立一個新的工作區,將你的 .json 檔案複製到其中,調整新工作區路徑、程式名稱等必要的設定,然後開始編碼!