本文转载自Using Clang in Visual Studio Code。
在本教程中,您将在macOS上配置Visual Studio Code以使用Clang/LLVM编译器和调试器。
配置VS代码后,您将在VS代码中编译和调试一个简单的C++程序。本教程不会教你Clang或C++语言。对于这些主题,网络上有很多好的资源。
如果您遇到任何问题,请随时在VS Code文档存储库中为本教程提交问题。
准备
要成功完成本教程,您必须执行以下操作:
- 在macOS上安装Visual Studio Code。
- 安装VS Code的C++扩展。您可以通过在扩展视图(⇧⌘X)中搜索“c++”来安装C/C++扩展。
确保安装了Clang
Clang可能已经安装在您的Mac上。要验证它是,请打开macOS终端窗口并输入以下命令:
clang --version
- 如果未安装Clang,请输入以下命令来安装命令行开发人员工具:
xcode-select --install
创建Hello World
从macOS终端,创建一个名为projects
的空文件夹,您可以在其中存储所有VS Code项目,然后创建一个名为helloworld
的子文件夹,导航进入它,并通过输入以下命令在该文件夹中打开VS Code:
mkdir projects
cd projects
mkdir helloworld
cd helloworld
code .
code .
命令在当前工作文件夹中打开VS代码,该文件夹将成为您的“工作区”。在浏览教程时,您将在工作区的.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保存文件。请注意,您的文件列在VS代码边栏的文件资源管理器视图(⇧⌘E)中:
您还可以通过在主文件菜单中选中自动保存来启用自动保存文件更改。
Visual Studio Code边缘的活动栏允许您打开不同的视图,如搜索、源代码管理和和运行和调试。您将在本教程的后面查看运行视图。您可以在VSCode用户界面文档中了解有关其他视图的更多信息。
注意:当您保存或打开C++文件时,您可能会看到来自C/C++扩展的关于Insiders版本可用性的通知,该通知允许您测试新功能和修复程序。您可以通过选择
X
(清除通知)来忽略此通知。
智能感知IntelliSense
在helloworld.cpp
文件中,将鼠标悬停在vector
或string
上以查看类型信息。声明msg
变量后,开始键入msg.
就像调用成员函数时一样。您应该会立即看到一个显示所有成员函数的完成列表,以及一个显示msg
对象类型信息的窗口:
您可以按Tab键插入所选成员。然后,当您添加开头括号时,您将看到有关函数所需的参数的信息。
运行helloworld.cpp
请记住,C++扩展使用您在机器上安装的C++编译器来构建您的程序。在尝试在VS Code中运行和debughelloworldhelloworld.cpp
之前,请确保您安装了C++编译器。
- 打开
helloworld.cpp
,使其成为活动文件。 - 按下编辑器右上角的播放按钮。
- 选择C/C++:clang++从系统上检测到的编译器列表中构建和调试活动文件。
只有第一次运行
helloworld.cpp
时,才会要求您选择一个编译器。该编译器将被设置为tasks.json
文件中的“默认”编译器。 - 构建成功后,您的程序输出将出现在集成终端中。
第一次运行程序时,C++扩展会创建tasks.json
,您可以在项目的.vscode
文件夹中找到。tasks.json
存储构建配置。
您的新tasks.json
文件应该类似于下面的JSON:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "C/C++: clang++ build active file",
"command": "/usr/bin/clang++",
"args": [
"-std=c++17",
"-stdlib=libc++",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger."
}
]
}
注意:您可以在变量参考中了解有关
tasks.json
变量的更多信息。
command
设置指定要运行的程序。在这种情况下"clang++"
是导致Clang编译器期望C++代码和链接到C++标准库的驱动程序。
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
您可以使用"${workspaceFolder}/*.cpp"
而不是${file}
等参数来修改您的tasks.json
以构建多个C++文件。这将构建您当前文件夹中的所有.cpp
文件。您还可以通过将"${fileDirname}/${fileBasenameNoExtension}"
为硬编码的文件名(例如"${workspaceFolder}/myProgram.out"
修改输出文件名。
调试helloworld.cpp
要调试您的代码,
- 返回
helloworld.cpp
,使其成为活动文件。 - 通过单击编辑器边距或在当前行上使用F9来设置断点。
- 从播放按钮旁边的下拉菜单中,选择调试C/C++文件。
- 从系统上检测到的编译器列表中选择clang++构建和调试活动文件(您只会被要求在第一次运行或调试
helloworld.cpp
选择编译器)。
播放按钮有两种模式:运行C/C++文件和调试C/C++文件。它将默认为最后使用的模式。如果您在播放按钮中看到调试图标,只需选择要调试的播放按钮,而不是选择下拉菜单项。
调试
在您开始浏览代码之前,让我们花点时间注意用户界面的几个变化:
- 集成终端出现在源代码编辑器的底部。在调试输出选项卡中,您会看到指示调试器正在启动并运行的输出。
- 编辑强调了
main
方法中的第一个语句。这是C++扩展自动为您设置的断点: - 左侧的运行和调试视图显示调试信息。您将在教程后面看到一个示例。
- 在代码编辑器的顶部,会出现一个调试控制面板。您可以通过抓住左侧的圆点在屏幕上移动它。
逐步浏览代码
现在你已经准备好开始浏览代码了。
- 单击或按下调试控制面板中的Step over图标,以便突出显示
for (const string& word : msg)
语句。
Step Over命令跳过创建和初始化msg
变量时调用的vector
和string
类中的所有内部函数调用。注意变量窗口的变化。msg
的内容是可见的,因为该声明已经完成。 - 再次按Step over以进入下一个语句(跳过为初始化循环而执行的所有内部代码)。现在,变量窗口显示有关循环变量的信息。
- 再次按Step over执行
cout
语句。注意:截至2019年3月版本的扩展,在最后一次cout
完成之前,调试控制台中不会显示任何输出。
设置一个监视
您可能希望在程序执行时跟踪变量的值。您可以通过在变量上设置监视来做到这一点。
- 将插入点放在循环内。在监视窗口中,单击加号,然后在文本框中键入
word
,这是循环变量的名称。现在,当你穿过循环时,查看监视窗口。 - 要在执行暂停时快速查看任何变量的值,您可以使用鼠标指针将其悬停在它上面。
使用launch.json自定义调试
当您使用播放按钮或F5进行调试时,C++扩展会实时创建动态调试配置。
在某些情况下,您希望自定义调试配置,例如指定在运行时传递给程序的参数。您可以在launch.json
文件中定义自定义调试配置。
要创建launch.json
,请从播放按钮下拉菜单中选择添加调试配置。
然后,您将看到各种预定义调试配置的下拉菜单。选择 clang++构建和调试活动文件。
VS Code创建一个launch.json
文件,看起来像这样:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "C/C++: clang++ build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb",
"preLaunchTask": "C/C++: clang++ build active file"
}
]
}
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)等设置。
通过运行命令**C/C++:**从命令调色板(⇧⌘P)编辑配置(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": "clang-x64"
}
],
"version": 4
}
只有当您的程序包含不在工作区或标准库路径中的头文件时,您才需要修改包括路径设置。
编译路径
compilerPath
是一个重要的配置设置。该扩展使用它来推断C++标准库头文件的路径。当扩展知道在哪里可以找到这些文件时,它可以提供智能完成和转到定义导航等有用功能。
C/C++扩展试图根据它在系统上找到的内容为compilerPath
填充默认编译器位置。compilerPath
搜索顺序是:
- 您的已知编译器名称的路径。编译器出现在列表中的顺序取决于您的路径。
- 然后搜索硬编码的Xcode路径,例如
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/
Mac框架路径
在C/C++配置屏幕上,向下滚动并展开高级设置,并确保Mac框架路径指向系统头文件。例如:/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks
重复使用您的C++配置
VS Code现在配置为在macOS上使用Clang。该配置适用于当前工作区。要重用配置,只需将JSON文件复制到新项目文件夹(工作区)中的.vscode
文件夹中,并根据需要更改源文件和可执行文件的名称。
故障排除
编译器和链接错误
当您开始构建或开始调试时,helloworld.cpp
不是活动文件时,最常见的错误原因(如undefined _main
,或attempting to link with file built for unknown-unsupported file format
等)会出现。这是因为编译器正试图编译不是源代码的东西,例如您的launch.json
、tasks.json
或c_cpp_properties.json
文件。
如果您看到提及“C++11扩展”的构建错误,您可能没有更新tasks.json
构建任务以使用clang++参数--std=c++17
。默认情况下,clang++使用C++98标准,该标准不支持helloworld.cpp
中使用的初始化。请确保用Run helloworld.cpp部分中提供的代码块替换tasks.json
文件的全部内容。
终端不会启动输入
On macOS Catalina and onwards, you might have a issue where you are unable to enter input, even after setting "externalConsole": true
. A terminal window opens, but it does not actually allow you type any input.
这个问题目前正在跟踪#5079。
解决方法是让VS Code启动终端一次。您可以通过在tasks.json
中添加和运行此任务来做到这一点:
{
"label": "Open Terminal",
"type": "shell",
"command": "osascript -e 'tell application \"Terminal\"\ndo script \"echo hello\"\nend tell'",
"problemMatcher": []
}
您可以使用终端>运行任务,运行此特定任务,然后选择打开终端。
一旦您接受权限请求,那么在您调试时应该会出现外部控制台。
参考资料
Configure VS Code for Clang/LLVM on macOS
太酷了