1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

make.bat: fix use of make.bat from v up (#16348)

* .editorconfig: fix EOL for BAT files

* make.bat: fix use of `make.bat` from `v up`

- use move semantics, instead of replace, for `v` executable updates
- fixes [#16184](https://github.com/vlang/v/issues/16184)

# [why]

`v up` updates the executable by directly calling `make.bat`, awaiting
the result, which keeps an open file handle to it's own executable file.
`make.bat` compiles and, crucially, attempts to directly replace that
`v` executable. But, in WinOS, files with open file handles cannot be
deleted/replaced, so the `make` then fails. The other key point is that,
although WinOS files with open file handles can't be deleted/replaced,
they _can be moved/renamed_.

Thus, the technique that most self-updating WinOS executables use is to
move the current executable to some alternate name (ie, *v_old.exe*) and
then move the newly updated executable to the original location (ie,
*v.exe*). The next invocation of the "original" executable will then run
the updated version.

Note, this technique also works correctly for direct invocations of `make.bat`.
This commit is contained in:
Roy Ivy III 2022-11-07 00:48:08 -06:00 committed by GitHub
parent 407bb6641f
commit c015f15d8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 28 deletions

View File

@ -10,6 +10,10 @@ trim_trailing_whitespace = true
indent_style = tab indent_style = tab
indent_size = 4 indent_size = 4
[*.{bat,cmd}]
# BAT/CMD ~ DOS/Win requires BAT/CMD files to have CRLF EOLNs
end_of_line = crlf
[*.{yml,yaml}] [*.{yml,yaml}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -1,6 +1,6 @@
@setlocal EnableDelayedExpansion EnableExtensions @setlocal EnableDelayedExpansion EnableExtensions
IF NOT DEFINED VERBOSE_MAKE @echo off @IF NOT DEFINED VERBOSE_MAKE @echo off
REM Option flags REM Option flags
set /a shift_counter=0 set /a shift_counter=0
@ -11,6 +11,11 @@ set compiler=
set subcmd= set subcmd=
set target=build set target=build
set V_EXE=.\v.exe
set V_BOOTSTRAP=.\v_win_bootstrap.exe
set V_OLD=.\v_old.exe
set V_UPDATED=.\v_up.exe
REM TCC variables REM TCC variables
set "tcc_url=https://github.com/vlang/tccbin" set "tcc_url=https://github.com/vlang/tccbin"
set "tcc_dir=thirdparty\tcc" set "tcc_dir=thirdparty\tcc"
@ -89,8 +94,8 @@ echo Cleanup build artifacts
echo ^> Purge debug symbols echo ^> Purge debug symbols
del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so
echo ^> Delete old V executable echo ^> Delete old V executable(s)
del v_old.exe v*.exe del v*.exe
exit /b 0 exit /b 0
:help :help
@ -124,13 +129,13 @@ if not [!compiler!] == [] goto :!compiler!_strap
REM By default, use tcc, since we have it prebuilt: REM By default, use tcc, since we have it prebuilt:
:tcc_strap :tcc_strap
:tcc32_strap :tcc32_strap
echo ^> Attempting to build v_win.c with "!tcc_exe!" echo ^> Attempting to build "%V_BOOTSTRAP%" (from v_win.c) with "!tcc_exe!"
"!tcc_exe!" -Bthirdparty/tcc -bt10 -g -w -o v.exe vc\v_win.c -ladvapi32 "!tcc_exe!" -Bthirdparty/tcc -bt10 -g -w -o "%V_BOOTSTRAP%" vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 goto :compile_error if %ERRORLEVEL% NEQ 0 goto :compile_error
echo ^> Compiling .\v.exe with itself echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%"
v.exe -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o v2.exe cmd/v "%V_BOOTSTRAP%" -keepc -g -showcc -cc "!tcc_exe!" -cflags -Bthirdparty/tcc -o "%V_UPDATED%" cmd/v
if %ERRORLEVEL% NEQ 0 goto :clang_strap if %ERRORLEVEL% NEQ 0 goto :clang_strap
call :move_v2_to_v call :move_updated_to_v
goto :success goto :success
:clang_strap :clang_strap
@ -141,18 +146,18 @@ if %ERRORLEVEL% NEQ 0 (
goto :gcc_strap goto :gcc_strap
) )
echo ^> Attempting to build v_win.c with Clang echo ^> Attempting to build "%V_BOOTSTRAP%" (from v_win.c) with Clang
clang -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32 clang -std=c99 -municode -g -w -o "%V_BOOTSTRAP%" .\vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
echo In most cases, compile errors happen because the version of Clang installed is too old echo In most cases, compile errors happen because the version of Clang installed is too old
clang --version clang --version
goto :compile_error goto :compile_error
) )
echo ^> Compiling .\v.exe with itself echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%"
v.exe -keepc -g -showcc -cc clang -o v2.exe cmd/v "%V_BOOTSTRAP%" -keepc -g -showcc -cc clang -o "%V_UPDATED%" cmd/v
if %ERRORLEVEL% NEQ 0 goto :compile_error if %ERRORLEVEL% NEQ 0 goto :compile_error
call :move_v2_to_v call :move_updated_to_v
goto :success goto :success
:gcc_strap :gcc_strap
@ -163,18 +168,18 @@ if %ERRORLEVEL% NEQ 0 (
goto :msvc_strap goto :msvc_strap
) )
echo ^> Attempting to build v_win.c with GCC echo ^> Attempting to build "%V_BOOTSTRAP%" (from v_win.c) with GCC
gcc -std=c99 -municode -g -w -o v.exe .\vc\v_win.c -ladvapi32 gcc -std=c99 -municode -g -w -o "%V_BOOTSTRAP%" .\vc\v_win.c -ladvapi32
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
echo In most cases, compile errors happen because the version of GCC installed is too old echo In most cases, compile errors happen because the version of GCC installed is too old
gcc --version gcc --version
goto :compile_error goto :compile_error
) )
echo ^> Compiling .\v.exe with itself echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%"
v.exe -keepc -g -showcc -cc gcc -o v2.exe cmd/v "%V_BOOTSTRAP%" -keepc -g -showcc -cc gcc -o "%V_UPDATED%" cmd/v
if %ERRORLEVEL% NEQ 0 goto :compile_error if %ERRORLEVEL% NEQ 0 goto :compile_error
call :move_v2_to_v call :move_updated_to_v
goto :success goto :success
:msvc_strap :msvc_strap
@ -204,19 +209,19 @@ if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
set ObjFile=.v.c.obj set ObjFile=.v.c.obj
echo ^> Attempting to build v_win.c with MSVC echo ^> Attempting to build "%V_BOOTSTRAP%" (from v_win.c) with MSVC
cl.exe /volatile:ms /Fo%ObjFile% /W0 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no cl.exe /volatile:ms /Fo%ObjFile% /W0 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:"%V_BOOTSTRAP%" /incremental:no
if %ERRORLEVEL% NEQ 0 ( if %ERRORLEVEL% NEQ 0 (
echo In some cases, compile errors happen because of the MSVC compiler version echo In some cases, compile errors happen because of the MSVC compiler version
cl.exe cl.exe
goto :compile_error goto :compile_error
) )
echo ^> Compiling .\v.exe with itself echo ^> Compiling "%V_EXE%" with "%V_BOOTSTRAP%"
v.exe -keepc -g -showcc -cc msvc -o v2.exe cmd/v "%V_BOOTSTRAP%" -keepc -g -showcc -cc msvc -o "%V_UPDATED%" cmd/v
del %ObjFile% del %ObjFile%
if %ERRORLEVEL% NEQ 0 goto :compile_error if %ERRORLEVEL% NEQ 0 goto :compile_error
call :move_v2_to_v call :move_updated_to_v
goto :success goto :success
:download_tcc :download_tcc
@ -312,11 +317,11 @@ echo syncing with remote
exit /b 0 exit /b 0
:bootstrap_tcc :bootstrap_tcc
echo Bootstraping TCC... echo Bootstrapping TCC...
echo ^> TCC not found 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! ) 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 --depth 1 --quiet --single-branch --branch !tcc_branch! !tcc_url! "%tcc_dir%" git clone --depth 1 --quiet --single-branch --branch !tcc_branch! !tcc_url! "%tcc_dir%"
git -C "%tcc_dir%" log -n3 git --no-pager -C "%tcc_dir%" log -n3
exit /b 0 exit /b 0
:cloning_vc :cloning_vc
@ -330,9 +335,10 @@ popd
endlocal endlocal
exit /b 0 exit /b 0
:move_v2_to_v :move_updated_to_v
del v.exe @REM del "%V_EXE%" &:: breaks if `make.bat` is run from `v up` b/c of held file handle on `v.exe`
if exist "%V_EXE%" move "%V_EXE%" "%V_OLD%" >nul
REM sleep for at most 100ms REM sleep for at most 100ms
ping 192.0.2.1 -n 1 -w 100 >nul ping 192.0.2.1 -n 1 -w 100 >nul
move v2.exe v.exe move "%V_UPDATED%" "%V_EXE%" >nul
exit /b 0 exit /b 0