写作原因

  • 微软的 VSCode 一直以来为人诟病的一个问题就是对于 C/C++ 工程的编译以及调试支持度有限,配置起来比较复杂,但是 vscode-cpptools 团队经过一段时间的 bug 修复之后,为我们带来了众多新特性
  • 截止到本文作成时 (2017-8-4) 此扩展已经更新到 0.12.1 版本,经过尝试使用,新版本对于 C/C++ 的支持有了很大提升,但目前中文博客很少有提到如何使用新版的 vscode-cpptools,而旧版与新版之间的区别也比较明显,所以这里记录一个 C/C++ 工作环境配置方案以供参考

面向的问题

  • 一直以来,写一个小型的 C/C++ 代码工程是非常令人头疼的一件事,比如有一个只有几个源文件的代码工程需要编辑和编译:

    • 打开 IDE 进行编辑,会有种杀鸡焉用牛刀的感觉,本可以在 IDE 打开的过程中就完成修改和编译工作
    • 使用代码编辑器配合命令行进行编译,如果代码有配合 Makefile,那么编译不成问题,但是调试又是一个麻烦,命令行下的调试工具没有那么直观,学习起来也很耗费时间
  • 所以能不能做个折衷,直接在轻量级的代码编辑器完成编辑、编译、调试的工作呢?直到最近 vscode-cpptools 做了大量更新,这个想法才得以更好地实现

准备工作

工具准备

  1. 安装 VS Code: 由于我们这里记录的是工具配置,所以暂不介绍安装流程,但相信点进这篇博客的读者具备安装工具的能力,或者已经安装好了 VS Code
  2. 安装 vscode-cpptools: 在 VS Code 的插件安装栏中搜索 C/C++ 即可找到微软官方出品的这个工具,根据指引安装并重载窗口即可
  3. 编译工具安装: 一般来讲在 VS Code 中进行开发并不涉及编译工具版本,但是由于其对 Clang 的支持比较好,我推荐有能力的读者安装 Clang ,当然其他的任何编译工具都是可以的,包括 GCC,MSVC等
    • 但是这里不得不提的一点是,在 Windows 下安装 Clang 是一件不太愉快的事情,如果您在安装时遇到困难,大可放弃安装 Clang ,转而安装 GCC
    • 本文讲解的内容是在 Windows 下实现的,在其他系统当中仅需对工具目录等进行简单的修改即可复现这个过程

方案选择

  • 根据应用环境不同,本文提出两种解决 C/C++ 工作环境配置的方案:

    1. 第一种是完全依赖 VS Code 的解决方案,即只使用其内置工具实现工作环境配置。这种方案比较简单,但是对于代码的迁移和扩展造成了一定的困扰。
    2. 第二种是 VS Code 配合 Makefile 的解决方案,即使用 VS Code 的代码编辑功能,配合 Makefile 的编译支持来配置工作环境。相对第一种解决方案,这种方案更适合代码的迁移
      • 例如代码从 Windows 平台的 VS Code 中迁移到服务器的 Linux 命令行下时,可以在 Windows 中使用 VS Code 来编辑和编译,将代码迁移后在 Linux 下使用 Makefile来编译

方案一:VS Code 原生工具编译

1. 新建测试工程

首先新建一个文件夹 VSC-CPP 并编写几个源文件,作为测试样例

这个工程包含五个文件,包括两对 .cpp + .h 的函数声明与实现,以及一个调用这两个函数的 main.cpp

目录结构

- add.h     // add() 函数声明
- add.cpp // add() 函数实现
- sub.h // sub() 函数声明
- sub.cpp // sub() 函数实现
- main.cpp // 调用 add() 与 sub()
  • add.h:
#ifndef _ADD_H_
#define _ADD_H_ int add(int a, int b);

endif // ! ADD_H

  • add.cpp:
#include "add.h"

int add(int a, int b) { return a + b; }
  • sub.h:
#ifndef _SUB_H_
#define _SUB_H_ int sub(int a, int b);

endif // ! SUB_H

  • sub.cpp:
#include "sub.h"

int sub(int a, int b) { return a - b; }
  • main.cpp:
#include "add.h"
#include "sub.h"
#include <iostream> int main() {

std::cout << add(1, 2) << std::endl;

std::cout << sub(2, 1) << std::endl;

return 0;

}

2. 配置环境

首先假定我们使用的编译工具如下:

  1. 编译工具:g++
  2. 调试工具:gdb
  • 在 VS Code 中打开工具窗口 (默认Ctrl+Alt+P) ,输入 C/CPP: Edit Configurations来生成配置文件

  • 然后在自动打开的c_cpp_properties.json中配置 Include路径等内容 (一般而言自动生成的就是可用的,但是 Windows 下可能需要额外配置)

  • 上一步结束后,一些 C/C++ 的代码提示等功能应该就可以正常工作了,接下来我们让 VS Code 能处理编译工作
  • 打开工具窗口 (默认Ctrl+Shift+P) → \rightarrow" role="presentation">→→ \rightarrow→ 输入Tasks: Configure Task Runner,弹出窗口中选择 Others (这里是假定我们要用 GCC 来编译,如果使用 MSBuild 做这项工作,那么可以直接选择 MSBuild 选项) → \rightarrow" role="presentation">→→ \rightarrow→ 在新打开的tasks.json中配置如下 注意:复制这段代码的时候请删除其中的注释,否则可能会报错
    • task.json:
{
"version": "2.0.0",
"tasks": [
{
// 默认第一条为编译命令
"taskName": "build",
// 使用 g++ 编译
"command": "g++",
// 参数包含所有使用到的源文件
"args": [
"main.cpp",
"add.cpp",
"sub.cpp",
"-o",
"main.exe"
],
// 默认在 shell 中执行编译命令
"type": "shell"
},
{
// 编译 debug 用的目标文件
"taskName": "build-debug",
"command": "g++",
// -g 参数用于编译可 debug 的目标文件
"args": [
"-g",
"main.cpp",
"add.cpp",
"sub.cpp",
"-o",
"debug.exe"
],
"type": "shell"
}
]
}
  • 至此代码应该可以正常编译了:打开工具窗口 (默认Ctrl+Alt+P) → \rightarrow" role="presentation">→→ \rightarrow→ 输入Tasks: Run Tasks → \rightarrow" role="presentation">→→ \rightarrow→ 此时应该已经可以看到两个不同的任务,分别为 buildbuild-debug,与上一步定义的相同

  • 选择 build 并执行输出得到的目标文件即可看到结果,说明编译执行是正确无误的

  • 接下来尝试对代码进行调试,进入调试窗口 → \rightarrow" role="presentation">→→ \rightarrow→ 点击调试配置按钮 (如图中红圈所示)

  • 选择 C++(GDB/LLDB) (如果使用 MSVC 编译,可以选择C++(Windows)) → \rightarrow" role="presentation">→→ \rightarrow→ 此时会生成调试配置文件 launcher.json

  • 使用配置如下,根据您的具体系统环境进行修改

{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
// g++ -g 生成的调试用目标文件名
"program": "${workspaceRoot}/debug.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
// 输入 gdb 的路径 (有些情况下需要绝对路径)
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
// task.json 中指定的调试目标文件编译命令
// 这样可以在调试前免去手动执行 build-debug 的一步
"preLaunchTask": "build-debug"
}
]
}
  • 在源文件中添加一个断点,点击调试界面中的开始调试按钮来调试

  • 至此编译和调试工作都可以正常进行了,如果 GDB 版本足够高,在调试 STL 程序时也会有很好的效果

  • 第一种方案的配置到这里基本结束了,大家可以继续探索这种方案,不过这种方案比较受制于 VS Code ,可移植性不高。接下来我们提出另一种方式来提高 VS Code 的 C/C++ 工程的灵活性。

方案二:VS Code 配合 Makefile 来提高 C/C++ 工程的可移植性

准备工作

  • 在方案一的基础上仍需准备如下内容:
  • 准备一套 Makefile 模板,比如说 https://github.com/TheNetAdmin/Makefile-Templates ,或者也可以自行写一套模板,一个好的 Makefile 模板可以省去很多麻烦
  • 安装编译工具与 make 工具:尤其是在 Windows 下,使用 make 是一个比较麻烦的事情,推荐大家使用 msys 提供的一套工具,这里有一个打包供下载 https://pan.baidu.com/s/1kV5hx3p

方案说明

  • 这个方案的思路是:使用 Makefile 来构建工程, VS Code 通过 Tasks 调用 make 工具来编译,再通过调用 gdb 来调试
  • 其优点在于不是过分依赖 VS Code 自身的配置,一个合适的 Makefile 可以在各个平台上执行编译,但是在开发过程中又可以用到 VS Code 自身的插件带来的便利,减少命令输入,减少命令行 gdb 调试带来的烦恼

步骤说明

  • 首先构建一个 Makefile ,如果没有合适的可以到这里找到一些现成模板
# originating https://github.com/TheNetAdmin/Makefile-Templates
# tool marcros
CC := g++
CCFLAG := -std=c++14
DBGFLAG := -g
CCOBJFLAG := $(CCFLAG) -c

path marcros

BIN_PATH := bin

OBJ_PATH := obj

SRC_PATH := src

DBG_PATH := debug

compile marcros

TARGET_NAME := main

ifeq ($(OS),Windows_NT)

TARGET_NAME := $(addsuffix .exe,$(TARGET_NAME))

endif

TARGET := $(BIN_PATH)/$(TARGET_NAME)

TARGET_DEBUG := $(DBG_PATH)/$(TARGET_NAME)

MAIN_SRC := src/main.cpp

src files & obj files

SRC := $(foreach x, $(SRC_PATH), $(wildcard $(addprefix $(x)/,.c)))

OBJ := $(addprefix $(OBJ_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))

OBJ_DEBUG := $(addprefix $(DBG_PATH)/, $(addsuffix .o, $(notdir $(basename $(SRC)))))

clean files list

DISTCLEAN_LIST := $(OBJ)

$(OBJ_DEBUG)

CLEAN_LIST := $(TARGET)

$(TARGET_DEBUG)

$(DISTCLEAN_LIST)

default rule

default: all

non-phony targets

$(TARGET): $(OBJ)

$(CC) $(CCFLAG) -o $@ $? $(OBJ_PATH)/%.o: $(SRC_PATH)/%.c*

$(CC) $(CCOBJFLAG) -o $@ $< $(DBG_PATH)/%.o: $(SRC_PATH)/%.c*

$(CC) $(CCOBJFLAG) $(DBGFLAG) -o $@ $< $(TARGET_DEBUG): $(OBJ_DEBUG)

$(CC) $(CCFLAG) $(DBGFLAG) $? -o $@

phony rules

.PHONY: all

all: $(TARGET) .PHONY: debug

debug: $(TARGET_DEBUG) .PHONY: clean

clean:

@echo CLEAN $(CLEAN_LIST)

@rm -f $(CLEAN_LIST) .PHONY: distclean

distclean:

@echo CLEAN $(CLEAN_LIST)

@rm -f $(DISTCLEAN_LIST)
  • 根据这个 Makefile,构建一个目录结构如下的工程目录
- Project
- Makefile
- src: 所有源文件 (不得放在子目录)
- add.cpp
- add.h
- sub.cpp
- sub.h
- main.cpp
- obj
- 空
- debug
- 空
- bin
- 空
  • 然后对于 VS Code 的 tasks.json 和 launch.json 做一些修改如下
  • tasks.json
{
"version": "2.0.0",
"tasks": [
{
"taskName": "build",
"command": "make",
"args": ["default"],
"type": "shell"
},
{
"taskName": "build-debug",
"command": "make",
"args": ["debug"],
"type": "shell"
},
{
"taskName": "clean",
"command": "make",
"args": ["clean"],
"type": "shell"
}
]
}
  • launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
// 修改为新的测试目标文件路径
"program": "${workspaceRoot}/debug/main.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build-debug"
}
]
}
  • 之后就如方案一中的步骤使用编译和调试工具即可

  • 这样的话将这个工程迁移到其他平台也不用担心没有 VS Code 而无法使用
  • 同时,如果工程发生重构,那么只需要更改 Makefile 与工程结构即可,不需要在 VS Code 中修改过多

总结

  • 总体而言,经过微软官方团队一段时间的努力, VS Code 上的 C/C++ 开发体验有了很大提升,在面对一个比较小型的工程时,我们可以免去开启 IDE 的时间以及处理 IDE 目录结构的时间,从而快速打开工程,快速开发并验证思路

  • 但是 VS Code 毕竟只是一个代码编辑器,无论我们赋予它多少功能,其对大型工程的处理能力终究是不如 IDE 的。比如 Refactor ,包管理,动态类型纠错,语法纠错等功能一直是 IDE 的强项,所以在面对比较复杂的工程时,不用多想,还是乖乖使用 IDE 吧

        </div>

VS Code 配置 C/C++ 环境的更多相关文章

  1. Windows 10 Mac 为Vs Code配置C/C++环境

    2019-06-10 更新: 加上Mac版本的Vscode配置文件 0.前言 实现效果:右键一键编译运行C/C++文件 Vs code的代码效果很好看,也很轻量,所以想为Vs Code配置C/C++环 ...

  2. Visual Studio Code配置 HTML 开发环境

    Visual Studio Code配置 HTML 开发环境 https://v.qq.com/x/page/l0532svf47c.html?spm=a2h0k.11417342.searchres ...

  3. Visual Studio Code配置GoLang开发环境

    Visual Studio Code配置GoLang开发环境 在Visual Studio Code配置GoLang开发环境 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页: ...

  4. VS Code配置C/C++环境

    VS Code配置C/C++环境 一.下载和安装VS Code 1.访问VS Code官网下载安装包 2.安装VS Code 3. 安装后, 打开VS Code是英文,按住Ctrl+shift+x进入 ...

  5. Visual Studio Code 配置C/C++环境

    0. 前言 VS Code 是微软发布一款跨平台的源代码编辑器,其拥有强大的功能和丰富的扩展,使之能适合编写许多语言. 本文面向初学者(但不是纯小白),分享一点我配置C/C++的经验. 本文所有内容均 ...

  6. 1 visual studio code 配置C++开发环境 (windows 开发环境)

    0 引言 最近帮GF(不幸变成ex了)配置C++开发环境,一开始想给她装个visual studio13完事,但是一想到自己安装以及使用时的诸多麻烦,就有点退却,觉得没有这个必要.正好了解到vscod ...

  7. Windows VS Code 配置 Java 开发环境

    Windows VS Code 配置 C/C++ 开发环境 准备 Windows [这个相信大家都有 笑: )] VS Code JDK 建议 JDK8以上(不包含JDK8,关于 Windows环境下 ...

  8. Vs code配置Go语言环境-Mac

    背景:最近受朋友介绍,学习Go语言.那么开始吧,首先从配置环境开始. 电脑:Mac Air,Vs code已经安装 一.Go下载和安装 下载地址:https://golang.google.cn/dl ...

  9. VS Code 配置 C/C++ 环境(转)

      写作原因 微软的 VSCode 一直以来为人诟病的一个问题就是对于 C/C++ 工程的编译以及调试支持度有限,配置起来比较复杂,但是 vscode-cpptools 团队经过一段时间的 bug 修 ...

随机推荐

  1. 6. 网络信息API

    一.用数值表示socket地址&用名字表示socket地址(socket地址==>IP地址和端口号) 1. 用数值表示socket地址不便于记忆,也不便于扩展(比如从IPv4转移到IPv ...

  2. 20181113-7 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 05

    作业要求https://edu.cnblogs.com/campus/nenu/2018fall/homework/2387 版本控制https://git.coding.net/lglr2018/F ...

  3. 【java】中缀表达式转后缀表达式 java实现

    算法: 中缀表达式转后缀表达式的方法:1.遇到操作数:直接输出(添加到后缀表达式中)2.栈为空时,遇到运算符,直接入栈3.遇到左括号:将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出 ...

  4. 四则运算(Android)版

    实验题目: 将小学四则运算整合成网页版或者是Android版.实现有无余数,减法有无负数.... 设计思路: 由于学到的基础知识不足,只能设计简单的加减乘除,界面设计简单,代码量少,只是达到了入门级的 ...

  5. P4tutorial实战

    Tutorial样例实战 GitHub仓库地址 参考博客 实验一:SIGCOMM_2015/Sourse_Routing 实验环境: OS:Ubuntu16.04 bmv2:behavioral-mo ...

  6. 扩展欧几里德 SGU 106

    题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=106   题意:求ax + by + c = 0在[x1, x2], [y1, y2 ...

  7. UIView maskView属性

    给View1的maskView 赋值View2 1.View2不会显示在View1上: 2.View2 的alpha通道会体现在View1上. 关于maskView,Apple的解释: An opti ...

  8. map的默认排序和自定义排序

    STL的容器map为我们处理有序key-value形式数据提供了非常大的便利,由于内部红黑树结构的存储,查找的时间复杂度为O(log2N). 一般而言,使用map的时候直接采取map<typen ...

  9. 类的static成员变量和成员函数能被继承吗

    1.   父类的static变量和函数在派生类中依然可用,但是受访问性控制(比如,父类的private域中的就不可访问),而且对static变量来说,派生类和父类中的static变量是共用空间的,这点 ...

  10. 守护线程以及要使用时注意的一点(Daemon Thread)

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) Daemon的作用是为其他线程的运行提供便利服务,比如垃圾回收线程就是一个很称职的守护者.User和 ...