Skip to content

ch55xduino sdcc.sh Compilation fails on Windows 编译失败 #192

Description

@CWZ7605

English version (recommended)

Title: Compilation fails on Windows: sdcc.sh uses bash syntax but is executed by busybox ash (POSIX shell)

Environment

  • OS: Windows 10 / Windows 11
  • Board package: DeqingSun/ch55xduino (CH55xDuino)
  • Tool version: packages/CH55xDuino/tools/MCS51Tools/2026.07.10
  • Core: hardware/mcs51/0.0.26
  • Board: CH552 (any CH55x board)
  • Arduino build defines observed: Arduino IDE 2.3.10

Describe the bug

On Windows, building any sketch fails during the "Detecting libraries included by …" / "Generating function prototypes" stage. The SDCC wrapper sdcc.sh is launched through busybox ash, which is a POSIX shell and does not understand the bash-only syntax used inside the script.

Steps to reproduce

  1. Install the CH55xDuino board package on Windows.
  2. Select a board such as CH552.
  3. Compile any sketch (e.g. a bundled example, or a user sketch like Serial2USBHIDKey).
  4. The build aborts with a compilation error.

Expected behavior

The sketch should compile and link successfully.

Actual behavior

The compiler output ends with:

... \MCS51Tools\2026.07.10/win/busybox ash ...\wrapper/sdcc.sh ...\USBhandler.c nul re12 -c -Ddouble=float ... -MMD -MF ...\USBhandler.c.libsdetect.d
Error while detecting libraries included by ...\USBhandler.c
Generating function prototypes...
... \wrapper/sdcc.sh: line 94: syntax error: unexpected "(" (expecting "fi")
... \wrapper/sdcc.sh: line 94: syntax error: unexpected "(" (expecting "fi")
exit status 2
Compilation error: exit status 2

Root cause

On Windows the build recipe invokes the wrapper as:

.../win/busybox ash .../wrapper/sdcc.sh <args...>

so it is interpreted by busybox ash (the Almquist shell, POSIX-only). However sdcc.sh relies on several bashisms:

  • Array assignment FILTERED_ARGS=() and FILTERED_ARGS+=("$arg") in the re12 branch (lines 94 / 107). ash has no arrays → syntax error: unexpected "(" (expecting "fi").
  • Extended test [[ … ]] (lines 144, 153, 166, 167, 181, 194, 195, 209, 210).
  • == inside a [ … ] test (lines 16, 19); POSIX [ uses =.

On Linux/macOS the #!/bin/bash shebang is honoured so it works; on Windows the explicit busybox ash call bypasses the shebang, so it breaks. The script has therefore never compiled successfully on Windows.

Proposed fix

Make sdcc.sh POSIX sh compatible so it runs under both bash and busybox ash, without changing behavior on other platforms:

  • Replace the FILTERED_ARGS array in the re12 branch with a positional-parameter rebuild: snapshot "$@" into a newline-joined string, filter it with set -f + IFS set to newline, then rebuild $@ via set --. The re12 branch must still drop -c, -MMD, and -MF together with its following argument.
  • Replace every [[ … ]] with [ … ]. For the [[ $(sed --version 2>/dev/null) != *GNU* ]] glob test, use a case statement instead.
  • Change == to = inside [ … ] tests.

After these changes both busybox ash -n sdcc.sh and bash -n sdcc.sh pass, and the re12 flag-filtering behaves correctly (verified: input -c -Ddouble=float -DUSE_STDINT -MMD -MF dep.d -IC:/inc → output -Ddouble=float -DUSE_STDINT -IC:/inc).

Additional context

The re12 branch was added for Arduino CLI ≥ 1.5 library detection / prototype generation (it strips the gcc-style -MMD/-MF flags that SDCC does not handle the same way). A minimal patch that keeps the existing logic but removes the bashisms fixes the Windows failure. A working POSIX rewrite of the re12 branch looks like:

if [ "$MARK" = "re12" ]; then
    __saved=""
    __first=1
    for __arg in "$@"; do
        if [ $__first -eq 1 ]; then
            __saved="$__arg"; __first=0
        else
            __saved="$__saved
$__arg"
        fi
    done
    set --
    set -f
    __skip=0
    IFS='
'
    for __arg in $__saved; do
        if [ $__skip -eq 1 ]; then __skip=0; continue; fi
        case "$__arg" in
            -c|-MMD) continue ;;
            -MF) __skip=1; continue ;;
        esac
        set -- "$@" "$__arg"
    done
    unset IFS
    set +f
    case "$SRC" in
        *.cpp.merged) "$SDCC" "$@" -x c "$SRC" -o "$OBJ"; exit $? ;;
        *.cpp)       "$SDCC" "$@" -x c --include dummy_variable_main.h "$SRC" -o "$OBJ"; exit $? ;;
        *.c)         "$SDCC" "$@" "$SRC" -o "$OBJ"; exit $? ;;
    esac
    exit 1
fi

中文版

标题: Windows 下编译失败:sdcc.sh 使用了 bash 语法,但被 busybox ash(POSIX shell)执行

环境

  • 操作系统:Windows 10 / Windows 11
  • 板卡包:DeqingSun/ch55xduino(CH55xDuino)
  • 工具版本:packages/CH55xDuino/tools/MCS51Tools/2026.07.10
  • 核心:hardware/mcs51/0.0.26
  • 开发板:CH552(任意 CH55x 板)
  • 编译时可见的宏定义:Arduino IDE 2.3.10

问题描述

在 Windows 上,编译任意工程都会在执行「Detecting libraries included by …」/「Generating function prototypes」阶段失败。SDCC 的封装脚本 sdcc.sh 是通过 busybox ash 调用的,而 busybox ash 是 POSIX shell,不支持脚本里使用的 bash 专有语法。

复现步骤

  1. 在 Windows 上安装 CH55xDuino 板卡包。
  2. 选择 CH552 等开发板。
  3. 编译任意工程(例如自带示例,或用户工程 Serial2USBHIDKey)。
  4. 编译中断并报错。

预期行为

工程应正常编译、链接通过。

实际行为

编译器输出以如下内容结束:

... \MCS51Tools\2026.07.10/win/busybox ash ...\wrapper/sdcc.sh ...\USBhandler.c nul re12 -c -Ddouble=float ... -MMD -MF ...\USBhandler.c.libsdetect.d
Error while detecting libraries included by ...\USBhandler.c
Generating function prototypes...
... \wrapper/sdcc.sh: line 94: syntax error: unexpected "(" (expecting "fi")
... \wrapper/sdcc.sh: line 94: syntax error: unexpected "(" (expecting "fi")
exit status 2
Compilation error: exit status 2

根因

Windows 上构建命令实际是这样调用封装脚本的:

.../win/busybox ash .../wrapper/sdcc.sh <参数...>

也就是说它由 busybox ash(Almquist shell,仅 POSIX)来解释执行。但 sdcc.sh 里用了若干 bash 特性:

  • re12 分支里的数组赋值 FILTERED_ARGS=()FILTERED_ARGS+=("$arg")(第 94 / 107 行)。ash 不支持数组 → 报 syntax error: unexpected "(" (expecting "fi")
  • 扩展测试 [[ … ]](第 144、153、166、167、181、194、195、209、210 行)。
  • [ … ] 测试里用了 ==(第 16、19 行);POSIX 的 [ 应该用 =

在 Linux/macOS 上 #!/bin/bash 这行 shebang 会生效,所以能正常跑;在 Windows 上显式用 busybox ash 调用绕过了 shebang,于是整体崩溃。该脚本在 Windows 上其实从未成功编译过。

建议修复

sdcc.sh 改写为 POSIX sh 兼容,使其在 bashbusybox ash 下都能运行,且不改变其他平台的行为:

  • re12 分支里的 FILTERED_ARGS 数组改为「重建位置参数」:先把 "$@" 快照成一个以换行连接的字符串,用 set -f + 把 IFS 设为换行来遍历过滤,再用 set -- 重建 $@re12 分支仍需丢弃 -c-MMD,以及 -MF 和它后面的那个参数。
  • 把每个 [[ … ]] 替换为 [ … ]。其中 [[ $(sed --version 2>/dev/null) != *GNU* ]] 这种通配符匹配改用 case 语句实现。
  • [ … ] 测试里的 == 改为 =

修改后 busybox ash -n sdcc.shbash -n sdcc.sh 均通过,且 re12 的过滤逻辑正确(已验证:输入 -c -Ddouble=float -DUSE_STDINT -MMD -MF dep.d -IC:/inc → 输出 -Ddouble=float -DUSE_STDINT -IC:/inc)。

补充说明

re12 分支是为 Arduino CLI ≥ 1.5 的库探测/函数原型生成而加的(它去掉 SDCC 不支持的同名 gcc 风格 -MMD/-MF 参数)。只要保留原有逻辑、去掉 bash 特性,就能修复 Windows 上的失败。可用的 POSIX 版 re12 分支示例如下:

if [ "$MARK" = "re12" ]; then
    __saved=""
    __first=1
    for __arg in "$@"; do
        if [ $__first -eq 1 ]; then
            __saved="$__arg"; __first=0
        else
            __saved="$__saved
$__arg"
        fi
    done
    set --
    set -f
    __skip=0
    IFS='
'
    for __arg in $__saved; do
        if [ $__skip -eq 1 ]; then __skip=0; continue; fi
        case "$__arg" in
            -c|-MMD) continue ;;
            -MF) __skip=1; continue ;;
        esac
        set -- "$@" "$__arg"
    done
    unset IFS
    set +f
    case "$SRC" in
        *.cpp.merged) "$SDCC" "$@" -x c "$SRC" -o "$OBJ"; exit $? ;;
        *.cpp)       "$SDCC" "$@" -x c --include dummy_variable_main.h "$SRC" -o "$OBJ"; exit $? ;;
        *.c)         "$SDCC" "$@" "$SRC" -o "$OBJ"; exit $? ;;
    esac
    exit 1
fi

sdcc.sh

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions