v
1@echo off
2setlocal EnableDelayedExpansion EnableExtensions
3
4REM Option flags
5set /a invalid_cc=0
6set /a shift_counter=0
7set /a flag_local=0
8set /a flag_verbose=0
9
10REM Option variables
11set "log_file=%TEMP%\v_make.log"
12set compiler=
13set subcmd=
14set target=build
15
16REM TCC variables
17set "tcc_url=https://github.com/vlang/tccbin"
18set "tcc_dir=%~dp0thirdparty\tcc"
19set "tcc_branch=thirdparty-windows-amd64"
20
21REM VC settings
22set "vc_url=https://github.com/vlang/vc"
23set "vc_dir=%~dp0vc"
24
25REM Let a particular environment specify their own TCC repo
26if /I not ["%TCC_GIT%"] == [""] set "tcc_url=%TCC_GIT%"
27if /I not ["%TCC_BRANCH%"] == [""] set "tcc_branch=%TCC_BRANCH%"
28
29pushd %~dp0
30
31:verifyopt
32REM Read stdin EOF
33if ["%~1"] == [""] goto :init
34
35REM Target options
36if !shift_counter! LSS 1 (
37 if "%~1" == "help" (
38 if not ["%~2"] == [""] set "subcmd=%~2"& shift& set /a shift_counter+=1
39 )
40 for %%z in (build clean cleanall help) do (
41 if "%~1" == "%%z" set target=%1& shift& set /a shift_counter+=1& goto :verifyopt
42 )
43)
44
45REM Compiler option
46for %%g in (-gcc -msvc -tcc -clang) do (
47 if "%~1" == "%%g" set compiler=%~1& set compiler=!compiler:~1!& shift& set /a shift_counter+=1& goto :verifyopt
48)
49
50REM Standard options
51if "%~1" == "--verbose" (
52 if !flag_verbose! NEQ 0 (
53 echo The flag %~1 has already been specified. 1>&2
54 exit /b 2
55 )
56 set /a flag_verbose=1
57 set /a shift_counter+=1
58 shift
59 goto :verifyopt
60)
61if "%~1" == "--local" (
62 if !flag_local! NEQ 0 (
63 echo The flag %~1 has already been specified. 1>&2
64 exit /b 2
65 )
66 set /a flag_local=1
67 set /a shift_counter+=1
68 shift
69 goto :verifyopt
70)
71if "%~1" == "--logfile" (
72 if ["%~2"] == [""] (
73 echo Log file is not specified for -logfile parameter. 1>&2
74 exit /b 2
75 )
76 pushd "%~dp2" 2>NUL || (
77 echo The log file specified for -logfile parameter does not exist. 1>&2
78 exit /b 2
79 )
80 popd
81 set "log_file=%~sf2"
82 set /a shift_counter+=2
83 shift
84 shift
85 goto :verifyopt
86)
87
88echo Undefined option: %~1
89exit /b 2
90
91:init
92goto :!target!
93
94:cleanall
95call :clean
96if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL%
97echo.
98echo Cleanup vc
99echo ^> Purge TCC binaries
100if !flag_verbose! EQU 1 (
101 echo [Debug] rmdir /s /q "%tcc_dir%">>"!log_file!"
102 echo rmdir /s /q "%tcc_dir%"
103)
104rmdir /s /q "%tcc_dir%">>"!log_file!" 2>NUL
105echo ^> Purge vc repository
106if !flag_verbose! EQU 1 (
107 echo [Debug] rmdir /s /q "%vc_dir%">>"!log_file!"
108 echo rmdir /s /q "%vc_dir%"
109)
110rmdir /s /q "%vc_dir%">>"!log_file!" 2>NUL
111exit /b 0
112
113:clean
114echo Cleanup build artifacts
115echo ^> Purge debug symbols
116if !flag_verbose! EQU 1 (
117 echo [Debug] del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so>>"!log_file!"
118 echo del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so
119)
120del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so>>"!log_file!" 2>NUL
121echo ^> Delete old V executable
122if !flag_verbose! EQU 1 (
123 echo [Debug] del v_old.exe v*.exe>>"!log_file!"
124 echo del v_old.exe v*.exe
125)
126del v_old.exe v*.exe>>"!log_file!" 2>NUL
127exit /b 0
128
129:help
130if [!subcmd!] == [] (
131 call :usage 2>NUL
132) else (
133 call :help_!subcmd! 2>NUL
134)
135if %ERRORLEVEL% NEQ 0 echo Invalid subcommand: !subcmd!
136exit /b %ERRORLEVEL%
137
138:build
139if !flag_local! NEQ 1 (
140 call :download_tcc
141 if %ERRORLEVEL% NEQ 0 goto :error
142 del "!log_file!">NUL 2>&1
143 pushd "%vc_dir%" 2>NUL && (
144 echo Updating vc...
145 echo ^> Sync with remote !vc_url!
146 if !flag_verbose! EQU 1 (
147 echo [Debug] cd "%vc_dir%">>"!log_file!"
148 echo cd "%vc_dir%"
149 cd "%vc_dir%">>"!log_file!" 2>NUL
150 echo [Debug] git pull --quiet>>"!log_file!"
151 echo git pull --quiet
152 git pull --quiet>>"!log_file!" 2>NUL
153 echo [Debug] cd ..>>"!log_file!"
154 echo cd ..
155 cd ..>>"!log_file!" 2>NUL
156 ) else (
157 cd "%vc_dir%">>"!log_file!" 2>NUL
158 git pull --quiet>>"!log_file!" 2>NUL
159 cd ..>>"!log_file!" 2>NUL
160 )
161 popd
162 ) || (
163 echo Cloning vc...
164 echo ^> Cloning from remote !vc_url!
165 if !flag_verbose! EQU 1 (
166 echo [Debug] git clone --depth 1 --quiet %vc_url%>>"!log_file!"
167 echo git clone --depth 1 --quiet %vc_url%
168 )
169 git clone --depth 1 --quiet %vc_url%>>"!log_file!" 2>NUL
170 )
171 echo.
172)
173
174echo Building V...
175if not [!compiler!] == [] goto :!compiler!_strap
176
177:clang_strap
178where /q clang
179if %ERRORLEVEL% NEQ 0 (
180 echo ^> Clang not found
181 if not [!compiler!] == [] goto :error
182 goto :gcc_strap
183)
184
185echo ^> Attempting to build v_win.c with Clang
186if !flag_verbose! EQU 1 (
187 echo [Debug] clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
188 echo clang -std=c99 -municode -w -o v.exe .\vc\v_win.c
189)
190clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_file!" 2>NUL
191if %ERRORLEVEL% NEQ 0 (
192 REM In most cases, compile errors happen because the version of Clang installed is too old
193 clang --version>>"!log_file!"
194 goto :compile_error
195)
196
197echo ^> Compiling with .\v.exe self
198if !flag_verbose! EQU 1 (
199 echo [Debug] v.exe -cc clang self>>"!log_file!"
200 echo v.exe -cc clang self
201)
202v.exe -cc clang self>>"!log_file!" 2>NUL
203if %ERRORLEVEL% NEQ 0 goto :compile_error
204goto :success
205
206:gcc_strap
207where /q gcc
208if %ERRORLEVEL% NEQ 0 (
209 echo ^> GCC not found
210 if not [!compiler!] == [] goto :error
211 goto :msvc_strap
212)
213
214echo ^> Attempting to build v_win.c with GCC
215if !flag_verbose! EQU 1 (
216 echo [Debug] gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!"
217 echo gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c
218)
219gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!" 2>NUL
220if %ERRORLEVEL% NEQ 0 (
221 REM In most cases, compile errors happen because the version of GCC installed is too old
222 gcc --version>>"!log_File!"
223 goto :compile_error
224)
225
226echo ^> Compiling with .\v.exe self
227if !flag_verbose! EQU 1 (
228 echo [Debug] v.exe -cc gcc self>>"!log_file!"
229 echo v.exe -cc gcc self
230)
231v.exe -cc gcc self>>"!log_file!" 2>NUL
232if %ERRORLEVEL% NEQ 0 goto :compile_error
233goto :success
234
235:msvc_strap
236set VsWhereDir=%ProgramFiles(x86)%
237set HostArch=x64
238if "%PROCESSOR_ARCHITECTURE%" == "x86" (
239 echo Using x86 Build Tools...
240 set VsWhereDir=%ProgramFiles%
241 set HostArch=x86
242)
243
244if not exist "%VsWhereDir%\Microsoft Visual Studio\Installer\vswhere.exe" (
245 echo ^> MSVC not found
246 if not [!compiler!] == [] goto :error
247 goto :tcc_strap
248)
249
250for /f "usebackq tokens=*" %%i in (`"%VsWhereDir%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -prerelease -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
251 set InstallDir=%%i
252)
253
254if exist "%InstallDir%\Common7\Tools\vsdevcmd.bat" (
255 call "%InstallDir%\Common7\Tools\vsdevcmd.bat" -arch=%HostArch% -host_arch=%HostArch% -no_logo > NUL
256) else if exist "%VsWhereDir%\Microsoft Visual Studio 14.0\Common7\Tools\vsdevcmd.bat" (
257 call "%VsWhereDir%\Microsoft Visual Studio 14.0\Common7\Tools\vsdevcmd.bat" -arch=%HostArch% -host_arch=%HostArch% -no_logo > NUL
258)
259
260set ObjFile=.v.c.obj
261
262echo ^> Attempting to build v_win.c with MSVC
263if !flag_verbose! EQU 1 (
264 echo [Debug] cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no>>"!log_file!"
265 echo cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no
266)
267cl.exe /volatile:ms /Fo%ObjFile% /O2 /MD /D_VBOOTSTRAP vc\v_win.c user32.lib kernel32.lib advapi32.lib shell32.lib /link /nologo /out:v.exe /incremental:no>>"!log_file!" 2>NUL
268if %ERRORLEVEL% NEQ 0 (
269 REM In some cases, compile errors happen because of the MSVC compiler version
270 cl.exe 1>NUL 2>"!log_file!"
271 goto :compile_error
272)
273
274echo ^> Compiling with .\v.exe self
275if !flag_verbose! EQU 1 (
276 echo [Debug] v.exe -cc msvc self>>"!log_file!"
277 echo v.exe -cc msvc self
278)
279v.exe -cc msvc self>>"!log_file!" 2>NUL
280del %ObjFile%>>"!log_file!" 2>>&1
281if %ERRORLEVEL% NEQ 0 goto :compile_error
282goto :success
283
284:tcc_strap
285if [!compiler!] == [] set /a invalid_cc=1
286echo ^> Attempting to build v_win.c with TCC
287if !flag_verbose! EQU 1 (
288 echo [Debug] "!tcc_exe!" -std=c99 -municode -lws2_32 -lshell32 -ladvapi32 -bt10 -w -o v.exe vc\v_win.c>>"!log_file!"
289 echo "!tcc_exe!" -std=c99 -municode -lws2_32 -lshell32 -ladvapi32 -bt10 -w -o v.exe vc\v_win.c
290)
291"!tcc_exe!" -std=c99 -municode -lws2_32 -lshell32 -ladvapi32 -bt10 -w -o v.exe vc\v_win.c>>"!log_file!" 2>NUL
292if %ERRORLEVEL% NEQ 0 goto :compile_error
293
294echo ^> Compiling with .\v.exe self
295if !flag_verbose! EQU 1 (
296 echo [Debug] v.exe -cc "!tcc_exe!" self>>"!log_file!"
297 echo v.exe -cc "!tcc_exe!" self
298)
299v.exe -cc "!tcc_exe!" self>>"!log_file!" 2>NUL
300if %ERRORLEVEL% NEQ 0 goto :compile_error
301goto :success
302
303:download_tcc
304pushd %tcc_dir% 2>NUL && (
305 echo Updating TCC
306 echo ^> Syncing TCC from !tcc_url!
307 if !flag_verbose! EQU 1 (
308 echo [Debug] git pull --quiet>>"!log_file!"
309 echo git pull --quiet
310 )
311 git pull --quiet>>"!log_file!" 2>NUL
312 popd
313) || (
314 echo Bootstraping TCC...
315 echo ^> TCC not found
316 echo ^> Downloading TCC from !tcc_url!
317 if !flag_verbose! EQU 1 (
318 echo [Debug] git clone --depth 1 --quiet --single-branch --branch !tcc_branch! !tcc_url! "%tcc_dir%">>"!log_file!"
319 echo git clone --depth 1 --quiet --single-branch --branch !tcc_branch! !tcc_url! "%tcc_dir%"
320 )
321 git clone --depth 1 --quiet --single-branch --branch !tcc_branch! !tcc_url! "%tcc_dir%">>"!log_file!" 2>NUL
322)
323for /f "usebackq delims=" %%i in (`dir "%tcc_dir%" /b /a /s tcc.exe`) do (
324 set "attrib=%%~ai"
325 set "dattrib=%attrib:~0,1%"
326 if /I not "%dattrib%" == "d" set "tcc_exe=%%~sfi"
327)
328if [!tcc_exe!] == [] echo ^> TCC not found, even after cloning& goto :error
329echo.
330exit /b 0
331
332:compile_error
333echo.
334type "!log_file!">NUL 2>&1
335goto :error
336
337:error
338echo.
339echo Exiting from error
340exit /b 1
341
342:success
343echo ^> V built successfully!
344echo ^> To add V to your PATH, run `.\v.exe symlink`.
345if !invalid_cc! EQU 1 (
346 echo.
347 echo WARNING: No C compiler was detected in your PATH. `tcc` was used temporarily
348 echo to build V, but it may have some bugs and may not work in all cases.
349 echo A more advanced C compiler like GCC or MSVC is recommended.
350 echo https://github.com/vlang/v/wiki/Installing-a-C-compiler-on-Windows
351 echo.
352)
353
354:version
355echo.
356echo | set /p="V version: "
357.\v.exe version
358goto :eof
359
360:usage
361echo Usage:
362echo make.bat [target] [compiler] [options]
363echo.
364echo Compiler:
365echo -msvc ^| -gcc ^| -tcc ^| -clang Set C compiler
366echo.
367echo Target:
368echo build[default] Compiles V using the given C compiler
369echo clean Clean build artifacts and debugging symbols
370echo clean-all Cleanup entire ALL build artifacts and vc repository
371echo help Display usage help for the given target
372echo.
373echo Examples:
374echo make.bat -msvc
375echo make.bat -gcc --local --logpath output.log
376echo make.bat build -fresh-tcc --local
377echo make.bat help clean
378echo.
379echo Use "make help <target>" for more information about a target, for instance: "make help clean"
380echo.
381echo Note: Any undefined/unsupported options will be ignored
382exit /b 0
383
384:help_help
385echo Usage:
386echo make.bat help [target]
387echo.
388echo Target:
389echo build ^| clean ^| clean-all ^| help Query given target
390exit /b 0
391
392:help_clean
393echo Usage:
394echo make.bat clean
395echo.
396echo Options:
397echo --logfile PATH Use the specified PATH as the log
398echo --verbose Output compilation commands to stdout
399exit /b 0
400
401:help_cleanall
402echo Usage:
403echo make.bat clean-all
404echo.
405echo Options:
406echo --logfile PATH Use the specified PATH as the log
407echo --verbose Output compilation commands to stdout
408exit /b 0
409
410:help_build
411echo Usage:
412echo make.bat build [compiler] [options]
413echo.
414echo Compiler:
415echo -msvc ^| -gcc ^| -[fresh-]tcc ^| -clang Set C compiler
416echo.
417echo Options:
418echo --local Use the local vc repository without
419echo syncing with remote
420echo --logfile PATH Use the specified PATH as the log
421echo file
422echo --verbose Output compilation commands to stdout
423exit /b 0
424
425:eof
426popd
427endlocal
428exit /b 0