1. 从Linux到Windows一场CMake的“水土不服”如果你和我一样是个喜欢在Windows上捣鼓嵌入式开发的玩家那你肯定也遇到过这种头疼事一个在Linux上跑得好好的开源项目比如我们今天要聊的pico-doom一搬到Windows上编译就各种报错简直像换了水土一样。这个项目原本是让Raspberry Pi Pico驱动VGA显示器来运行经典游戏DOOM的原作者在Linux环境下搭建得顺风顺水但代码包一解压到Windows的盘符下CMake就开始“闹脾气”了。这太常见了。很多优秀的开源项目尤其是围绕树莓派Pico生态的开发者主力环境往往是Linux或macOS。他们写的CMakeLists.txt脚本在Unix-like系统上路径分隔符是正斜杠/环境变量设置也有一套习惯。但到了Windows上路径是反斜杠\编译器工具链是MSYS2或MinGWCMake的某些预设行为也不同。这就导致了直接克隆代码后你运行cmake ..大概率会收获一屏幕红色的错误信息从找不到PICO_SDK_PATH到链接时缺库五花八门。我这次的目标很明确在Windows 11系统上使用Visual Studio Code配合CMake Tools插件把pico-doom项目成功编译生成能烧录到Pico板子里的UF2文件并且让它在我的ILI9341 SPI液晶屏上正常显示。听起来简单但整个过程就像在解一个由路径、依赖和版本号组成的谜题。最关键的一把钥匙就是正确修改那几个CMakeLists.txt文件。别怕跟着我一步步来我把踩过的坑和填坑的方法都详细告诉你。我们不用最新版的Pico SDK就用1.5.1这个特定版本这是项目兼容性的“甜蜜点”也是解决问题的关键第一步。2. 环境准备与SDK的“锁定”动手之前得把“战场”布置好。在嵌入式开发里工具链和SDK的版本匹配是头等大事一步错后面全是坑。2.1 工具链安装稳字当头首先确保你的Windows电脑上已经安装了以下三样东西并且我都推荐使用比较“经典”或“稳定”的版本别追求最新Visual Studio Code这个没啥好说的轻量级代码编辑器的事实标准。安装好后务必装上“CMake Tools”和“C/C”这两个扩展。它们是后续配置和编译的指挥中心。ARM GCC工具链Pico的芯片是ARM Cortex-M0需要专门的编译器。去ARM官网下载“GNU Arm Embedded Toolchain”版本选择10.x或11.x的稳定版即可。下载后安装记住安装路径比如我的是D:\ArmGCC\10 2021.10\bin。然后把这个路径添加到系统的PATH环境变量里。打开命令行输入arm-none-eabi-gcc --version能显示出版本信息就对了。CMake同样去官网下载安装包版本选择3.20以上即可。安装时记得勾选“Add CMake to the system PATH”选项方便在任意地方使用。2.2 获取并“锁定”Pico SDK 1.5.1这是最核心、最容易出错的一步。原始文章里也强调了这个pico-doom项目“只能用pico-sdk-1.5.1不能用最新版的”。这不是危言耸听很多开源项目对SDK的特定版本有依赖尤其是涉及底层硬件驱动和音频、显示库的时候。为什么不能用新版因为Pico SDK的API和库结构在不同版本间可能会有变动。比如某个函数在1.5.1里是function_a()到了2.0.0可能改名叫function_a_ex()了或者所需的头文件路径变了。项目作者是基于某个特定版本开发的如果你用了更新的SDK编译时就会找不到符号或者链接失败。所以我们不要用git clone最新的master分支。正确的方法是去树莓派官方的GitHub仓库https://github.com/raspberrypi/pico-sdk找到1.5.1这个tag直接下载它的ZIP压缩包。同样对于pico-extras这个包含额外驱动比如我们需要的LCD驱动的扩展库也去它的仓库找到对应1.5.1版本的tag下载ZIP包。下载后把它们解压到一个没有中文和空格的路径下。我强烈建议你像我一样建一个专门的目录来管理比如D:/Dev/RP2040/ ├── pico-sdk-1.5.1/ (解压后的pico-sdk) └── pico-extras-1.5.1/ (解压后的pico-extras)记住这个路径下一步修改CMakeLists.txt时就要用到了。这里有个Windows下的重要习惯在CMake脚本里即使你在Windows下路径也要用正斜杠/或者使用双反斜杠\\。直接使用单反斜杠\会被CMake解释为转义字符导致路径解析错误。所以我们的路径会写成D:/Dev/RP2040/pico-sdk-1.5.1这种形式。3. 庖丁解牛逐层修改CMakeLists.txt现在进入实战环节。我们拿到pico-doom的源代码后会发现里面有好几个CMakeLists.txt文件它们像一套组合拳层层递进地定义了整个项目的构建规则。我们的任务就是调整这套拳法让它适应Windows和SDK 1.5.1这个新擂台。3.1 根目录CMakeLists.txt设定全局擂台首先打开项目根目录下的CMakeLists.txt。这个文件是构建的起点它要告诉CMake去哪找SDK、用什么编译模式、有哪些子目录要参与构建。你会看到原文件里可能有一些针对Linux的设定或者已经失效的变量。我们需要在文件靠前的位置通常在project()命令之后添加或修改以下几行关键内容# 设置Pico SDK的路径指向你刚刚解压的1.5.1版本目录 set(PICO_SDK_PATH D:/Dev/RP2040/pico-sdk-1.5.1) # 设置Pico Extras的路径 set(PICO_EXTRAS_PATH D:/Dev/RP2040/pico-extras-1.5.1) # 设置默认的构建类型为最小体积发布模式这对单片机很友好 set(CMAKE_BUILD_TYPE MinSizeRel) # 引入Pico SDK的构建系统 include(${PICO_SDK_PATH}/external/pico_sdk_import.cmake)这里set(CMAKE_BUILD_TYPE MinSizeRel)这一行非常实用。MinSizeRel是CMake的一种构建类型它会开启编译器优化如-Os旨在最小化生成的可执行文件体积。对于Pico这种Flash空间只有2MB的微控制器能省一点是一点。当然如果你在调试阶段可以改成Debug但最终烧录时建议换回MinSizeRel。3.2 src目录下的CMakeLists.txt精简目标接下来打开src/目录下的CMakeLists.txt。原始项目可能为了适配多种配置比如VGA输出、LCD输出定义了多个构建目标target。但在我们移植到特定LCD屏幕的场景下很多目标是多余的甚至会引起冲突。你的任务就是“做减法”。找到定义可执行文件add_executable或者添加子目录add_subdirectory的地方。根据原始文章的提示我们需要删除其他无关的目标只保留一个核心目标很可能叫做doom_tiny。修改后的效果应该是这个文件里只清晰地定义或引入了doom_tiny这一个我们要构建的程序。例如你可能需要把类似下面的段落add_executable(doom_vga ...) add_executable(doom_lcd ...) add_executable(doom_tiny ...)精简为只保留add_executable(doom_tiny ...)或者确保add_subdirectory只引向包含doom_tiny的目录。这一步的目的是让构建系统集中火力只编译我们需要的那个版本避免目标混乱导致的链接错误。3.3 src/pico目录下的CMakeLists.txt驱动替换与链接修补这是修改的重中之重也是问题最集中的地方。src/pico/这个目录下的代码和配置是直接和Pico硬件以及外设屏幕、音频打交道的。首先屏幕驱动的替换。原项目可能默认配置了ST7789驱动的LCD但你的屏幕可能是ILI9341这在SPI屏中很常见。你需要找到定义LCD驱动的地方通常是一行#define或者CMake的变量设置。把它从ST7789改为ILI9341。在CMakeLists.txt里这可能体现为链接不同的库文件。比如把链接pico_st7789库的语句换成链接pico_ili9341具体库名需根据pico-extras中的命名来定。有时候你还需要在同一个目录下的config.h或magic.h对就是这个名字后面会提到头文件里做相应的宏定义切换。其次音频库的链接。这是原始文章作者踩过的一个大坑也是我花了很长时间才排查到的问题缺失pico_audio_i2s库的链接。项目代码里明明调用了I2S音频相关的函数但在CMakeLists.txt里却没有告诉链接器需要这个库。这就好比你的程序说要使用一个工具箱里的特定扳手却没告诉仓库管理员把这个扳手放进配送清单最后组装时当然找不到工具。你需要在src/pico/CMakeLists.txt中找到target_link_libraries命令它负责告诉链接器你的可执行文件需要哪些库。在链接列表里明确加上pico_audio_i2s。修改后可能看起来像这样target_link_libraries(doom_tiny pico_stdlib hardware_i2c hardware_pwm pico_ili9341 # 替换后的屏幕驱动库 pico_audio_i2s # 手动添加这行解决链接错误 # ... 其他库 )添加这一行后之前可能遇到的“undefined reference toaudio_i2s_*”这类链接错误就会消失。这种问题非常隐蔽因为编译检查语法能过链接组装所有部件时才报错需要仔细对照SDK中的示例查看函数到底来自哪个库。4. 配置、编译与颜色校正所有的CMakeLists.txt文件都修改妥当后就可以启动构建流程了。我强烈推荐在VSCode里操作因为CMake Tools扩展让这个过程可视化了很多。4.1 在VSCode中配置与编译用VSCode打开pico-doom项目的根目录。按下CtrlShiftP打开命令面板输入“CMake: Configure”并执行。这时CMake Tools会读取我们修改过的CMakeLists.txt生成适用于你当前系统的构建文件在Windows下通常是Makefile或Ninja文件以及VS Code的settings.json配置。状态栏下方应该会显示“Configuring done”之类的成功信息。如果失败请仔细检查上面的路径设置和语法错误输出窗口会有详细提示。配置成功后再次按CtrlShiftP输入“CMake: Build”并执行。或者直接点击状态栏的“Build”按钮。CMake就会调用编译器我们之前安装的ARM GCC开始编译整个项目。如果一切顺利你会在输出窗口看到编译进度最终出现“Build finished with exit code 0”的成功提示。生成的UF2文件通常位于build目录下的某个子文件夹里名字就是doom_tiny.uf2。把这个文件拖拽到你的Pico板子需进入USB大容量存储模式它就变身为一台迷你DOOM游戏机了4.2 解决颜色显示异常修改magic.h但是先别高兴太早。当你满怀期待地给屏幕上电可能发现游戏虽然能跑但颜色完全不对——画面发紫、发绿像是蒙上了一层诡异的滤镜。这不是硬件问题而是一个经典的颜色格式Color Format问题。DOOM游戏内部使用一种特定的调色板而不同的LCD驱动芯片ILI9341, ST7789等期望接收的像素数据格式可能不同。常见的有RGB565、BGR565等。如果发送和接收的格式不匹配颜色通道就错位了红色显示成蓝色绿色显示成红色。原始文章里提到了一个关键文件src/pico/magic.h。这个文件名听起来就很“魔法”它通常包含了一些硬件相关的底层配置和颜色转换宏。你需要打开这个文件找到负责颜色格式定义的部分。根据文章线索通常需要注释掉原来的某一行比如第45行然后将另一行正确的格式定义比如第50行复制到合适的位置比如第46行。具体行号可能因版本而异但你要找的关键词是颜色顺序比如RGB565、BGR565、SWAP_COLOR_ENDIAN之类的宏定义或函数。你需要将颜色输出格式调整为你的ILI9341屏幕所支持的格式。如果不确定可以查阅你的屏幕规格书或者参考pico-extras中ILI9341驱动示例所用的格式。修改并保存这个头文件后必须重新执行一次CMake Build因为头文件的修改会影响所有包含它的源文件。重新编译生成新的UF2文件再次烧录绚丽的或者说至少颜色正常的地狱之火就应该在你的小屏幕上燃烧起来了。5. 常见编译错误与深度排查指南即使按照上述步骤操作你可能还是会遇到一些编译错误。别慌这是移植工作的常态。下面我列举几个我遇到过的典型错误和排查思路。5.1 “找不到PICO_SDK_PATH”或“Could NOT find PicoSDK”这是最经典的错误。说明CMake在第一步就卡住了。检查路径回头仔细检查根目录CMakeLists.txt里set(PICO_SDK_PATH ...)这一行。路径是否完全正确末尾有没有多余的空格或字符确保路径指向的文件夹里确实有pico_sdk_import.cmake这个文件。检查斜杠再次确认路径使用的是正斜杠/或双反斜杠\\。重新配置在VSCode里尝试运行“CMake: Delete Cache and Reconfigure”。有时候CMake会缓存旧的、错误的路径信息。5.2 “undefined reference to ...” 链接错误这种错误发生在编译成功、链接阶段失败的时候。它告诉你“我知道你要调用某个函数但我找不到这个函数具体在哪个库文件里。”检查库链接百分之九十的原因就是target_link_libraries里漏了库。对照错误信息里缺失的函数名去Pico SDK或pico-extras的文档、头文件里搜一下看这个函数属于哪个库。比如之前提到的audio_i2s_开头的函数就在pico_audio_i2s库里。检查库顺序理论上现代链接器不关心顺序但有时依赖关系复杂时确保被依赖的库放在依赖它的库之后可能有助于解决问题。检查SDK版本再次确认你用的函数在你锁定的SDK 1.5.1版本中是否存在。去对应版本的SDK源码里搜一下函数定义。5.3 头文件找不到 “fatal error: xxx.h: No such file or directory”这表示编译器在预处理阶段找不到某个头文件。检查包含路径在CMakeLists.txt中确保使用了target_include_directories()命令将必要的头文件目录添加进来。Pico SDK通常通过pico_sdk_init()或链接库的方式自动添加了路径但第三方或自定义的目录可能需要手动添加。检查文件是否存在根据报错信息去磁盘上确认那个头文件是否真的在你认为的路径下。可能是文件被移动或重命名了。5.4 版本不兼容导致的语法错误或警告如果你坚持使用了非1.5.1版本的SDK可能会遇到一些API变更导致的错误。例如某个函数参数数量变了或者某个结构体成员改名了。终极方案老老实实换回SDK 1.5.1。这是与pico-doom这个代码快照最匹配的环境。折中方案如果真想用新版SDK就需要仔细对比SDK版本间的变更日志Changelog然后手动修改pico-doom的源代码适配新的API。这工作量不小但也是学习SDK演进的好机会。调试的过程就是不断缩小问题范围的过程。从CMake配置错误路径、生成器到编译错误语法、头文件再到链接错误库缺失最后到运行时错误颜色、驱动。每解决一个你就离成功更近一步。当最终看到DOOM的标题画面在你亲手移植的Pico掌机上出现时那种成就感绝对值得这一路的折腾。记住嵌入式移植没有银弹耐心和仔细查看每一行错误信息是你最好的工具。