@@ -60,11 +60,39 @@ def fetch-core [ version: string ] {
6060 }
6161}
6262
63+ # Patch runtime.c to guard `#include <windows.h>` behind MOONBIT_NATIVE_NO_SYS_HEADER.
64+ # The bundled TCC doesn't ship with winapi headers and the moon build tool compiles with
65+ # -DMOONBIT_NATIVE_NO_SYS_HEADER, but the runtime still includes <windows.h> unconditionally
66+ # for GetConsoleOutputCP/SetConsoleOutputCP used in moonbit_println. Without Visual Studio
67+ # installed TCC can't discover system headers, causing the native target build to fail.
68+ def patch-runtime-windows-header [libDir : string ] {
69+ let runtime = [$libDir runtime.c ] | path join
70+ if not ($runtime | path exists ) { return }
71+ let content = open $runtime
72+ let old = " #ifdef _WIN32\n #include <windows.h>\n #endif"
73+ if ($content | str contains $old ) {
74+ let new = [
75+ ' #ifdef _WIN32'
76+ ' #ifndef MOONBIT_NATIVE_NO_SYS_HEADER'
77+ ' #include <windows.h>'
78+ ' #else'
79+ ' #define CP_UTF8 65001'
80+ ' unsigned int GetConsoleOutputCP(void);'
81+ ' int SetConsoleOutputCP(unsigned int);'
82+ ' #endif'
83+ ' #endif'
84+ ] | str join " \n "
85+ $content | str replace $old $new | save -- force $runtime
86+ print $' (ansi g )Patched runtime.c: guarded <windows.h> behind MOONBIT_NATIVE_NO_SYS_HEADER(ansi reset )'
87+ }
88+ }
89+
6390# Download moonbit binary files to local
6491export def 'setup moonbit' [
6592 version ?, # The version of moonbit toolchain to setup, and `latest` by default
6693 -- setup-core(-c) , # Setup moonbit core
6794 -- core-version(-V) : string = ' latest' , # The version of moonbit core to setup, `latest` by default
95+ -- patch-runtime(-p) , # Patch runtime.c to fix native build on Windows without Visual Studio
6896] {
6997 let version = $version | default $env .MOONBIT_INSTALL_VERSION ? | default ' latest'
7098 if ($version not-in $VALID_VERSION_TAG ) and not (is-semver $version ) {
@@ -85,10 +113,24 @@ export def 'setup moonbit' [
85113 print $' (char nl )Setup moonbit toolchain of version: (ansi g )($version )(ansi reset )' ; hr-line
86114 print $' Current moon home: (ansi g )($MOONBIT_HOME )(ansi reset )'
87115
116+ # Clean up old lib and include directories before extraction to
117+ # avoid stale files, matching the behavior of the official install scripts
118+ let includeDir = [$MOONBIT_HOME include ] | path join
119+ if ($includeDir | path exists ) { rm - rf $includeDir }
120+ if ($MOONBIT_LIB_DIR | path exists ) { rm - rf $MOONBIT_LIB_DIR }
121+
88122 if (windows ? ) {
89123 fetch-release $version $' moonbit-($archive ).zip'
90124 unzip - qo $' moonbit-($archive ).zip' - d $MOONBIT_HOME
91125 rm moonbit*.zip
126+ if $patch_runtime {
127+ # Workaround: runtime.c includes <windows.h> without guarding it
128+ # behind MOONBIT_NATIVE_NO_SYS_HEADER. When TCC has no winapi headers
129+ # and Visual Studio is not installed, this causes the native build to
130+ # fail. Patch runtime.c to guard the include and provide manual
131+ # declarations for the required Windows API functions.
132+ patch-runtime-windows-header $MOONBIT_LIB_DIR
133+ }
92134 } else {
93135 fetch-release $version $' moonbit-($archive ).tar.gz'
94136 tar xf $' moonbit-($archive ).tar.gz' -- directory $MOONBIT_HOME
0 commit comments