1. 为什么要在 VSCode 里折腾 MSVC 加 EasyX 这套组合
先把场景说清楚:你手里有一台 Windows 机器,想用 C++ 写点带图形界面的小玩意儿——画个圆、贴张图、做个贪吃蛇或者扫雷,但又不想背 Visual Studio 那套庞大的 IDE 包袱,只想在 VSCode 里敲代码、按个快捷键就编译运行。这时候 MSVC 加 EasyX 就是一条很顺的路子。
MSVC 是微软自家的 C++ 编译器工具链,Windows 上原生支持最好,和系统库、图形库的兼容性也最稳。EasyX 则是一个面向 C++ 初学者的图形库,封装了 Windows 底层的 GDI 绘图接口,把initgraph、circle、line、getimage这些函数做得跟当年 Turbo C 的 graphics.h 很像,上手门槛极低。两者搭配,等于用最省心的编译器去驱动一个最省心的图形库。
那为什么不用 Visual Studio 而要塞进 VSCode?原因很现实:VSCode 轻、启动快、插件生态灵活,写代码的体验对很多人来说更舒服。但代价就是——编译环境、头文件路径、库链接这些原本 VS 帮你自动搞定的东西,现在得自己配。这篇就是把这套配置从头到尾捋一遍,包括我踩过的坑。
适合谁看:有一点 C++ 基础、装过 VSCode、但被“找不到 windows.h”“无法解析的外部符号”这类报错卡住的人。如果你完全没碰过命令行编译,也别慌,我会把每一步为什么这么做讲清楚,照着抄作业就行。
需要提前说明的是,下面涉及的路径、版本号都是示例,你机器上的实际路径可能不同,重点是理解每个配置项在干什么,而不是死记硬背。
2. 动手前的整体思路与方案选型
2.1 三条可选路线,为什么选 MSVC 而不是 MinGW
在 Windows 上用 VSCode 写 C++,主流有三条路:一是 MSVC(微软编译器),二是 MinGW-w64(GCC 的 Windows 移植版),三是 Clang。很多人第一次配环境会选 MinGW,因为安装包小、配置看起来简单。但一旦你要用 EasyX,MinGW 这条路基本走不通——EasyX 官方只提供 MSVC 版本的库文件(.lib),没有 GCC 能用的.a格式。你硬要用 MinGW 链接 MSVC 的库,会撞上一堆 ABI 不兼容的问题,得不偿失。
所以结论很直接:要用 EasyX,就老老实实上 MSVC。这不是偏好问题,是兼容性问题。
那 MSVC 从哪来?最省事的办法是装 Visual Studio(社区版免费),但安装时只勾选“使用 C++ 的桌面开发”这一个工作负载,别全装,否则几十个 G 下去硬盘吃不消。装完之后,MSVC 编译器、Windows SDK、EasyX 需要的底层库就都齐了。你也可以只装 Build Tools for Visual Studio,体积更小,但没有 IDE 界面,对纯命令行党更友好。
2.2 VSCode 侧需要哪些插件和配置文件
VSCode 本身只是个编辑器,它不懂 C++,也不懂怎么调用 MSVC。真正干活的是三样东西:
- C/C++ 扩展:提供语法高亮、智能提示、跳转定义。微软官方那个就行。
- tasks.json:告诉 VSCode “按 Ctrl+Shift+B 时执行哪条编译命令”。
- launch.json:告诉 VSCode “按 F5 调试时怎么启动程序、怎么挂调试器”。
这三者里,tasks.json是核心,因为编译能不能过全看它。launch.json主要影响调试体验,不调试的话可以先不管。
这里有个关键认知:VSCode 调用 MSVC 的方式,本质上是先执行一个叫vcvarsall.bat的批处理脚本,这个脚本会把编译器cl.exe、链接器link.exe、以及各种头文件和库的路径临时写进当前命令行环境。只有在这个环境里,cl命令才认得出来。所以我们的tasks.json里,编译命令不能直接写cl,而要先想办法把环境准备好。
2.3 EasyX 的安装位置和版本选择
EasyX 官网下载下来是个安装程序,它会自动检测你装的 Visual Studio 版本,然后把头文件(graphics.h、easyx.h)和库文件(EasyXa.lib、EasyXw.lib)塞进对应的目录。这里有个坑:如果你装的是较新的 Visual Studio 版本,而 EasyX 安装程序版本较老,它可能识别不到,导致文件没放对地方。
我的建议是:下载最新版 EasyX,安装时如果它提示检测到多个 VS 版本,选你实际在用的那个。装完后去VS安装目录\VC\Tools\MSVC\版本号\include下看看有没有graphics.h,有就说明成功了。如果没有,就手动把 EasyX 安装目录里的include和lib文件复制过去。
提示:EasyX 分 32 位和 64 位库。默认安装可能只放了对应你 VS 默认平台的版本。如果你编译时选 x64 却链接了 32 位库,会报“模块计算机类型 x64 与目标计算机类型 x86 冲突”。后面会讲怎么处理。
3. 核心配置细节逐个拆解
3.1 找到 vcvarsall.bat 并理解它的作用
vcvarsall.bat通常在VS安装目录\VC\Auxiliary\Build\下面。它的用法是带一个参数,比如vcvarsall.bat x64表示准备 64 位编译环境,vcvarsall.bat x86表示 32 位。执行后,当前命令行窗口里cl就能用了。
你可以先手动验证一下:打开一个普通的 cmd 窗口,敲cl,大概率提示“不是内部或外部命令”。然后执行:
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 cl如果这次cl输出了版本信息,说明环境脚本没问题。注意路径里的空格,必须用引号包起来,否则 cmd 会把空格当参数分隔符。
这一步是整个配置的地基。很多人tasks.json写不对,就是因为没搞明白“编译命令必须跑在 vcvarsall 准备好的环境里”这件事。
3.2 tasks.json 的写法与参数含义
下面是一份可以直接改路径用的tasks.json。我把它放在项目的.vscode文件夹里。
{ "version": "2.0.0", "tasks": [ { "label": "build-easyx", "type": "shell", "command": "cmd", "args": [ "/c", "call \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Auxiliary\\Build\\vcvarsall.bat\" x64 && cl /EHsc /std:c++17 /I\"C:\\EasyX\\include\" \"${file}\" /link /LIBPATH:\"C:\\EasyX\\lib\\VC2015\\x64\" EasyXw.lib user32.lib gdi32.lib" ], "group": { "kind": "build", "isDefault": true }, "problemMatcher": ["$msCompile"] } ] }逐段解释:
"command": "cmd"加"/c":表示用 cmd 执行后面那串命令,执行完就退出。call vcvarsall.bat x64:准备 64 位环境。call不能省,否则批处理执行完会直接结束当前 shell,后面的cl就没机会跑了。&&:前一条命令成功才执行后一条。cl /EHsc /std:c++17:/EHsc启用标准 C++ 异常处理,EasyX 内部和很多 C++ 代码都需要;/std:c++17指定语言标准,你也可以换成c++14或c++20,看代码需求。/I"路径":添加头文件搜索路径。如果你已经把 EasyX 头文件复制进 MSVC 的 include 目录,这个可以省。"${file}":当前打开的源文件。VSCode 会把它替换成实际路径。/link:后面跟的是链接器参数。/LIBPATH:"路径":添加库文件搜索路径。EasyXw.lib:EasyX 的宽字符版本库。如果你代码里用的是多字节字符集,就换成EasyXa.lib。一般新代码建议用宽字符版。user32.lib gdi32.lib:EasyX 底层依赖的 Windows 系统库,必须显式链接,否则会报一堆“无法解析的外部符号”。
注意:路径里的反斜杠在 JSON 里要写成双反斜杠
\\,这是 JSON 转义规则,不是 Windows 的问题。写错了 VSCode 会提示 JSON 格式错误。
3.3 launch.json 与调试配置
如果你要按 F5 调试,launch.json也得配。核心是告诉调试器可执行文件在哪、用什么调试器。
{ "version": "0.2.0", "configurations": [ { "name": "Debug EasyX", "type": "cppvsdbg", "request": "launch", "program": "${fileDirname}\\${fileBasenameNoExtension}.exe", "args": [], "stopAtEntry": false, "cwd": "${fileDirname}", "environment": [], "console": "externalTerminal", "preLaunchTask": "build-easyx" } ] }关键点:
"type": "cppvsdbg":这是 MSVC 专用的调试器类型,别写成cppdbg(那是给 GCC 用的)。"program":指向编译出来的 exe。默认cl会把 exe 生成在当前工作目录,也就是源文件旁边。"preLaunchTask":必须和tasks.json里的label一致,这样按 F5 时会先编译再调试。"console": "externalTerminal":EasyX 是图形程序,用外部终端窗口更稳,避免 VSCode 内置终端偶尔的显示问题。
3.4 字符集与运行库的坑
EasyX 有EasyXa.lib(多字节)和EasyXw.lib(宽字符)两个版本。你链接哪个,代码里就得对应设置字符集。如果你链接了EasyXw.lib,但代码里initgraph传的是char*字符串,可能编译能过但运行时乱码。
最省事的做法:在代码开头加#include <graphics.h>之前,确保项目字符集设置和库匹配。用cl命令行编译时,默认是多字节字符集。如果你想用宽字符,加/DUNICODE /D_UNICODE编译选项。
运行库方面,/MD(动态链接 CRT)和/MT(静态链接 CRT)会影响 exe 能否在没有 VC 运行库的机器上跑。自己练习用/MD就行,要发给别人用考虑/MT。EasyX 官方库通常是按/MD编译的,混用/MT可能报链接错误。
4. 完整实操流程与现场记录
4.1 环境准备清单
动手前确认这几样都到位:
| 项目 | 检查方式 | 常见问题 |
|---|---|---|
| Visual Studio 或 Build Tools | 开始菜单能搜到,或vcvarsall.bat存在 | 没勾选 C++ 工作负载 |
| EasyX 已安装 | MSVC include 目录下有graphics.h | 安装程序没识别到 VS 版本 |
| VSCode 已装 C/C++ 扩展 | 扩展面板搜索能看到已安装 | 装了但没启用 |
项目文件夹有.vscode目录 | 文件资源管理器能看到 | 手动新建即可 |
4.2 从零写一个测试程序
新建一个test.cpp,写一段最简单的 EasyX 代码:
#include <graphics.h> #include <conio.h> int main() { initgraph(640, 480); setbkcolor(WHITE); cleardevice(); setlinecolor(RED); circle(320, 240, 100); setfillcolor(GREEN); fillcircle(320, 240, 50); _getch(); closegraph(); return 0; }这段代码做了几件事:创建 640x480 的窗口,背景刷白,画一个红色空心圆,再画一个绿色实心圆,按任意键关闭。_getch()来自conio.h,作用是让窗口停住,不然程序一闪就没了。
4.3 编译运行与观察输出
按Ctrl+Shift+B触发编译。如果配置正确,VSCode 终端会输出类似:
test.cpp 正在生成代码... 已生成代码...然后目录下出现test.exe。双击它,或者按 F5 调试,应该能看到一个白底窗口,中间有红圈和绿圆。
如果报错,别急,下一节专门讲排查。这里先记一个观察点:编译成功的标志是生成了.exe和.obj文件。如果只有.obj没有.exe,说明编译过了但链接失败,问题多半在库路径或库名上。
4.4 参数调整的实际案例
假设你想把窗口改成 800x600,并且用宽字符库。改动如下:
代码里initgraph(800, 600);。tasks.json里把EasyXw.lib保持不动(本来就是宽字符版),但如果你之前用的是EasyXa.lib,现在要换成EasyXw.lib。同时确认编译选项里没有强制多字节的设置。
再假设你要用 32 位编译(有些老库只支持 32 位)。把vcvarsall.bat x64改成x86,库路径里的x64改成x86。这两处必须同时改,只改一处会报平台冲突。
我实测下来,64 位环境下 EasyX 工作正常,除非你有特殊的 32 位依赖,否则建议直接用 x64。
5. 常见报错与排查技巧实录
5.1 找不到 graphics.h
报错原文通常是fatal error C1083: 无法打开包括文件: "graphics.h"。原因就两种:EasyX 没装好,或者头文件路径没告诉编译器。
排查顺序:先去 MSVC 的 include 目录看有没有graphics.h。有的话,说明是tasks.json里/I路径写错了或者没写。没有的话,重新装 EasyX,或者手动复制。
手动复制时注意,EasyX 安装目录下通常有include和lib两个文件夹,把include里的文件复制到 MSVC 的include,lib里的对应版本复制到 MSVC 的lib\x64或lib\x86。
5.2 无法解析的外部符号
这是链接阶段的经典错误,形如error LNK2019: 无法解析的外部符号 _initgraph。意思是编译器找到了函数声明(头文件),但链接器找不到函数实现(库文件)。
三个检查点:
EasyXw.lib或EasyXa.lib有没有写进链接参数。/LIBPATH指向的目录里是否真的有这个 lib 文件。user32.lib和gdi32.lib有没有漏。EasyX 内部调用了大量 Windows GDI 函数,这两个系统库必须显式链接。
提示:如果你用的是
EasyXw.lib却报_initgraph找不到,试试换成EasyXa.lib,或者反过来。字符集不匹配时,函数名修饰会不同,导致链接器找不到。
5.3 模块计算机类型冲突
报错原文类似模块计算机类型“x64”与目标计算机类型“x86”冲突。这是 32 位和 64 位混用导致的。
vcvarsall.bat的参数决定了编译目标平台,/LIBPATH里的库也分平台。两者必须一致。你用了x64环境,就得链接x64目录下的库;用了x86环境,就链接x86目录下的库。
EasyX 安装后,lib 目录下一般有VC2015\x64和VC2015\x86这样的子目录,看清楚再写路径。
5.4 程序闪退
编译链接都过了,双击 exe 窗口一闪就没了。这是因为程序执行完main就退出了,图形窗口还没来得及看。
解决办法就是在closegraph()之前加_getch()或system("pause")。_getch()更好,因为它不依赖系统命令,也不会在窗口里打印“请按任意键继续”。
5.5 常见问题速查表
| 报错关键词 | 大概率原因 | 解决方向 |
|---|---|---|
| C1083 无法打开包括文件 | 头文件路径缺失 | 检查/I或复制头文件 |
| LNK2019 无法解析的外部符号 | 库未链接或库名错 | 检查 lib 名和 LIBPATH |
| LNK1112 模块计算机类型冲突 | 32/64 位混用 | 统一 vcvarsall 和 lib 平台 |
| 程序闪退 | 缺少暂停 | 加_getch() |
| cl 不是内部或外部命令 | 没跑 vcvarsall | 检查 call 语句 |
| JSON 解析错误 | 反斜杠没转义 | 路径用\\ |
5.6 几个我踩过的坑
第一个坑:vcvarsall.bat的路径里有空格,我一开始没加引号,结果 cmd 把C:\Program当成一个参数,直接报错。后来所有带空格的路径我都老老实实加引号。
第二个坑:tasks.json里我一开始把command写成cl,想着 VSCode 会自己找。结果它找不到,因为 VSCode 启动的 shell 环境里根本没有 MSVC 的路径。必须通过cmd /c call vcvarsall.bat这种方式把环境带进来。
第三个坑:EasyX 安装程序默认装的是 32 位库,我编译时选了 x64,链接阶段报平台冲突。后来去 lib 目录一看,x64 文件夹是空的。重新运行 EasyX 安装程序,手动指定了 x64 库的复制,才解决。
第四个坑:代码里用了initgraph但没包含graphics.h,只包含了easyx.h。虽然easyx.h里可能间接包含,但保险起见,直接#include <graphics.h>最稳。
6. 进阶玩法与后续扩展方向
6.1 用 Makefile 或 CMake 管理多文件项目
单文件用tasks.json里的${file}就够了。但项目一旦有多个.cpp,就得把所有源文件都传给cl。这时候可以写个简单的 Makefile,或者上 CMake。
CMake 的好处是跨平台,而且 VSCode 有 CMake Tools 扩展,配置起来比手写tasks.json更清晰。不过 EasyX 本身是 Windows 专属,跨平台意义不大,所以用 Makefile 也完全够。
一个最简 Makefile 大概长这样:
CXX = cl CXXFLAGS = /EHsc /std:c++17 /I"C:\EasyX\include" LDFLAGS = /link /LIBPATH:"C:\EasyX\lib\VC2015\x64" EasyXw.lib user32.lib gdi32.lib all: game.exe game.exe: main.obj utils.obj $(CXX) $(CXXFLAGS) main.obj utils.obj $(LDFLAGS) /OUT:game.exe main.obj: main.cpp $(CXX) $(CXXFLAGS) /c main.cpp utils.obj: utils.cpp $(CXX) $(CXXFLAGS) /c utils.cpp clean: del *.obj *.exe注意 Makefile 里的命令必须在 vcvarsall 环境里执行,所以你还是得先开一个配好环境的终端,或者用 VSCode 的 task 包一层。
6.2 双缓冲与画面闪烁处理
EasyX 默认直接往窗口上画,复杂动画会闪。解决办法是用双缓冲:先画到内存 DC,再一次性贴到屏幕。
EasyX 提供了BeginBatchDraw()和FlushBatchDraw()这对函数,用法很简单:
BeginBatchDraw(); // 所有绘图操作 FlushBatchDraw();把绘图代码夹在中间,就能明显减少闪烁。这个技巧在做游戏循环时几乎是必用的。
6.3 资源文件与图片加载
EasyX 支持加载图片,用loadimage函数。但图片路径是相对当前工作目录的,调试时工作目录可能是项目根目录,也可能是 exe 所在目录,容易搞混。
稳妥做法是用绝对路径,或者用GetModuleFileName获取 exe 路径再拼接。另外,图片格式支持有限,bmp 最稳,jpg 和 png 需要额外配置。
6.4 把配置固化下来方便复用
每次新建项目都复制一遍.vscode配置很烦。我的做法是建一个模板文件夹,里面放好tasks.json、launch.json和一个空的main.cpp。新项目直接复制这个文件夹,改改名字就能用。
更进一步,可以把vcvarsall.bat的路径写成一个环境变量,tasks.json里引用这个变量。这样换机器时只改变量,不用改配置文件。VSCode 的tasks.json支持${env:VAR_NAME}这种写法。
7. 一些个人体会
这套配置我前后折腾过好几台机器,每次重装环境都会重新踩一遍坑。最大的感受是:MSVC 加 EasyX 的难点不在代码,而在环境路径。代码写错了编译器会告诉你哪一行,但路径配错了,报错信息往往很含糊,得靠经验去猜。
另一个体会是,tasks.json里的命令最好先在普通 cmd 里手动跑通,再搬进 VSCode。因为 VSCode 的终端输出有时候会吞掉一些信息,手动跑能看到完整的报错。我现在的习惯是,任何编译命令先在 cmd 里验证,确认没问题了再写进配置文件。
最后说个小事:EasyX 的官方文档虽然不算特别详细,但示例代码质量不错,遇到不会的函数直接翻安装目录里的示例,比在网上搜半天强。图形编程这东西,看一百遍不如自己画一个圆出来。