使用VsCode+makefile开发C/C++

1. 介绍

  vscode作为现在越来越受欢迎的编辑器之一,因为可以使用插件让vscode支持几乎市面上所有的编程语言,由于笔者主要接触的是 C/C++ 方面,因此在这里简单介绍一下如何搭建vscode编译、调试C/C++项目的过程;整套环境完全使用开源软件进行搭建,只需要做很少的改变就可以无缝搬移到linux中;采用的方案是:vscode+git+mingw gcc+makefile;最后有详细的技术说明和资源分享(GitHub 项目:vscode_c_demo);

  介绍一下笔者搭建的平台和所需要的软件:

                       

1. win7 以上;

2. VS Code 官方下载地址

3. Git (官方下载地址);

4. mingw GUN 编译工具 (官方下载地址);

5. 在VS Code中你需要安装

5.1. C/C++ 插件(用于智能代码提示);

5.2. Chinese (Simplified) Language Pack(中文简体支持包,英文好的请忽略)

下载安装VsCode插件比较简单;点击右侧图标搜索即可; ,或者 快捷键 "Ctrl+Shift+X",搜索上述插件名称即可;

 

笔者不建议在mingw 的官网下载GCC 编译器;因为网络的速度会很慢,会等很久;很多开源的编译器都会自带mingwGcc编译器;例如DEVC++ 、Qt 等;

这里提供一个百度链接 https://pan.baidu.com/s/1x-jXHtiiWI0Kc1l34M_LrA       提取码:8q0d  ;里面有上述所需要的所有安装包;截至2019年11月8日,里面的安装包均是最新版本,里面请区分32bit和64bit;

 

 2.安装软件

上述所有软件下载好之后,我们就可以开始安装程序了,所有程序可以一起安装,这里我们只讲解安装过程中的注意事项;

首先安装中,安装路径中不能出现中文;尽量避免空格 !

---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

2.1  mingw GUN GCC 编译器

mingw 在我的百度云链接中是压缩包,我们把他解压到指定位置后(我解压的位置是C:/mingw32 ),将编译器的bin目录添加到系统环境变量;如何添加系统环境变量请自行百度;

查看是否添加成功:打开 cmd(window + R 输入cmd打开命令行窗口) 输入   g++ --version   如果出现类似以下字样表示设置环境变量成功;

 

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

2.2  Git

 

git 的默认编辑器是 vim 如果你从来没有听说过Git,那么请一路 next 安装;如果你有听过git ;我想我这个菜鸟也帮不了你啥~;如果你正在学习git,你可以看看这篇文章:git学习笔记--基础运用

 

 

  ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

2.3  VS Code

 

安装vscode 也比较简单,只有一个需要注意

 


 

一定要将 “通过Code 打开操作” 添加到目录的上下文菜单,后期作用会比较大;其他选项请自行选择;

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

 2.4  安装插件

                           

 

插件安装之后会提示重启vscode 激活插件,重启即可

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

3.配置参数

 1. 导入一个示例项目

这边你们可以随便导入一个项目,可以有多个文件夹,文件夹中可以有.c/.h文件,但是有一个要求,就是在里面的文件不存在冲突;即文件夹里面的源文件都是需要用到的,就算没有用到,也没有命名冲突等系列问题;

因为接下来的这个makefile会自动将你项目文件夹下所有的.c/.h文件全部编译,如果出现冲突,那么请你自己解决;最好的情况是:你用到了哪些文件你就放入哪些文件,不需要的文件可以修改他的后缀名;

为了方便展示,我从github 上clone 一个项目到文件夹下;在文件夹空白处右键单击,选择git bash here 输入:

 

git clone https://github.com/KimAlittleStar/vscode_c_demo.git

 

克隆成功后,右键点击生成出来的 vscode_c_demo文件夹;open with vscode ;文件树如下:

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

2.设置默认的shell 命令行

点击左下角 齿轮图标 选择 设置 或者  点击 文件->首选项->设置 打开如下界面

如果你选择用户,那么更改的是默认配置,如果你选择工作区,那么你做的设置只会在这个文件夹内部起作用;

 

 

  ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

3.让VScode 提供智能提示

 

 

 

 

//C:/Git/bin/bash.exe 应该是你安装的git的bin目录下的bash.exe
//C:/mingw32/bin/gcc.exe 应该是你安装的mingw下bin目录的gcc.exe
//如果你的项目是C++ ,请换成 g++.exe
//如果复制此段单吗到你的 setting.json文件后出错,请删除注释
{
    "terminal.integrated.automationShell.windows":"C:/Git/bin/bash.exe",
    "C_Cpp.default.compilerPath": "C:/mingw32/bin/gcc.exe"
}

 

 

 

 

 

  ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

4.设置编译任务task.json 和 运行设置  launch.json

 

 

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    //此 json 文件中需要注意的就是 执行makefile的执行文件是 mingw32-make.exe ,如果你使用qmake 或者其他make 执行文件,替换它即可;其他不需要修改
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build", //task的名字,调用方式就是 task build
            "command": "mingw32-make.exe", //会在命令行中调用此命令
            "args": [ //调用上述 mingw32-make.exe 传递给它的参数
                "target=${workspaceRootFolderName}.exe" //${workspaceRootFolderName} 会被替换成 根目录 即:vscode_c_demo
            ],
            "type": "shell",
            "problemMatcher": []
        }, //此命令等效展开为:mingw32-make.exe target=vscode_c_demo.exe
        {
            "label": "build-debug",
            "command": "mingw32-make.exe",
            "args": [
                "target=${workspaceRootFolderName}.exe",
                "DEBUG=-g", //添加debug 参数 使gcc 生成调试信息
                "PREDEF=Debug" //相当于在程序中定义了一个宏定义 #define Debug
            ],
            "type": "shell"
        }, //此命令等效展开为:mingw32-make.exe target=vscode_c_demo.exe DEBUG=-g PREDEF=Debug
        {
            "label": "clean",
            "command": "mingw32-make.exe",
            "args": [
                "clean",
                "target=${workspaceRootFolderName}.exe"
            ],
            "type": "shell",
            "problemMatcher": []
        }, //此命令等效展开为:mingw32-make.exe clean target=vscode_c_demo.exe
        {
            "label": "runing",
            "command": "./runExcute.sh",
            "args": [
                "${workspaceRootFolderName}.exe" // 传给脚本的参数
            ],
            "type": "shell"
        } //此命令等效展开为:mingw32-make.exe target=vscode_c_demo.exe  然后执行 ./vscode_c_demo.exe
    ]
}
task.json

 

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    // 
    //这里我们需要注意修改的是:"miDebuggerPath": "C:/Qt/Tools/mingw730_64/bin/gdb.exe"
    //
    //这里gdb的路径应该是你自己的gdb 文件路径
    // 
    // "program": "${workspaceFolder}/${workspaceRootFolderName}.exe"
    // 这里调用的exe 应就是 task build-debug 中生成的可执行文件;
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) 启动", //名字,会显示在debug 的选项中
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/${workspaceRootFolderName}.exe", //表示要调试的可执行文件在当前打开的文件下下的这个文件,此名称需要和task 中的target=<>,一一对应;
            "args": [],
            "stopAtEntry": false, //时候要在main函数处自动停止,false表示不会停止,true表示会在main函数处自动停止;
            "cwd": "${workspaceFolder}", //表示首先要切换到当前目录下
            "environment": [],
            "externalConsole": true, //为true时,会新建一个黑窗口运行程序,如果为false ,就会在vscode中新建终端,
            //不过这样就需要在用户设置中设置默认bash 为 gitbash,否则会报错
            "MIMode": "gdb",
            "miDebuggerPath": "C:/Qt/Tools/mingw730_64/bin/gdb.exe", // 这里填写的应该是你自己gdb.exe文件的路径;一般与g++.exe minwg32-make.exe 在同一文件夹下
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "build-debug" //在执行这个gdb launcher 之前,首先执行task build-debug;
        }
    ]
}
launch.json

 

 

 

贴一下task.josn 和 launch.json 的代码

 

  ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

5.尝试运行 

快捷键  CTRL + P 打开命令行 输入 task+空格+任务命令 即可执行相应命令

task.json中一共创建了4个命令; 分别是  build build-debug clean running

task build #创建一个文件夹名字相同的可执行文件;并且所有的中间文件都会生成放在build文件夹下;

task build-debug #与build类似,但是会生成调试信息,如果你想使用gdb等工具调试,那么必须使用此选项;

task clean #清除所有由build带来的文件

task runing #一共分两步,首先build ,其次调用其可执行文件;
task命令解释

 

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

 6 DEBUG 选项

vscode Debug使用的是mingw32中的gdb.exe调试,与平常的断点调试并无太大差异;

具体使用方法如下:点击左侧导航键 虫子的图标,选择(gdb)启动,点击右方绿色的开始图标,vscode会自动开始编译,运行到断点处会自动停止,更多设置请参考上文launch.json中的注释

 

 

 

  ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

4.原理分析

        整个环境搭建最主要的工作在于:mingw32-make.exe 中,实际上,如果你安装了git ,并按照上述方式修改了默认的终端为 gitbash,那么你只需要在终端中输入 mingw32-make.exe target=a.exe ,也会自动生成一个a.exe的可执行文件,在终端输入mingw32-make.exe clean target=a.exe,也可以清除所有由build带来的所有新建的中间依赖文件;task.json的作用就在于 当我 输入 task build 时 ,就相当于我在gitbash中输入了mingw32-make.exe target=DirName.exe 这个命令;

  接下来我们会分析为什么mingw32-make.exe 可以做到这些,如果你仔细观察我们的文件树,你会发现文件树中有一个没有后缀的文件叫 makefile,我们可以打开makefile 文件,

 

#此项目源文件后缀类型
PROJECTTYPE = .c

#您想要生成可执行文件的名字 如果外部没有赋值,那么使用obj.out
target ?= obj.out

#是否生成DEBUG选项
DEBUG ?=

#系统之外的宏定义
PREDEF ?=

#获取当前makefile绝对路径
pes_parent_dir:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))////

#删除路径下最后一个 / 
pes_parent_dir:=$(subst /////,,$(pes_parent_dir))

#获得mkfile 的实际路径  测试使用,  没有实际用到 可删除
mkPath:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))////
mkPath:=$(subst /////,,$(mkPath))

#将所有宏定义前方加入-D指令以便给编译器识别
DEF := $(foreach n,$(PREDEF),-D$(n))

#获取目录下所有子目录
AllDirs := $(shell cd $(pes_parent_dir); ls -R | grep '^\./.*:$$' | awk '{gsub(":","");print}') .

#添加成为绝对路径
AllDirs := $(foreach n,$(AllDirs),$(subst .,$(pes_parent_dir),$(n)))

#获取所有 .c/.cpp文件路径
Sources := $(foreach n,$(AllDirs) , $(wildcard $(n)/*$(PROJECTTYPE)))

#设置*.o 和 *.d 文件的存放路径
buildPath :=$(foreach n,$(Sources),$(subst $(pes_parent_dir),$(pes_parent_dir)/build,$(n)))

#处理得到*.o 后缀文件名
OBJS := $(patsubst %$(PROJECTTYPE),%.o, $(buildPath))  

#同理得到 *.d文件名
Deps := $(patsubst %$(PROJECTTYPE),%.d, $(buildPath))  

#需要用到的第三方静态库
StaticLib :=

#需要用到的第三方动态链接库
DynamicLib := 

#真实二进制文件输出路径
Bin :=$(pes_parent_dir)/$(target)

#C语言编译器
CC = gcc

#C++编译器
CXX = g++

#简化rm -f
RM = rm -f

#C语言配置参数
CFLAGS = -g  -pedantic -std=c11 -Wall -o

#C++配置参数
CXXFLAGS = -g -Wall -std=c11 

#头文件搜索路径
INCLUDE_PATH = $(foreach n,$(AllDirs) , -I$(n))
LDFLAGS = 

#指定AllLibs为终极目标 即:最新的Bin 
AllLibs:$(Bin)

#声明这个标签 des 用于观察当前的路径是否正确
.PHONY:des
des:
    @echo OBJS =  $(OBJS)
    @echo cur_makefile_path = $(pes_parent_dir)
    @echo AllDirs = $(AllDirs)
    @echo Sources = $(Sources)
    @echo Deps = $(Deps)
    @echo makefilePath =$(mkPath)
    @echo bulidPath=$(buildPath)
    @echo PREDEF = $(DEF)
    @echo DEBUG = $(DEBUG)

#对应关系 在本makefile中以空格隔开的后缀为.c 都会为其生成一个新的.d文件
#$(pes_parent_dir)/build/%.d :$(pes_parent_dir)/%.c  
#       @echo 'finding $< depending head file'
#       @if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi;
#       @$(CC) -MT"$(<:.c=.o) $@" -MM $(INCLUDE_PATH) $(CPPFLAGS) $< > $@


#对应关系 在本makefile中以空格隔开的后缀为.c 都会为其生成一个新的.d文件
$(pes_parent_dir)/build/%.d :$(pes_parent_dir)/%.c
    @echo 'finding $< depending head file'
    @if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi;
    @set -e; rm -f $@; \
    $(CC) -MM $(INCLUDE_PATH) $(DEF) $(CPPFLAGS) $< > $@.$$$$; \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    rm -f $@.$$$$


#对于include中的*.d文件,只要里面任意有一个文件被修改,那么就会触发此规则生成一个新的*.o文件
%.o: %.d
    @echo compile $(patsubst %.d,%.c,$(subst build/,,$<)) 
    @$(CC) -c $(patsubst %.d,%.c,$(subst build/,,$<)) $(DEBUG) $(DEF) $(INCLUDE_PATH) $(CFLAGS) $@ 



$(Bin) : $(OBJS)  
    @echo bulding....
    @$(CC) $(OBJS)  $(CFLAGS) $(Bin)
    @echo created file: $(target)    

.PHONY : clean  
clean:   
        @echo '清理所有文件ing...'
        @$(RM) -r $(pes_parent_dir)/build/
        @echo '清理可执行文件ing...'
        @$(RM) $(Bin)
        @echo 'done'

.PHONY : cleanO
cleanO:
        @echo '清理Obj && Dep'
        @$(RM) -r $(pes_parent_dir)/build
        @echo 'done'
#main.out: $(OBJ)
#    cc -o main.out $(OBJ)

include $(buildPath:.c=.d)

    
makefile

 

 

   在上述makefile 中,比较关键的语句在于

 

#获取目录下所有子目录
AllDirs := $(shell cd $(pes_parent_dir); ls -R | grep '^\./.*:$$' | awk '{gsub(":","");print}') .
···
#对应关系 在本makefile中以空格隔开的后缀为.c 都会为其生成一个新的.d文件
$(pes_parent_dir)/build/%.d :$(pes_parent_dir)/%.c
@echo 'finding $< depending head file'
@if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi;
@set -e; rm -f $@; \
$(CC) -MM $(INCLUDE_PATH) $(DEF) $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$

 

 

 

 shell cd  $(pes_parent_dir) 表示切换路径到该makefile 的目录下,然后 ls -R :递归输入该目录下的所有文件以及文件夹;如果是文件夹,那么就会单独起一行然后文件夹名字前有 ‘.’ 作为标记 后面的grep 和 awk 、gsup 都是linux下才有的命令;

同理在 下方 if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi; 所做的逻辑就是判断当前想要生成的*.d文件的目标文件夹在不在, 不在则创建它, 其中 dir  mkdir 都是linux中才会有的命令,当然windows下也有与其差不多功能的命令,但是此makefile我希望在linux下也能用,这个时候怎么办呢,这个时候就要介绍我们的 Git 了,git在windows中使用的命令行软件 bash.exe 就把上面的命令都覆盖到了,也就是说,如果我们使用windows 自带的cmd.exe 或者 powerShell.exe 里面都会使得 dir mkdir 和其他命令找不到,导致makefile错误终止;所以我们才需要安装Git ,所以我们才需要将Git bash 设置成为vsCode 默认的终端;因为只有git bash 中才可以调用上述makefile中的几个shell命令

还记的我们将mingw32编译器的路径加入到了系统环境变量里面去了~为什么呢?

#C语言编译器
CC = gcc

#C++编译器
CXX = g++

 

因为 在makefile 的编译器中,gcc 、g++ 只是简单的字符,只有将gcc 、g++ 的路径加入了环境变量,他们才能正确的被找到;

还有,如果我们想管理C++ 项目这个时候怎么办呢~我们只需要在 makefile中将所有的 $(CC) 替换成 $(CXX)  所有 的$(CFLAG) 替换成 $(CXXFLAG) 就可以了哦~

makefile中其他的只是我就不赘述了,你可以参考这个链接:一个自动管理项目的makefile

最后献上我整个项目的github地址https://github.com/KimAlittleStar/vscode_c_demo

里面有所有的项目文件,以及配置文件,和较为详细的注释;只需要修改几个简单的路径就可以完成上述的配置;我都有在json文件里面说明哦~~~

 

 ---------------------------------------------------------------------------------------华丽丽分割线---------------------------------------------------------------------------------------

如果关注度还可以的话;

我会选择更新:

一键/自动转换 C/C++ 项目的makefile,

编写一个只清楚中间文件,而不清除可执行文件的task

搭建VSCode + 嵌入式 ARM编译调试环境

 

码字不易,觉得稍微有点用的,可以在git里面 star一下,博客点个小赞;

读书的时候就想了2、3年的事情,现在终于快要看到成功了;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2019-11-08 23:05  Kim_小星兴  阅读(1953)  评论(0编辑  收藏  举报