尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CH55xDuino编译报错sdcc.sh语法错误修复指南

CH55xDuino编译报错sdcc.sh语法错误修复指南 如果你最近在 Windows 下用 Arduino IDE 折腾 CH55xDuino编译一个最简单的 Blink 却碰到sdcc.sh: syntax error: unexpected (这个报错先别慌——芯片没有坏代码也没有错问题出在工具链的调用方式上。我花了一个晚上从 Arduino 的编译日志一路追到 shell 脚本源码最后只用了三分钟就解决了问题。这篇把整个过程完整记录下来包括根因分析、三种修复方案和后续避坑清单给同样卡在这条报错上的朋友一份可以直接抄的作业。1. 报错出现时的完整环境与现象1.1 我的硬件和软件组合先交代一下背景。最近我在做一个基于 CH552 的小型 USB 设备看中的是 CH55x 系列极低的单价和内置 USB 控制器。CH552 是一颗 8051 内核的 MCU官方叫法是增强型 E8051 内核主频可以到 24MHz 左右片上带 USB、ADC、PWM、串口这些外设做 HID 键盘鼠标、小传感器采集板都非常合适。想在 Arduino 生态里玩它就需要装 CH55xDuino 这个第三方开发板支持包。我的电脑环境是 Windows 10 专业版Arduino IDE 版本是 1.8.19。我在开发板管理器里添加了 CH55xDuino 的官方 JSON 源搜索 ch55xduino 后安装了最新版。安装完成后在工具 - 开发板 - CH55xDuino 分类下能看到 CH551、CH552、CH553、CH554、CH555 等型号可选。我手头的板子是 CH552 最小系统板12MHz 晶振板载 USB 口没有额外接串口芯片走的是芯片自带的 USB bootloader 下载。这里有个细节提醒一下CH55xDuino 在 Windows 上安装时会自动下载对应的工具链包括 SDCC 编译器。正常情况下编译流程应该走sdcc.exe但如果你和我一样在编译输出里看到的是sdcc.sh就说明工具链的调用路径已经和 Windows 系统不匹配了这也是后面一切问题的根源。1.2 原封不动的报错信息我当时的操作非常常规打开示例代码选择开发板点击上传。结果编译刚开始就中断Arduino IDE 下方输出窗口变成一片红色。完整报错大概是这样的C:\Users\me\AppData\Local\Arduino15\packages\ch55xduino\tools\sdcc\4.0.0\bin\sdcc.sh -c -g -o build/... syntax error: unexpected ( Error compiling for board CH55xDuino (CH552).我一开始以为是自己工程代码里写了什么不合法的东西但仔细一看报错位置在编译非常靠前的阶段还没到真正编译 C 文件那一步。这基本可以断定问题不是出在.ino代码里而是出在“启动编译器”这个环节。如果你勾选了 Arduino IDE 首选项里的“显示详细输出”中的“编译”你会看到 Arduino 试图执行的第一个程序就是这个sdcc.sh。一个.sh文件出现在 Windows 的编译命令里本身就是最大的线索。Windows 系统并没有原生 bash 环境一个 shell 脚本被强行当成可执行程序去跑结果自然是语法错误。接下来要做的就是把这条命令拆开看看它到底调用了什么、用什么解释器执行。2. sdcc.sh 为什么成了编译链路上的关键节点2.1 CH55xDuino 的编译器与常见的 AVR 项目有何不同在 Arduino 生态里不同开发板背后的编译器完全不同。玩 UNO 的人熟悉 avr-gcc玩 ESP32 的人用的是 xtensa-esp32-elf-gcc而 CH55xDuino 用的是 SDCC全称是 Small Device C Compiler。SDCC 是一款开源 C 编译器支持 8051、STM8、Z80 等多个架构CH55x 的 8051 内核正好被它支持。为什么 CH55xDuino 不直接用 avr-gcc因为 CH55x 是 8051 架构AVR 编译器生成的二进制根本跑不起来。8051 的内存模型、寄存器、位操作、中断向量处理和 AVR 差异非常大必须用专门的编译器。SDCC 能处理 MCS-51 系列的一些特殊扩展比如 data 指针、code 空间、bit 变量的定位这些是普通桌面编译器完全不具备的。对从 ESP32 或者 UNO 转过来的用户来说这里的第一道坎是以前玩 Arduino 时可能完全没有手动配过编译器开发板管理器装好就能用。但 CH55xDuino 在某些版本里并不是完全自包含的它需要 SDCC而 SDCC 在 Windows 上的安装方式又不止一种。于是各种路径问题、工具链选择问题就冒出来了。这次遇到的sdcc.sh报错本质上就是工具链“没有按 Windows 的方式工作”。2.2 sdcc.sh 到底在编译流程里做了什么为了搞清楚sdcc.sh的职责我在打开详细编译日志后直接打开文件管理器找到报错路径下的脚本文件。这个脚本通常位于 Arduino15 数据目录下AppData\Local\Arduino15\packages\ch55xduino\tools\sdcc\版本号\bin\sdcc.sh。打开脚本后它做的事情可以归纳成三类第一是环境检测判断当前操作系统、找到 SDCC 可执行文件的位置必要时设置临时变量第二是参数解析把 Arduino 编译器 recipe 传进来的一长串参数拆开、重组补上 SDCC 所需的芯片型号、内存模型等选项第三是真正执行 sdcc把重组后的参数交给sdcc可执行文件再把退出码原样返回给上层。也就是说sdcc.sh是一个兼容层。Linux 和 macOS 上它工作得很好因为系统自带 bash脚本开头的#!/bin/bashshebang 直接生效。Windows 上麻烦在于系统不认 shebangArduino IDE 内部环境里有哪个 bash、会不会用 bash取决于安装包怎么规定。一旦脚本落到一个不支持 bash 扩展语法的解释器手里就会在解析阶段直接死亡。当时我打开脚本看到里面有类似这样的写法function run_sdcc() { local args() for arg in $; do args($arg) done exec sdcc ${args[]} }这种写法在 bash 里完全没问题但换成 dash第一行的function就会触发syntax error: unexpected (。这就是报错的直接触发点。3. 从报错信息反推根因一个 shell 兼容性问题3.1unexpected (在 shell 语言里意味着什么Shell 脚本的报错看起来神秘其实逻辑很简单解释器在一个它认为不可能出现(的地方遇到了(。在 bash 中(出现的合法场景包括命令替换$(...)、子 shell(...)、算术求值$((...))、函数定义foo()。但function foo()这种写法只有 bash 支持POSIX sh 并不支持。大多数 Linux 发行版虽然自带/bin/sh但它往往是指向 dash 的软链接。dash 以严格 POSIX 和快速启动为目标不支持function关键字不支持数组不支持[[ ]]等 bashism。如果一个脚本是给 bash 写的却被 dash 执行错误就会这样冒出来。Windows 上更复杂Arduino IDE 的编译器调用不是直接在 cmd 里执行的而是会经过内置的 MSYS2 或工具链自带的 shell。MSYS2 的sh默认可能就是 dash于是sdcc.sh里任何一个 bash 特有语法都会引爆。你看到syntax error: unexpected (并且报错文件是.sh那 90% 以上是 bashism 问题剩下 10% 是文件编码或行尾问题。这里要补充一个容易误判的点很多人看到 syntax error 第一反应是去查 C 语言代码或者重新安装 Arduino IDE实际上和代码一点关系都没有。Shell 脚本的语法错误和 C 语言编译错误是两套完全不同的体系。3.2 我复现错误的完整操作排错的第一步不是开 IDE 猜来猜去而是把编译命令完整抓出来。在 Arduino IDE 中文件 - 首选项 - 勾选“显示详细输出”里的“编译”。然后再编译一次输出窗口会显示实际执行的完整命令行。我把它复制出来提取出sdcc.sh的完整路径拿到 CMD 和 Git Bash 里分别执行。我的复现过程分三步在 CMD 里直接运行sdcc.sh --helpWindows 弹窗问“你想如何打开此文件”。这说明 CMD 根本没把它当可执行程序。在 Git Bash 里运行bash sdcc.sh --help脚本正常打印帮助信息。说明脚本本身没问题bash 能解析。在 Git Bash 里运行sh sdcc.sh --help复现一模一样的错误syntax error: unexpected (。三次对比做完根因基本锁定sdcc.sh的语法依赖 bash而 Arduino IDE 在 Windows 上把它交给了shdash来执行。为了进一步证实我用文本编辑器打开了sdcc.sh搜索function果然找到了类似function make_cmd()的定义。这个关键字就是 dash 的引爆点。我把function make_cmd()改成make_cmd()再用sh -n sdcc.sh做语法检查没有报错了。到这一步问题已经一清二楚。3.3 为什么只在 Windows 上炸、在 Linux/macOS 上正常这个问题可以一句话解释Windows 没有原生 bash而 CH55xDuino 的脚本假设自己会被 bash 执行。在 Linux 或 macOS 上类 Unix 系统自带/bin/bash脚本头#!/bin/bash被内核直接识别脚本能拿到正确的解释器自然不炸。Windows 没有这种机制.sh文件只是普通文本必须由调用方显式启动一个 shell 去跑。如果调用方启动的是sh而不是bash或者 bash 根本不在预期路径就会出问题。另外还有一个非常重要的诱因装错了平台包。开发板管理器安装时会根据操作系统自动选择工具链版本但如果你参考了一些老教程手动从 GitHub 下载了 release 包很可能拿到的还是 Linux 版工具链。这种包里全是.sh和 Linux 可执行文件Windows 下当然跑不通。判断方法很简单看包路径里有没有bin/sdcc.exe。如果只有.sh却没有.exe说明包类型不对重新去开发板管理器装才靠谱。4. 三种修复方案及我的实测结果4.1 方案一让 Arduino IDE 用 bash 而不是 sh 去执行脚本这个方案最快适合已经装了 Git for Windows 的朋友。Git for Windows 自带一个完整的 bash 环境路径一般在C:\Program Files\Git\bin\bash.exe。我们要做的就是让 Arduino 在调用sdcc.sh之前先启动这个 bash。具体操作是这样的打开文件资源管理器定位到C:\Users\用户名\AppData\Local\Arduino15\packages\ch55xduino\找到platform.txt。先把platform.txt复制一份到别处备份防止改坏。用 VSCode 或 Notepad 打开platform.txt查找sdcc.sh。你会看到类似这样的 recipe 行recipe.cpp.o.pattern{compiler.path}sdcc.sh {compiler.cpp.flags} {compiler.mcu.flags} {includes} {source_file} -o {object_file}改成这样recipe.cpp.o.patternC:/Program Files/Git/bin/bash.exe {compiler.path}sdcc.sh {compiler.cpp.flags} {compiler.mcu.flags} {includes} {source_file} -o {object_file}注意路径里的反斜杠。在platform.txt中反斜杠可能被当成转义字符处理所以我测试时发现更稳的写法是统一用正斜杠C:/Program Files/Git/bin/bash.exeWindows 命令行对正斜杠是接受的。保存回到 Arduino IDE 重新编译。我改完之后编译输出里不再是直接运行sdcc.sh而是先运行bash.exe再由 bash 接sdcc.sh。几分钟内Blink 就编译通过了。这个方案有个小问题platform.txt在开发板管理器更新包时会被覆盖需要重新修改。为了避免这个麻烦你可以把修改后的 recipe 写进platform.local.txt。Arduino 支持这个文件用它做 recipe 覆盖不会影响原始包文件升级时也不容易被覆盖。缺点是 recipe 参数必须和原始platform.txt完全对上否则容易出现变量未定义。我建议先复制原始行再改前头的命令路径。如果你没有 Git for Windows 但装了 WSL理论上也可以把C:\Windows\System32\wsl.exe当作 bash 调用。但测试中我发现 WSL 默认发行版的当前目录和 Arduino 环境变量不一定能正确继承路径映射很容易出问题所以不推荐用来修这个 recipe。最省事的还是 Git for Windows。4.2 方案二修改 sdcc.sh把 bash 特有语法改写成 POSIX 兼容写法如果你不想依赖 bash或者你的环境根本没有 bash可以修改sdcc.sh本身。原理很简单既然错误是由 bashism 引起的那就把 bash 特有的语法降级成 POSIX 写法。具体步骤备份sdcc.sh。用 VSCode 或 Notepad 打开右下角确认行尾是 LF编码是 UTF-8 无 BOM。搜索function关键字把所有function foo()改成foo()。如果脚本里有数组例如args($)需要改成普通字符串拼接或者用set --重新组织位置参数。这一步比较考验 shell 功底。保存后在终端执行sh -n sdcc.sh如果没有任何输出说明语法检查已经通过。再执行sh sdcc.sh验证能正常调用 sdcc。我实际操作时脚本里只有两处函数定义需要改没有用到数组所以改完立刻就能跑。但我也要提醒一句只做语法降级不要动它原有的逻辑否则 SDCC 参数可能被改坏出现更莫名其妙的编译错误。这个方案的缺点很明显开发板管理器一旦升级sdcc.sh会被新版本覆盖你又得重新改。如果你是按文档复现的还得记录自己改了哪几行。所以我把这个方案定位成临时救急用不适合当长期解法。适合的场景是手里没有 Git for Windows也不想装额外软件只求这次能编译过。4.3 方案三Windows 下改用官方 SDCC 包的 sdcc.exe绕过脚本从长期稳定角度看我更推荐第三个方案让编译命令直接调用sdcc.exe把sdcc.sh完全抛开。既然 CH55xDuino 真正需要的是 SDCC 编译器而 SDCC 在 Windows 下有官方安装包那我们完全没有必要让脚本当中间商。步骤是这样的去 SDCC 官网或 SourceForge 下载 Windows 版 SDCC 安装包。当前稳定版大约是 4.2.0和 CH55xDuino 要求的 4.0.0 能兼容。安装到一个无空格路径例如C:\sdcc。把C:\sdcc\bin加入系统 PATH或者把platform.txt里的compiler.path改为C:/sdcc/bin/。修改platform.txt中所有sdcc.sh为sdcc.exe。如果 recipe 原本写的就是{compiler.path}sdcc而没有.exe那就保持不动。重新编译。这里要注意版本匹配。CH55xDuino 的库代码是按特定 SDCC 版本测试的装太旧或太新都可能出现奇怪的编译错误。开发板管理器里记录的工具版本一般就是推荐版本手动安装时尽量选接近的版本不用刻意追新。我用这个方案验证了一个工程后编译速度和稳定性都很好。以后升级 CH55xDuino 平台包只要platform.txt里还是用sdcc.exe就不会再受 shell 兼容性影响。唯一的门槛是手动改环境变量和文件路径对刚接触 Arduino 的用户来说稍微繁琐一点。三种方案放到一起对比看你的情况选方案难度稳定性适用人群方案一bash 包装低中升级覆盖可能失效装了 Git for Windows 的用户方案二改脚本语法中低升级覆盖必失效临时救急、无 bash 环境方案三直连 sdcc.exe中高高长期使用 CH55x 的人5. 修复后的完整编译验证与后续避坑5.1 从空工程到跑通 Blink 的验证清单修复完不要马上宣布成功我习惯从空工程到烧录完整走一遍确认整个链路没问题。你可以按这个清单核对新建一个最小工程或者直接编译官方示例里的 Blink。确认工具 - 开发板 - CH55xDuino (CH552) 选中正确。点击编译等输出窗口出现Done compiling。打开生成的临时目录确认存在.hex文件且体积不是 0KB。连接 CH552 开发板。如果芯片里没有有效引导程序插电前按住 BOOT 键插上后再松开。选择上传方式。CH55x 芯片自带 USB bootloaderArduino 会在上传前自动复位进入 bootloader如果走的是串口方式需要确认端口号。等待上传成功断开并重新上电观察板载 LED 闪烁节奏是否正常。这一步最容易翻车的是第 5 步。CH55x 的内置 bootloader 只在特定条件下才允许写入一种是芯片上电时检测到下载引脚被拉低另一种是用户程序主动跳转到 bootloader。很多新手直接把板子插上就点上传结果一直超时其实就是没按下载键。我自己的板子第一次刷的时候也卡在这里按了 BOOT 键之后上传秒过。5.2 编译通过后还会遇到的三个常见坑编译通过只是第一步后续还有几个和路径、编码、工具链相关的坑一并写在这里。第一个坑路径里的空格问题。Windows 下如果用户名是中文或者带空格某些 recipe 在解析路径时会出诡异问题。我建议把 Arduino 数据目录和项目目录都放在无空格的纯英文路径下。比如把项目放在D:\ArduinoProjects\CH552_Test把 Arduino15 数据目录的环境变量也指到一个无空格路径。很多莫名其妙的file not found和unexpected token都和空格有关。第二个坑脚本编码和行尾符问题。如果你手动编辑过platform.txt或者sdcc.sh保存时务必选择 UTF-8 无 BOM 和 LF 行尾。Windows 记事本默认保存的 UTF-8 BOM 会导致脚本第一行 shebang 解析失败CRLF 会让命令末尾带上\r被错误执行。这类问题的报错经常是$\r: command not found或者奇怪的syntax error near unexpected token }。编辑工具我推荐 VSCode 或 Notepad别用系统记事本。第三个坑与其它开发板工具链的冲突。如果你同时装了 ESP32、ESP8266 或者其他依赖 SDCC 的工具链全局 PATH 里可能混入旧版 sdcc。CH55xDuino 的 recipe 如果使用了相对路径也可能被 PATH 里的错误版本截胡。我在排查时把 PATH 里所有和 sdcc 相关的临时变量清理了一遍只保留 Arduino15 包路径里那一个问题才彻底干净。这次报错排查花的时间不算长但教训挺深。以后在 Windows 下遇到任何syntax error我的第一反应就是先看报错的是哪个文件、用什么解释器执行而不是盯着代码一行行找。CH55xDuino 是个很好玩的低预算平台解决完工具链问题之后USB 外设、数据采集这些项目跑起来非常顺手。如果你也卡在sdcc.sh这条报错上试试方案一或者方案三三分钟内应该就能看到编译进度条动起来。
返回列表