使用VsCode+makefile開發(fā)C/C++
1. 介紹
vscode作為現(xiàn)在越來越受歡迎的編輯器之一,因?yàn)榭梢允褂貌寮寁scode支持幾乎市面上所有的編程語言,由于筆者主要接觸的是 C/C++ 方面,因此在這里簡單介紹一下如何搭建vscode編譯、調(diào)試C/C++項(xiàng)目的過程;整套環(huán)境完全使用開源軟件進(jìn)行搭建,只需要做很少的改變就可以無縫搬移到linux中;采用的方案是:vscode+git+mingw gcc+makefile;最后有詳細(xì)的技術(shù)說明和資源分享(GitHub 項(xiàng)目:vscode_c_demo);
介紹一下筆者搭建的平臺(tái)和所需要的軟件:






win7 以上;
VS Code 官方下載地址;
Git (官方下載地址);
mingw GUN 編譯工具 (官方下載地址);
-
在VS Code中你需要安裝
5.1. C/C++ 插件(用于智能代碼提示);
5.2. Chinese (Simplified) Language Pack(中文簡體支持包,英文好的請忽略)

,或者 快捷鍵 "Ctrl+Shift+X",搜索上述插件名稱即可;
筆者不建議在mingw 的官網(wǎng)下載GCC 編譯器;因?yàn)榫W(wǎng)絡(luò)的速度會(huì)很慢,會(huì)等很久;很多開源的編譯器都會(huì)自帶mingwGcc編譯器;例如DEVC++ 、Qt 等;
這里提供一個(gè)百度鏈接 https://pan.baidu.com/s/1x-jXHtiiWI0Kc1l34M_LrA 提取碼:8q0d ;里面有上述所需要的所有安裝包;截至2019年11月8日,里面的安裝包均是最新版本,里面請區(qū)分32bit和64bit;
** 2.安裝軟件**
上述所有軟件下載好之后,我們就可以開始安裝程序了,所有程序可以一起安裝,這里我們只講解安裝過程中的注意事項(xiàng);
首先安裝中,安裝路徑中不能出現(xiàn)中文;盡量避免空格 !
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
2.1 mingw GUN GCC 編譯器
mingw 在我的百度云鏈接中是壓縮包,我們把他解壓到指定位置后(我解壓的位置是C:/mingw32 ),將編譯器的bin目錄添加到系統(tǒng)環(huán)境變量;如何添加系統(tǒng)環(huán)境變量請自行百度;
查看是否添加成功:打開 cmd(window + R 輸入cmd打開命令行窗口) 輸入 ** g++ --version ** 如果出現(xiàn)類似以下字樣表示設(shè)置環(huán)境變量成功;

---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
2.2 Git
git 的默認(rèn)編輯器是 vim 如果你從來沒有聽說過Git,那么請一路 next 安裝;如果你有聽過git ;我想我這個(gè)菜鳥也幫不了你啥~;如果你正在學(xué)習(xí)git,你可以看看這篇文章:git學(xué)習(xí)筆記--基礎(chǔ)運(yùn)用
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
2.3 VS Code
安裝vscode 也比較簡單,只有一個(gè)需要注意

一定要將 “通過Code 打開操作” 添加到目錄的上下文菜單,后期作用會(huì)比較大;其他選項(xiàng)請自行選擇;
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
2.4 安裝插件


插件安裝之后會(huì)提示重啟vscode 激活插件,重啟即可
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
3.配置參數(shù)
** 1. 導(dǎo)入一個(gè)示例項(xiàng)目**
這邊你們可以隨便導(dǎo)入一個(gè)項(xiàng)目,可以有多個(gè)文件夾,文件夾中可以有.c/.h文件,但是有一個(gè)要求,就是在里面的文件不存在沖突;即文件夾里面的源文件都是需要用到的,就算沒有用到,也沒有命名沖突等系列問題;
因?yàn)榻酉聛淼倪@個(gè)makefile會(huì)自動(dòng)將你項(xiàng)目文件夾下所有的.c/.h文件全部編譯,如果出現(xiàn)沖突,那么請你自己解決;最好的情況是:你用到了哪些文件你就放入哪些文件,不需要的文件可以修改他的后綴名;
為了方便展示,我從github 上clone 一個(gè)項(xiàng)目到文件夾下;在文件夾空白處右鍵單擊,選擇git bash here 輸入:
git clone https://github.com/KimAlittleStar/vscode_c_demo.git
克隆成功后,右鍵點(diǎn)擊生成出來的 vscode_c_demo文件夾;open with vscode ;文件樹如下:

---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
2.設(shè)置默認(rèn)的shell 命令行
點(diǎn)擊左下角 齒輪圖標(biāo) 選擇 設(shè)置 或者 點(diǎn)擊 文件->首選項(xiàng)->設(shè)置 打開如下界面
如果你選擇用戶,那么更改的是默認(rèn)配置,如果你選擇工作區(qū),那么你做的設(shè)置只會(huì)在這個(gè)文件夾內(nèi)部起作用;

---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
3.讓VScode 提供智能提示

//C:/Git/bin/bash.exe 應(yīng)該是你安裝的git的bin目錄下的bash.exe//C:/mingw32/bin/gcc.exe 應(yīng)該是你安裝的mingw下bin目錄的gcc.exe//如果你的項(xiàng)目是C++ ,請換成 g++.exe//如果復(fù)制此段單嗎到你的 setting.json文件后出錯(cuò),請刪除注釋{ "terminal.integrated.automationShell.windows":"C:/Git/bin/bash.exe", "C_Cpp.default.compilerPath": "C:/mingw32/bin/gcc.exe"}
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
4.設(shè)置編譯任務(wù)task.json 和 運(yùn)行設(shè)置 launch.json
{ // See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format //此 json 文件中需要注意的就是 執(zhí)行makefile的執(zhí)行文件是 mingw32-make.exe ,如果你使用qmake 或者其他make 執(zhí)行文件,替換它即可;其他不需要修改
"version": "2.0.0",
"tasks": [
{
"label": "build", //task的名字,調(diào)用方式就是 task build
"command": "mingw32-make.exe", //會(huì)在命令行中調(diào)用此命令
"args": [ //調(diào)用上述 mingw32-make.exe 傳遞給它的參數(shù)
"target=${workspaceRootFolderName}.exe" //${workspaceRootFolderName} 會(huì)被替換成 根目錄 即: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 參數(shù) 使gcc 生成調(diào)試信息
"PREDEF=Debug" //相當(dāng)于在程序中定義了一個(gè)宏定義#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" // 傳給腳本的參數(shù)
],
"type": "shell"
} //此命令等效展開為:mingw32-make.exe target=vscode_c_demo.exe 然后執(zhí)行 ./vscode_c_demo.exe
]
}
{
// 使用 IntelliSense 了解相關(guān)屬性。
// 懸停以查看現(xiàn)有屬性的描述。
// 欲了解更多信息,請?jiān)L問: https://go.microsoft.com/fwlink/?linkid=830387
//
//這里我們需要注意修改的是:"miDebuggerPath": "C:/Qt/Tools/mingw730_64/bin/gdb.exe"
//
//這里gdb的路徑應(yīng)該是你自己的gdb 文件路徑
//
// "program": "${workspaceFolder}/${workspaceRootFolderName}.exe"
// 這里調(diào)用的exe 應(yīng)就是 task build-debug 中生成的可執(zhí)行文件;
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) 啟動(dòng)", //名字,會(huì)顯示在debug 的選項(xiàng)中
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/${workspaceRootFolderName}.exe", //表示要調(diào)試的可執(zhí)行文件在當(dāng)前打開的文件下下的這個(gè)文件,此名稱需要和task 中的target=<>,一一對應(yīng);
"args": [],
"stopAtEntry": false, //時(shí)候要在main函數(shù)處自動(dòng)停止,false表示不會(huì)停止,true表示會(huì)在main函數(shù)處自動(dòng)停止;
"cwd": "${workspaceFolder}", //表示首先要切換到當(dāng)前目錄下
"environment": [],
"externalConsole": false, //為true時(shí),會(huì)新建一個(gè)黑窗口運(yùn)行程序,如果為false ,就會(huì)在vscode中新建終端,
//不過這樣就需要在用戶設(shè)置中設(shè)置默認(rèn)bash 為 gitbash,否則會(huì)報(bào)錯(cuò)
"MIMode": "gdb",
"miDebuggerPath": "E:/userFile/userSoftware/Qt/Tools/mingw730_64/bin/gdb.exe", // 這里填寫的應(yīng)該是你自己gdb.exe文件的路徑;一般與g++.exe minwg32-make.exe 在同一文件夾下
"setupCommands": [
{
"description": "為 gdb 啟用整齊打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "build-debug" //在執(zhí)行這個(gè)gdb launcher 之前,首先執(zhí)行task build-debug;
}
]
}

貼一下task.josn 和 launch.json 的代碼
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
5.嘗試運(yùn)行
快捷鍵 CTRL + P 打開命令行 輸入 task+空格+任務(wù)命令 即可執(zhí)行相應(yīng)命令
task.json中一共創(chuàng)建了4個(gè)命令; 分別是 build build-debug clean running
task build #創(chuàng)建一個(gè)文件夾名字相同的可執(zhí)行文件;并且所有的中間文件都會(huì)生成放在build文件夾下;
task build-debug #與build類似,但是會(huì)生成調(diào)試信息,如果你想使用gdb等工具調(diào)試,那么必須使用此選項(xiàng);
task clean #清除所有由build帶來的文件
task runing #一共分兩步,首先build ,其次調(diào)用其可執(zhí)行文件;

---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
** 6 DEBUG 選項(xiàng)**
vscode Debug使用的是mingw32中的gdb.exe調(diào)試,與平常的斷點(diǎn)調(diào)試并無太大差異;
具體使用方法如下:點(diǎn)擊左側(cè)導(dǎo)航鍵 蟲子的圖標(biāo),選擇(gdb)啟動(dòng),點(diǎn)擊右方綠色的開始圖標(biāo),vscode會(huì)自動(dòng)開始編譯,運(yùn)行到斷點(diǎn)處會(huì)自動(dòng)停止,更多設(shè)置請參考上文launch.json中的注釋

---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
4.原理分析
整個(gè)環(huán)境搭建最主要的工作在于:**mingw32-make.exe** 中,實(shí)際上,如果你安裝了git ,并按照上述方式修改了默認(rèn)的終端為 gitbash,那么你只需要在終端中輸入 mingw32-make.exe target=a.exe ,也會(huì)自動(dòng)生成一個(gè)a.exe的可執(zhí)行文件,在終端輸入mingw32-make.exe clean target=a.exe,也可以清除所有由build帶來的所有新建的中間依賴文件;task.json的作用就在于 當(dāng)我 輸入 task build 時(shí) ,就相當(dāng)于我在gitbash中輸入了mingw32-make.exe target=DirName.exe 這個(gè)命令;
接下來我們會(huì)分析為什么mingw32-make.exe 可以做到這些,如果你仔細(xì)觀察我們的文件樹,你會(huì)發(fā)現(xiàn)文件樹中有一個(gè)沒有后綴的文件叫 makefile,我們可以打開makefile 文件,
#此項(xiàng)目源文件后綴類型
PROJECTTYPE = .c
#您想要生成可執(zhí)行文件的名字 如果外部沒有賦值,那么使用obj.out
target ?= obj.out
#是否生成DEBUG選項(xiàng)
DEBUG ?=#系統(tǒng)之外的宏定義
PREDEF ?=#獲取當(dāng)前makefile絕對路徑
pes_parent_dir:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))////#刪除路徑下最后一個(gè) / pes_parent_dir:=$(subst /////,,$(pes_parent_dir))#獲得mkfile 的實(shí)際路徑 測試使用, 沒有實(shí)際用到 可刪除
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)))
#設(shè)置*.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))
#需要用到的第三方靜態(tài)庫
StaticLib :=
#需要用到的第三方動(dòng)態(tài)鏈接庫
DynamicLib :=
#真實(shí)二進(jìn)制文件輸出路徑
Bin :=$(pes_parent_dir)/$(target)
#C語言編譯器
CC = gcc
#C++編譯器
CXX = g++
#簡化rm -f
RM = rm -f
#C語言配置參數(shù)
CFLAGS = -g -pedantic -std=c11 -Wall -o
#C++配置參數(shù)
CXXFLAGS = -g -Wall -std=c11
#頭文件搜索路徑
INCLUDE_PATH = $(foreach n,$(AllDirs) , -I$(n))
LDFLAGS =
#指定AllLibs為終極目標(biāo) 即:最新的Bin
AllLibs:$(Bin)
#聲明這個(gè)標(biāo)簽 des 用于觀察當(dāng)前的路徑是否正確
.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)
#對應(yīng)關(guān)系 在本makefile中以空格隔開的后綴為.c 都會(huì)為其生成一個(gè)新的.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) $< > $@
#對應(yīng)關(guān)系 在本makefile中以空格隔開的后綴為.c 都會(huì)為其生成一個(gè)新的.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文件,只要里面任意有一個(gè)文件被修改,那么就會(huì)觸發(fā)此規(guī)則生成一個(gè)新的*.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 '清理可執(zhí)行文件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 中,比較關(guān)鍵的語句在于
= $(shell cd $(pes_parent_dir); -R | | ) .
···
#對應(yīng)關(guān)系 在本makefile中以空格隔開的后綴為.c 都會(huì)為其生成一個(gè)新的.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:遞歸輸入該目錄下的所有文件以及文件夾;如果是文件夾,那么就會(huì)單獨(dú)起一行然后文件夾名字前有 ‘.’ 作為標(biāo)記 后面的grep 和 awk 、gsup 都是linux下才有的命令;
同理在 下方if [ ! -d $(dir $@) ]; then mkdir -p $(dir $@); fi;所做的邏輯就是判斷當(dāng)前想要生成的.d文件的目標(biāo)文件夾在不在, 不在則創(chuàng)建它, 其中dir mkdir 都是linux中才會(huì)有的命令,當(dāng)然windows下也有與其差不多功能的命令,但是此makefile我希望在linux下也能用,這個(gè)時(shí)候怎么辦呢,這個(gè)時(shí)候就要介紹我們的 Git 了,git在windows中使用的命令行軟件 bash.exe 就把上面的命令都覆蓋到了,也就是說,如果我們使用windows 自帶的cmd.exe 或者 powerShell.exe 里面都會(huì)使得 dir mkdir 和其他命令找不到,導(dǎo)致makefile錯(cuò)誤終止;所以我們才需要安裝Git* ,所以我們才需要將Git bash 設(shè)置成為vsCode 默認(rèn)的終端;因?yàn)?strong>只有g(shù)it bash 中才可以調(diào)用上述makefile中的幾個(gè)shell命令;
還記的我們將mingw32編譯器的路徑加入到了系統(tǒng)環(huán)境變量里面去了~為什么呢?
#C語言編譯器
CC = gcc#C++編譯器
CXX = g++
因?yàn)?在makefile 的編譯器中,gcc 、g++ 只是簡單的字符,只有將gcc 、g++ 的路徑加入了環(huán)境變量,他們才能正確的被找到;
還有,如果我們想管理C++項(xiàng)目這個(gè)時(shí)候怎么辦呢~我們只需要在 makefile中將所有的 $(CC) 替換成 $(CXX) 所有 的$(CFLAG) 替換成 $(CXXFLAG) 就可以了哦~
makefile中其他的只是我就不贅述了,你可以參考這個(gè)鏈接:一個(gè)自動(dòng)管理項(xiàng)目的makefile
最后獻(xiàn)上我整個(gè)項(xiàng)目的github地址:https://github.com/KimAlittleStar/vscode_c_demo
里面有所有的項(xiàng)目文件,以及配置文件,和較為詳細(xì)的注釋;只需要修改幾個(gè)簡單的路徑就可以完成上述的配置;我都有在json文件里面說明哦~~~
---------------------------------------------------------------------------------------華麗麗分割線---------------------------------------------------------------------------------------
如果關(guān)注度還可以的話;
我會(huì)選擇更新:
一鍵/自動(dòng)轉(zhuǎn)換 C/C++ 項(xiàng)目的makefile,
編寫一個(gè)只清楚中間文件,而不清除可執(zhí)行文件的task
搭建VSCode + 嵌入式 ARM編譯調(diào)試環(huán)境
碼字不易,覺得稍微有點(diǎn)用的,可以在git里面 star一下,博客點(diǎn)個(gè)小贊;
讀書的時(shí)候就想了2、3年的事情,現(xiàn)在終于快要看到成功了;