Jade Dungeon

VSCode开发C、C++

环境准备

GCC、MinGW、Cygwin中的开发工具都可以。 如果是使用cygwin中的gcc,那么对应的包有: 安装好以下工具并且确保它们都在环境变量PATH中:

  • gcc-core
  • gcc-g++
  • make
  • gdb
  • binutils 包含 readelf nm 等 工具(注意:只选择devel版本即可,正常情况下,我们一般需要携带调试信息的版本)

安装完成后可以测试一下如何查看so文件,查看一个完整的so文件的Section命令:

readelf -S libshella-2.8.so

VSCode插件安装

参考官方文档安装C/C++插件:

例子

简单例子

简单地处理两种情况:

  • 编译并调试单个文件
  • 多个文件编译链接并调试

编译并运行单个文件

配置文件.vscode/tasks.json中可以定义多个任务。 可以在里面定义一个任务,直接调用gcc编译我们正在编辑的文件:

{
    "label": "build: sample-1",
    "command": "gcc", //c++为g++, c为gcc
    "args": [ "-g", "${file}", "-o", "${file}.exe" ], // 命令参数
    "options": { "cwd": "${workspaceFolder}" },
    "problemMatcher": {
        "owner": "cpp",
        "fileLocation": [ "relative", "${workspaceRoot}" ],
        "pattern": {
            "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
            "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5
        }
    }
}

注意这里编译参数中:

  • -g表示带调度标记
  • ${file}表示当前正在编辑的那个源代码文件。

配置文件.vscode/launch.json中可以定义多个运行程序的启动配置。 可以在里面定义一个调用gdb的启动配置:

{
    "name": "debug: sample-1",              // 配置名称,将会在启动配置的下拉菜单中显示
    "type": "cppdbg",                           // 配置类型,这里只能为cppdbg
    "request": "launch",                        // 请求配置类型,可以为launch(启动)或attach(附加)
    //"launchOptionType": "Local",              // 调试器启动类型,这里只能为Local
    "targetArchitecture": "x64",                // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64
    "program": "${file}.exe",                   // 将要进行调试的程序的路径
    "miDebuggerPath":"c:/cygwin64/bin/gdb.exe", // miDebugger的路径,注意这里要与cygwin/MinGw的路径对应
    "args": ["blackkitty",  "1221", "# #"],     // 程序调试时传递给程序的命令行参数,一般设为空即可
    "stopAtEntry": true,                        // 设为true时程序将暂停在程序入口处,一般设置为false
    "cwd": "${workspaceRoot}",                  // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录
    "externalConsole": true,                    // 调试时是否显示控制台窗口,一般设置为true显示控制台
    "preLaunchTask": "build: sample-1"    // 调试会话开始前执行的任务,编译
}
  • program指定为${file}.exe,正好是当前编辑的文件名加上后缀。
  • prelaunchTask关联到了之前定义的编译任务。这样在VSCode的「运行视图」 中就可以编译并调试当前程序了。

如果源代码是C++代码,只要在编译任务中把编译命令替换成g++就可以了。 一般C和C++代码都可以用g++命令编译,而gcc命令一般只用来编译c代码。

编译连接并调试

配置文件.vscode/tasks.json中的任务要调用make命令:

{
    "label": "build: sample-3",
    "command": "make", 
    "args": [ "all" ], // 编译命令参数
    "options": { "cwd": "${workspaceFolder}" },
    "problemMatcher": ["$gcc", {
        "owner": "cpp",
        "fileLocation": [ "relative", "${workspaceRoot}" ],
        "pattern": {
            "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
            "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5
        }
    }]
}

配置文件.vscode/launch.json中要指定最终生成的可执行文件, 而不是当前编辑文件的文件名加上后缀:

{
    "name": "debug: sample-3",              // 配置名称,将会在启动配置的下拉菜单中显示
    "type": "cppdbg",                           // 配置类型,这里只能为cppdbg
    "request": "launch",                        // 请求配置类型,可以为launch(启动)或attach(附加)
    //"launchOptionType": "Local",              // 调试器启动类型,这里只能为Local
    "targetArchitecture": "x64",                // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64
    "program": "${workspaceRoot}/out/hello.exe",// 将要进行调试的程序的路径
    "miDebuggerPath":"c:/cygwin64/bin/gdb.exe", // miDebugger的路径,注意这里要与cygwin/MinGw的路径对应
    "args": ["blackkitty",  "1221", "# #"],     // 程序调试时传递给程序的命令行参数,一般设为空即可
    "stopAtEntry": true,                        // 设为true时程序将暂停在程序入口处,一般设置为false
    "cwd": "${workspaceRoot}",                  // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录
    "externalConsole": true,                    // 调试时是否显示控制台窗口,一般设置为true显示控制台
    "preLaunchTask": "build: sample-3"              // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc
}

全部代码

#include <stdio.h>

int main() {
    for (int i = 0; i < 10; i++) {
        printf("%d\n", i);
    }
    return 0;
}
#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;
   return 0;
}
void print_hello();
int factorial(int n);
#include "../functions.h"

int factorial(int n){
	if (n!=1) return n * factorial(n-1);
	else return 1;
}
#include <iostream>

void print_hello() {
	std::cout << "hello world" << std::endl;
}
# include <iostream>
# include "functions.h"

int main() {
	print_hello();
	std::cout << "this is main" << std::endl;
	std::cout << "The factorial of 5 is " << factorial(5) << std::endl;
	return 0;
}
CC = g++

SRC_DIR = src
OUT_DIR = out

rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OUT_DIR)/%.o, $(call rwildcard,src/,*.cpp))

CFLAGS = -c -Wall -g
LFLAGS = -Wall
CYGLIB = -static-libgcc -static-libstdc++

all: $(OUT_DIR)/hello
$(OUT_DIR)/hello: $(OBJS)
	$(CC) $(LFLAGS) $(CYGLIB) $^ -o $@
$(OBJS): $(OUT_DIR)/%.o : $(SRC_DIR)/%.cpp
	@mkdir -p $(@D)
	$(CC) $(CFLAGS) $(CYGLIB) $< -o $@

clean:
	rm -rf $(OUT_DIR)/* $(OUT_DIR)/hello

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build: sample-1",
            "command": "gcc", //c++为g++, c为gcc
            "args": [ "-g", "${file}", "-o", "${file}.exe" ], // 编译命令参数
            "options": { "cwd": "${workspaceFolder}" },
            "problemMatcher": {
                "owner": "cpp",
                "fileLocation": [ "relative", "${workspaceRoot}" ],
                "pattern": {
                    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
                    "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5
                }
            }
        },
        {
            "label": "build: sample-2",
            "command": "g++", //c++为g++, c为gcc
            "args": [ "-g", "${file}", "-o", "${file}.exe" ], // 编译命令参数
            "options": { "cwd": "${workspaceFolder}" },
            "problemMatcher": ["$gcc", {
                "owner": "cpp",
                "fileLocation": [ "relative", "${workspaceRoot}" ],
                "pattern": {
                    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
                    "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5
                }
            }]
        },
        {
            "label": "build: sample-3",
            "command": "make", 
            "args": [ "all" ], // 编译命令参数
            "options": { "cwd": "${workspaceFolder}" },
            "problemMatcher": ["$gcc", {
                "owner": "cpp",
                "fileLocation": [ "relative", "${workspaceRoot}" ],
                "pattern": {
                    "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
                    "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5
                }
            }]
        }
    ]
}
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "debug: sample-1",              // 配置名称,将会在启动配置的下拉菜单中显示
            "type": "cppdbg",                           // 配置类型,这里只能为cppdbg
            "request": "launch",                        // 请求配置类型,可以为launch(启动)或attach(附加)
            //"launchOptionType": "Local",              // 调试器启动类型,这里只能为Local
            "targetArchitecture": "x64",                // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64
            "program": "${file}.exe",                   // 将要进行调试的程序的路径
            "miDebuggerPath":"c:/cygwin64/bin/gdb.exe", // miDebugger的路径,注意这里要与cygwin/MinGw的路径对应
            "args": ["blackkitty",  "1221", "# #"],     // 程序调试时传递给程序的命令行参数,一般设为空即可
            "stopAtEntry": true,                        // 设为true时程序将暂停在程序入口处,一般设置为false
            "cwd": "${workspaceRoot}",                  // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录
            "externalConsole": true,                    // 调试时是否显示控制台窗口,一般设置为true显示控制台
            "preLaunchTask": "build: sample-1"    // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc
        },
        {
            "name": "debug: sample-2",              // 配置名称,将会在启动配置的下拉菜单中显示
            "type": "cppdbg",                           // 配置类型,这里只能为cppdbg
            "request": "launch",                        // 请求配置类型,可以为launch(启动)或attach(附加)
            //"launchOptionType": "Local",              // 调试器启动类型,这里只能为Local
            "targetArchitecture": "x64",                // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64
            "program": "${file}.exe",// 将要进行调试的程序的路径
            "miDebuggerPath":"c:/cygwin64/bin/gdb.exe", // miDebugger的路径,注意这里要与cygwin/MinGw的路径对应
            "args": ["blackkitty",  "1221", "# #"],     // 程序调试时传递给程序的命令行参数,一般设为空即可
            "stopAtEntry": true,                        // 设为true时程序将暂停在程序入口处,一般设置为false
            "cwd": "${workspaceRoot}",                  // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录
            "externalConsole": true,                    // 调试时是否显示控制台窗口,一般设置为true显示控制台
            "preLaunchTask": "build: sample-2"    // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc
        },
        {
            "name": "debug: sample-3",              // 配置名称,将会在启动配置的下拉菜单中显示
            "type": "cppdbg",                           // 配置类型,这里只能为cppdbg
            "request": "launch",                        // 请求配置类型,可以为launch(启动)或attach(附加)
            //"launchOptionType": "Local",              // 调试器启动类型,这里只能为Local
            "targetArchitecture": "x64",                // 生成目标架构,一般为x86或x64,可以为x86, arm, arm64, mips, x64, amd64, x86_64
            "program": "${workspaceRoot}/out/hello.exe",// 将要进行调试的程序的路径
            "miDebuggerPath":"c:/cygwin64/bin/gdb.exe", // miDebugger的路径,注意这里要与cygwin/MinGw的路径对应
            "args": ["blackkitty",  "1221", "# #"],     // 程序调试时传递给程序的命令行参数,一般设为空即可
            "stopAtEntry": true,                        // 设为true时程序将暂停在程序入口处,一般设置为false
            "cwd": "${workspaceRoot}",                  // 调试程序时的工作目录,一般为${workspaceRoot}即代码所在目录
            "externalConsole": true,                    // 调试时是否显示控制台窗口,一般设置为true显示控制台
            "preLaunchTask": "build: sample-3"              // 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc
        }
    ]
}