最近在尝试使用VSCode搭建C++开发环境,而目前听说过2种方式:
(1)一种就是网上常说的要分别对launch.json,c_cpp_properties.json,tasks.json这3个文件
(2)直接使用cmake的方式
但是无论是哪种方式,对于复杂的C++工程,尤其是涉及到要包含各种复杂的头文件时,经常会遇到“找不到头文件”而显示波浪号的问题。博主经过反复尝试,目前分别对使用cmake和不使用cmake两种构建工程的方式进行了尝试,终于成功,在此对其中的细节和关键点进行记录,方便自己后续可以复现。
目录
1.仅使用VSCode自带的各种json文件来进行配置
目标工程结构如下:
VSCodeWorkplace2
|——.vscode
|——MyClass
|——include
Parent.h
Child.h
Blob.h
Parent.cpp
Child.cpp
|——main.cpp
文件包含关系如下:
Parent.cpp包含Parent.h,Child.cpp包含Child.h,Blob.h直接实现一个完整的class
main.cpp包含Parent.h,Child.h,Blob.h
接下来从最简单的main.cpp逐步增加上述文件完成工程的构建
- 首先创建一个基本的只包含main.cpp的工程
(1)新建工程:“打开文件夹”:
新建并选择这个文件夹:
然后就可以看到下面的了:一开始什么都没有
(2)接下来先新建main.cpp。
输入以下内容:
#includeusing namespace std; int main(){ cout << "Hello World!" << endl; return 0; }
再创建launch.json:
选择1(“运行和调试”),再“创建launch.json”,再选择“C++(GDB/LLDB)”(这里特别说明一下,一般只有安装了MinGW之后才会有这个,具体安装方法自行百度),再按照下面的选择:
然后在下面的“终端”就可以看见下面运行成功:
此时目录结构变成这样:
相当于VSCode已经为我们创建好了最基础的配置文件,而其中的main.exe就是生成的二进制可执行文件。
- 接下来继续创建MyClass目录
(1)按照下图创建目录:
源码分别如下:
Parent.h
#ifndef PARENT_H
#define PARENT_H
class Parent
{
public:
static int num; //设置静态成员变量
static void get_value();
public:
Parent();
virtual ~Parent();
virtual void print();
};
#endif
Parent.cpp
#include "Parent.h" #includeParent::Parent(){ std::cout << "Create a parent" << std::endl; } Parent::~Parent(){ std::cout << "Delete a parent" << std::endl; } void Parent::print(){ std::cout << "I am Parent!" << std::endl; } void Parent::get_value(){ std::cout << "Parent value is " << num << std::endl; } int Parent::num = 0;
Child.h
#ifndef CHILD_H
#define CHILD_H
#include "Parent.h"
class Child: public Parent{
public:
Child();
~Child();
void print();
};
#endif
Child.cpp
#include "Child.h" #includeChild::Child(){ std::cout << "Create a child!" << std::endl; } Child::~Child(){ std::cout << "Delete a Child" << std::endl; } void Child::print(){ std::cout << "I am Child!" << std::endl; }
Blob.h
#ifndef BLOB_H #define BLOB_H #includeclass Blob{ public: Blob() : data_(nullptr), size_(0){ log("Blob's default constructor"); } explicit Blob(unsigned int size) : data_(new char[size]), size_(size){ log("Blob's parameter constructor"); } ~Blob(){ log("Blob's destructor"); delete[] data_; } //拷贝构造函数 Blob(const Blob& other){ log("Blob's copy constructor"); data_ = new char[other.size_]; memcpy(data_, other.data_, other.size_); size_ = other.size_; } //重载赋值操作符 Blob& operator= (const Blob& other){ log("Blob's copy assignment operator"); if (this == &other){ return *this; } delete[] data_; data_ = new char[other.size_]; memcpy(data_, other.data_, other.size_); size_ = other.size_; return *this; } //移动构造函数 Blob(Blob&& other) : data_(other.data_), size_(other.size_){ log("Blob's move constructor"); other.data_ = nullptr; other.size_ = 0; } //重载移动赋值操作符 Blob& operator= (Blob&& other){ data_ = other.data_; size_ = other.size_; other.data_ = nullptr; other.size_ = 0; return *this; } private: char* data_; unsigned int size_; void log(const char* msg){ std::cout << "[" << this << "]" << msg << std::endl; } }; #endif
此时在Parent.cpp和Child.cpp里面都会看到波浪号如下:
(2)接下来就开始解决文件包含的问题
进入“命令面板”,开始配置C/C++:编译配置(JSON)
在.vscode目录下可以看到生成了一个c_cpp_properties.json,其中需要特别改动的如下
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**" //改动:这个是为了解决由于无法解析头文件包含的问题而显示出来的波浪号,当然,这个也与后续的编译有关
],
"windowsSdkVersion": "10.0.17763.0",
"compilerPath": "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64"
}
],
"version": 4
}
其中${workspaceFolder}是VSCode自定义的变量,表示当前工作路径,即F:VSCodeWorkplace2。当然,还定义了其他的变量,参考网上其他帖子将可能会用到的变量贴出来:
${workspaceFolder} :表示当前workspace文件夹路径,也即/home/Coding/Test
${workspaceRootFolderName}:表示workspace的文件夹名,也即Test
${file}:文件自身的绝对路径,也即/home/Coding/Test/.vscode/tasks.json
${relativeFile}:文件在workspace中的路径,也即.vscode/tasks.json
${filebasenameNoExtension}:当前文件的文件名,不带后缀,也即tasks
${filebasename}:当前文件的文件名,tasks.json
${fileDirname}:文件所在的文件夹路径,也即/home/Coding/Test/.vscode
${fileExtname}:当前文件的后缀,也即.json
${lineNumber}:当前文件光标所在的行号
${env:PATH}:系统中的环境变量
————————————————
版权声明:本文为CSDN博主「扎不下村村长」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_39249524/article/details/105438814
再看tasks.json,改动如下
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "D:\SoftWareInstall\mingw64\bin\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"${workspaceFolder}\MyClass\Parent.cpp", //改动:增加Parent.cpp
"${workspaceFolder}\MyClass\Child.cpp", //改动:增加Child.cpp
"-IF:\VSCode_workplace\MyClass\include", //改动:增加头文件路径
"-o",
"${fileDirname}\${filebasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}
当然,当然为了简化,可以更改成下面这样:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe 生成活动文件",
"command": "D:\SoftWareInstall\mingw64\bin\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"${workspaceFolder}\MyClass\*.cpp", //改动:此处采用通配符的形式
//"${workspaceFolder}\MyClass\Parent.cpp",
//"${workspaceFolder}\MyClass\Child.cpp",
"-I",
"F:\VSCode_workplace\MyClass\include",
"-o",
"${fileDirname}\${filebasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "调试器生成的任务。"
}
],
"version": "2.0.0"
}
另外,为了测试完整的工程,把main.cpp改成如下样子:
#include//#include "Blob.h" #include "Parent.h" #include "Child.h" int main(int, char**) { std::cout << "Hello, world!n"; //Blob *blob = new Blob(); //delete blob; //blob = nullptr; Child* child = new Child(); Parent* parent = child; parent->print(); delete parent; parent = nullptr; }
至此,会发现还有波浪号问题(但是编译运行没问题)。通过查询,发现是clang的设置问题,按照如下设置,把Clang的Diagnostic的Enable的√去掉
此处是有参考VScode编译C++,首次成功,多编译几次头文件显示not found的解决方法
至此,头文件的波浪号和无法找到头文件的问题就解决了。
(3)编译运行,选择“运行”中的“启动调试”或“以非调试模式运行”
这里作者通过快速截图,将编译过程的命令展示如下:
运行结果如下:
至此,整个工程的编译运行都完成了,并且看不到任何波浪号。
(4)讨论:
- ${file}表示当前正在打开的文件的绝对路径,特别注意,这个变量并不是固定。
比如,你当前正在打开的是main.cpp,你停留在main.cpp文件上,你去点击“以非调试模式运行(Ctrl + F5)”,那么其实VSCode就会根据你刚才在tasks.json中args来先进行编译。
从上面编译过程的截图可以看到-g后面有3个.cpp文件(-g是指为编译过程增加调试信息,具体可以百度),后两个可以理解,是我们自己增加的;
但是还有一个F:VSCodeWorkplace2main.cpp是怎么来的呢?只能是${file}转化来的,而前面说过,我们是停留在main.cpp页面上去执行“以非调试模式运行(Ctrl + F5)”,那么${file}就会转化为main.cpp这个文件的绝对路径。之前作者以为${file}是这个tasks.json的绝对路径,但是编译过程却根本没有显示,反而是main.cpp的绝对路径,所以其实就说明${file}是会变换的。



