From c590ffe8f1fb1501c15a16e6ea33e6fda8524f97 Mon Sep 17 00:00:00 2001 From: Maokaman1 Date: Mon, 27 Apr 2026 01:19:47 +0300 Subject: [PATCH] makev.bat: fix Windows TCC bootstrap (#26998) --- makev.bat | 131 +++++++++++------- vlib/v/gen/c/auto_str_methods.v | 6 +- vlib/v/gen/c/cheaders.v | 7 +- .../gen/c/cheaders_manual_stdlib_decls_test.v | 5 +- 4 files changed, 94 insertions(+), 55 deletions(-) diff --git a/makev.bat b/makev.bat index 73213959d..6437d6730 100644 --- a/makev.bat +++ b/makev.bat @@ -17,6 +17,10 @@ set V_OLD=./v_old.exe set V_UPDATED=./v_up.exe set V_STAGE=./v_stage.exe set V_C_FILE=./vc/v_win.c +REM Existing vc bootstraps may predate the TCC Win64 CRT prelude fix, so keep +REM their cgen single-threaded while they build a fresh compiler from sources. +REM TODO: remove this after vc/v_win.c is regenerated with the fixed CRT prelude. +set V_BOOTSTRAP_VFLAGS=-no-parallel set where_exe=where.exe if not ["%SystemRoot%"] == [""] if exist "%SystemRoot%\System32\where.exe" set where_exe=%SystemRoot%\System32\where.exe @@ -84,13 +88,19 @@ exit /b 0 :cleanall call :clean -if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% +if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! echo. echo Cleanup vc echo ^> Purge TCC binaries -rmdir /s /q "%tcc_dir%" +if exist "%tcc_dir%" ( + rmdir /s /q "%tcc_dir%" + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! +) echo ^> Purge vc repository -rmdir /s /q "%vc_dir%" +if exist "%vc_dir%" ( + rmdir /s /q "%vc_dir%" + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! +) exit /b 0 :clean @@ -104,6 +114,7 @@ exit /b 0 :rebuild call :cleanall +if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! goto :build :help @@ -112,24 +123,27 @@ if [!subcmd!] == [] ( ) else ( call :help_!subcmd! ) -if %ERRORLEVEL% NEQ 0 echo Invalid subcommand: !subcmd! -exit /b %ERRORLEVEL% +if !ERRORLEVEL! NEQ 0 echo Invalid subcommand: !subcmd! +exit /b !ERRORLEVEL! :build if !flag_local! NEQ 1 ( call :download_tcc - if %ERRORLEVEL% NEQ 0 goto :error + if !ERRORLEVEL! NEQ 0 goto :error if exist "%vc_dir%" ( - pushd "%vc_dir%" && ( - echo Updating vc... - echo ^> Sync with remote !vc_url! - cd %vc_dir% - git pull --rebase --quiet - cd .. + pushd "%vc_dir%" + if !ERRORLEVEL! NEQ 0 goto :error + echo Updating vc... + echo ^> Sync with remote !vc_url! + git pull --rebase --quiet + if !ERRORLEVEL! NEQ 0 ( popd + goto :error ) + popd ) else ( call :cloning_vc + if !ERRORLEVEL! NEQ 0 goto :error ) echo. ) @@ -142,55 +156,67 @@ REM By default, use tcc, since we have it prebuilt: :tcc_strap :tcc32_strap call :build_bootstrap_with_tcc -if %ERRORLEVEL% NEQ 0 goto :compile_error -echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%" -REM Keep the TCC root relative here; V forwards -cflags through a response file. -REM An absolute -B path breaks there when the checkout path contains spaces. -"%V_BOOTSTRAP%" -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o "%V_UPDATED%" cmd/v -if %ERRORLEVEL% NEQ 0 goto :tcc_retry_with_host_bootstrap +if !ERRORLEVEL! NEQ 0 goto :compile_error +call :build_fresh_v_with_tcc +if !ERRORLEVEL! NEQ 0 goto :tcc_retry_with_host_bootstrap call :move_updated_to_v goto :success :tcc_retry_with_host_bootstrap echo ^> TCC-built bootstrap failed; retrying bootstrap with Clang/GCC before compiling "%V_EXE%" with TCC call :build_bootstrap_with_clang -if %ERRORLEVEL% NEQ 0 call :build_bootstrap_with_gcc -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 call :build_bootstrap_with_gcc +if !ERRORLEVEL! NEQ 0 ( if [!compiler!] == [] goto :clang_strap goto :compile_error ) -echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%" -"%V_BOOTSTRAP%" -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o "%V_UPDATED%" cmd/v -if %ERRORLEVEL% NEQ 0 ( +call :build_fresh_v_with_tcc +if !ERRORLEVEL! NEQ 0 ( if [!compiler!] == [] goto :clang_strap goto :compile_error ) call :move_updated_to_v goto :success +:build_fresh_v_with_tcc +echo ^> Compiling "%V_STAGE%" with "%V_BOOTSTRAP%" +REM Keep the TCC root relative here; V forwards -cflags through a response file. +REM An absolute -B path breaks there when the checkout path contains spaces. +"%V_BOOTSTRAP%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o "%V_STAGE%" cmd/v +set stage_error=!ERRORLEVEL! +if !stage_error! NEQ 0 ( + if exist "%V_STAGE%" del "%V_STAGE%" + exit /b !stage_error! +) +echo ^> Compiling "%V_EXE%" with "%V_STAGE%" +"%V_STAGE%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o "%V_UPDATED%" cmd/v +set stage_error=!ERRORLEVEL! +if exist "%V_STAGE%" del "%V_STAGE%" +exit /b !stage_error! + :clang_strap call :build_bootstrap_with_clang -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( if not [!compiler!] == [] goto :error goto :gcc_strap ) echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%" -"%V_BOOTSTRAP%" -keepc -g -showcc -cc clang -cflags "--target=!clang_target!" -o "%V_UPDATED%" cmd/v -if %ERRORLEVEL% NEQ 0 goto :compile_error +"%V_BOOTSTRAP%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc -cc clang -cflags "--target=!clang_target!" -o "%V_UPDATED%" cmd/v +if !ERRORLEVEL! NEQ 0 goto :compile_error call :move_updated_to_v goto :success :gcc_strap call :build_bootstrap_with_gcc -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( if not [!compiler!] == [] goto :error goto :msvc_strap ) echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%" -"%V_BOOTSTRAP%" -keepc -g -showcc -cc "!gcc_exe!" -o "%V_UPDATED%" cmd/v -if %ERRORLEVEL% NEQ 0 goto :compile_error +"%V_BOOTSTRAP%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc -cc "!gcc_exe!" -o "%V_UPDATED%" cmd/v +if !ERRORLEVEL! NEQ 0 goto :compile_error call :move_updated_to_v goto :success @@ -224,15 +250,15 @@ set ObjFile=.v.c.obj echo ^> Bootstrapping "%V_BOOTSTRAP%" before compiling "%V_EXE%" with MSVC set stage_vflags= call :build_bootstrap_with_clang -if %ERRORLEVEL% EQU 0 ( +if !ERRORLEVEL! EQU 0 ( set stage_vflags=-cc clang -cflags "--target=!clang_target!" ) else ( call :build_bootstrap_with_gcc - if %ERRORLEVEL% EQU 0 ( + if !ERRORLEVEL! EQU 0 ( set stage_vflags=-cc "!gcc_exe!" ) else ( call :build_bootstrap_with_tcc - if %ERRORLEVEL% EQU 0 set stage_vflags=-cc "!tcc_exe!" -cflags -Bthirdparty/tcc + if !ERRORLEVEL! EQU 0 set stage_vflags=-cc "!tcc_exe!" -cflags -Bthirdparty/tcc ) ) if not defined stage_vflags ( @@ -242,16 +268,16 @@ if not defined stage_vflags ( ) echo ^> Compiling "%V_STAGE%" with "%V_BOOTSTRAP%" -"%V_BOOTSTRAP%" -keepc -g -showcc !stage_vflags! -o "%V_STAGE%" cmd/v -if %ERRORLEVEL% NEQ 0 ( +"%V_BOOTSTRAP%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc !stage_vflags! -o "%V_STAGE%" cmd/v +if !ERRORLEVEL! NEQ 0 ( if exist %ObjFile% del %ObjFile% if exist "%V_STAGE%" del "%V_STAGE%" goto :compile_error ) echo ^> Compiling "%V_EXE%" with "%V_STAGE%" -"%V_STAGE%" -keepc -g -showcc -cc msvc -o "%V_UPDATED%" cmd/v -set msvc_error=%ERRORLEVEL% +"%V_STAGE%" %V_BOOTSTRAP_VFLAGS% -keepc -g -showcc -cc msvc -o "%V_UPDATED%" cmd/v +set msvc_error=!ERRORLEVEL! if exist %ObjFile% del %ObjFile% if exist "%V_STAGE%" del "%V_STAGE%" if %msvc_error% NEQ 0 goto :compile_error @@ -260,19 +286,25 @@ goto :success :download_tcc if exist "%tcc_dir%" ( - pushd "%tcc_dir%" && ( - echo Updating TCC - echo ^> Syncing TCC from !tcc_url! - if exist "lib\advapi32.def" git checkout -- lib\advapi32.def >nul 2>nul - git pull --rebase --quiet + pushd "%tcc_dir%" + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! + echo Updating TCC + echo ^> Syncing TCC from !tcc_url! + if exist "lib\advapi32.def" git checkout -- lib\advapi32.def >nul 2>nul + git pull --rebase --quiet + if !ERRORLEVEL! NEQ 0 ( + set tcc_update_error=!ERRORLEVEL! popd + exit /b !tcc_update_error! ) + popd ) else ( call :bootstrap_tcc + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! ) call :patch_tcc_defs -if %ERRORLEVEL% NEQ 0 goto :error +if !ERRORLEVEL! NEQ 0 goto :error if not exist "%tcc_exe%" echo ^> TCC not found, even after cloning& goto :error echo. @@ -386,14 +418,15 @@ echo Bootstrapping TCC... echo ^> TCC not found if "!tcc_branch!" == "thirdparty-windows-i386" ( echo ^> Downloading TCC32 from !tcc_url! , branch !tcc_branch! ) else ( echo ^> Downloading TCC64 from !tcc_url! , branch !tcc_branch! ) git clone --filter=blob:none --quiet --branch !tcc_branch! !tcc_url! "%tcc_dir%" +if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! git --no-pager -C "%tcc_dir%" log -n3 -exit /b 0 +exit /b !ERRORLEVEL! :cloning_vc echo Cloning vc... echo ^> Cloning from remote !vc_url! git clone --filter=blob:none --quiet "%vc_url%" -exit /b 0 +exit /b !ERRORLEVEL! :build_bootstrap_with_tcc if not exist "!tcc_exe!" ( @@ -402,18 +435,18 @@ if not exist "!tcc_exe!" ( ) echo ^> Attempting to build "%V_BOOTSTRAP%" (from %V_C_FILE%) with "!tcc_exe!" "!tcc_exe!" -B"%tcc_dir%" -bt10 -g -w -o "%V_BOOTSTRAP%" "%V_C_FILE%" -ladvapi32 -lws2_32 -Wl,-stack=33554432 -exit /b %ERRORLEVEL% +exit /b !ERRORLEVEL! :build_bootstrap_with_clang "%where_exe%" /q clang -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( echo ^> Clang not found exit /b 1 ) if "%PROCESSOR_ARCHITECTURE%" == "x86" ( set clang_target=i686-w64-mingw32 ) else ( set clang_target=x86_64-w64-mingw32 ) echo ^> Attempting to build "%V_BOOTSTRAP%" (from %V_C_FILE%) with Clang clang --target=!clang_target! -std=c99 -municode -g -w -Wno-error=implicit-function-declaration -Wno-error=incompatible-function-pointer-types -o "%V_BOOTSTRAP%" "%V_C_FILE%" -ladvapi32 -lws2_32 -Wl,-stack=33554432 -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( echo In most cases, compile errors happen because the version of Clang installed is too old clang --version exit /b 1 @@ -422,13 +455,13 @@ exit /b 0 :build_bootstrap_with_gcc call :find_gcc_exe -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( echo ^> GCC not found exit /b 1 ) echo ^> Attempting to build "%V_BOOTSTRAP%" (from %V_C_FILE%) with GCC "!gcc_exe!" "!gcc_exe!" -std=c99 -municode -g -w -o "%V_BOOTSTRAP%" "%V_C_FILE%" -ladvapi32 -lws2_32 -Wl,-stack=33554432 -if %ERRORLEVEL% NEQ 0 ( +if !ERRORLEVEL! NEQ 0 ( echo In most cases, compile errors happen because the version of GCC installed is too old "!gcc_exe!" --version exit /b 1 diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index 82dafbe72..8772af2ac 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -127,10 +127,10 @@ fn (mut g Gen) final_gen_str(typ StrType) { } styp := typ.styp str_fn_name := g.get_str_fn(typ.typ) - if str_fn_name in g.str_fn_names { - return - } lock g.str_fn_names { + if str_fn_name in g.str_fn_names { + return + } g.str_fn_names << str_fn_name } if typ.typ.has_flag(.option) { diff --git a/vlib/v/gen/c/cheaders.v b/vlib/v/gen/c/cheaders.v index f5bc2af67..016edcfef 100644 --- a/vlib/v/gen/c/cheaders.v +++ b/vlib/v/gen/c/cheaders.v @@ -546,6 +546,11 @@ V_CRT_LINKAGE isize V_CRT_CALL getline(char **lineptr, size_t *n, FILE *stream); V_CRT_LINKAGE int V_CRT_CALL _fileno(FILE *stream); V_CRT_LINKAGE FILE * V_CRT_CALL _wfopen(const unsigned short *filename, const unsigned short *mode); V_CRT_LINKAGE int V_CRT_CALL _wremove(const unsigned short *path); +V_CRT_LINKAGE void * V_CRT_CALL _aligned_malloc(size_t size, size_t alignment); +V_CRT_LINKAGE void * V_CRT_CALL _aligned_realloc(void *memory, size_t size, size_t alignment); +V_CRT_LINKAGE void V_CRT_CALL _aligned_free(void *memory); +V_CRT_LINKAGE unsigned short * V_CRT_CALL _wgetenv(const unsigned short *varname); +V_CRT_LINKAGE int V_CRT_CALL _wputenv(const unsigned short *envstring); #endif #if defined(_MSC_VER) && !defined(__clang__) #ifndef _TRUNCATE @@ -553,8 +558,6 @@ V_CRT_LINKAGE int V_CRT_CALL _wremove(const unsigned short *path); #endif V_CRT_LINKAGE int V_CRT_CALL _vscprintf(const char *format, va_list ap); V_CRT_LINKAGE int V_CRT_CALL _vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list ap); -V_CRT_LINKAGE unsigned short * V_CRT_CALL _wgetenv(const unsigned short *varname); -V_CRT_LINKAGE int V_CRT_CALL _wputenv(const unsigned short *envstring); #endif #endif #ifndef _IOFBF diff --git a/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v b/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v index cf2a01951..0a375031a 100644 --- a/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v +++ b/vlib/v/gen/c/cheaders_manual_stdlib_decls_test.v @@ -22,7 +22,7 @@ fn test_default_c_prelude_uses_manual_stdio_stdlib_string_and_stdarg_decls() { assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL vfprintf(FILE *stream, const char *format, va_list ap);'), generated_c assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL vsnprintf(char *str, size_t size, const char *format, va_list ap);'), generated_c - assert generated_c.contains('#if defined(_WIN32) || defined(_WIN64)\nV_CRT_LINKAGE int V_CRT_CALL _fileno(FILE *stream);\nV_CRT_LINKAGE FILE * V_CRT_CALL _wfopen(const unsigned short *filename, const unsigned short *mode);\nV_CRT_LINKAGE int V_CRT_CALL _wremove(const unsigned short *path);\n#endif'), generated_c + assert generated_c.contains('#if defined(_WIN32) || defined(_WIN64)\nV_CRT_LINKAGE int V_CRT_CALL _fileno(FILE *stream);\nV_CRT_LINKAGE FILE * V_CRT_CALL _wfopen(const unsigned short *filename, const unsigned short *mode);\nV_CRT_LINKAGE int V_CRT_CALL _wremove(const unsigned short *path);\nV_CRT_LINKAGE void * V_CRT_CALL _aligned_malloc(size_t size, size_t alignment);\nV_CRT_LINKAGE void * V_CRT_CALL _aligned_realloc(void *memory, size_t size, size_t alignment);\nV_CRT_LINKAGE void V_CRT_CALL _aligned_free(void *memory);\nV_CRT_LINKAGE unsigned short * V_CRT_CALL _wgetenv(const unsigned short *varname);\nV_CRT_LINKAGE int V_CRT_CALL _wputenv(const unsigned short *envstring);\n#endif'), generated_c assert generated_c.contains('V_CRT_LINKAGE void V_CRT_CALL perror(const char *str);'), generated_c assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL mkstemp(char *stemplate);'), generated_c @@ -37,6 +37,9 @@ fn test_default_c_prelude_uses_manual_stdio_stdlib_string_and_stdarg_decls() { assert generated_c.contains('#if defined(_MSC_VER) && !defined(__clang__)\n\t#define V_CRT_LINKAGE __declspec(dllimport)\n\t#define V_CRT_CALL VCALLCONV(cdecl)\n#else\n\t#define V_CRT_LINKAGE\n\t#define V_CRT_CALL\n#endif'), generated_c assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL _vscprintf(const char *format, va_list ap);'), generated_c assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL _vsnprintf_s(char *buffer, size_t size, size_t count, const char *format, va_list ap);'), generated_c + assert generated_c.contains('V_CRT_LINKAGE void * V_CRT_CALL _aligned_malloc(size_t size, size_t alignment);'), generated_c + assert generated_c.contains('V_CRT_LINKAGE void * V_CRT_CALL _aligned_realloc(void *memory, size_t size, size_t alignment);'), generated_c + assert generated_c.contains('V_CRT_LINKAGE void V_CRT_CALL _aligned_free(void *memory);'), generated_c assert generated_c.contains('V_CRT_LINKAGE unsigned short * V_CRT_CALL _wgetenv(const unsigned short *varname);'), generated_c assert generated_c.contains('V_CRT_LINKAGE int V_CRT_CALL _wputenv(const unsigned short *envstring);'), generated_c assert generated_c.contains('#elif defined(__MINGW32__) || defined(__MINGW64__) || (defined(__clang__) && (defined(_WIN32) || defined(_WIN64)))\ntypedef struct _iobuf FILE;\nFILE* __cdecl __acrt_iob_func(unsigned index);\n#define stdin (__acrt_iob_func(0))\n#define stdout (__acrt_iob_func(1))\n#define stderr (__acrt_iob_func(2))'), generated_c -- 2.39.5