1 | @echo off |
2 | setlocal EnableDelayedExpansion EnableExtensions |
3 | |
4 | REM Option flags |
5 | set /a invalid_cc=0 |
6 | set /a shift_counter=0 |
7 | set /a flag_local=0 |
8 | set /a flag_verbose=0 |
9 | |
10 | REM Option variables |
11 | set "log_file=%TEMP%\v_make.log" |
12 | set compiler= |
13 | set subcmd= |
14 | set target=build |
15 | |
16 | REM TCC variables |
17 | set "tcc_url=https://github.com/vlang/tccbin" |
18 | set "tcc_dir=%~dp0thirdparty\tcc" |
19 | set "tcc_branch=thirdparty-windows-amd64" |
20 | |
21 | REM VC settings |
22 | set "vc_url=https://github.com/vlang/vc" |
23 | set "vc_dir=%~dp0vc" |
24 | |
25 | REM Let a particular environment specify their own TCC repo |
26 | if /I not ["%TCC_GIT%"] == [""] set "tcc_url=%TCC_GIT%" |
27 | if /I not ["%TCC_BRANCH%"] == [""] set "tcc_branch=%TCC_BRANCH%" |
28 | |
29 | pushd %~dp0 |
30 | |
31 | :verifyopt |
32 | REM Read stdin EOF |
33 | if ["%~1"] == [""] goto :init |
34 | |
35 | REM Target options |
36 | if !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 | |
45 | REM Compiler option |
46 | for %%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 | |
50 | REM Standard options |
51 | if "%~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 | ) |
61 | if "%~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 | ) |
71 | if "%~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 | |
88 | echo Undefined option: %~1 |
89 | exit /b 2 |
90 | |
91 | :init |
92 | goto :!target! |
93 | |
94 | :cleanall |
95 | call :clean |
96 | if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% |
97 | echo. |
98 | echo Cleanup vc |
99 | echo ^> Purge TCC binaries |
100 | if !flag_verbose! EQU 1 ( |
101 | echo [Debug] rmdir /s /q "%tcc_dir%">>"!log_file!" |
102 | echo rmdir /s /q "%tcc_dir%" |
103 | ) |
104 | rmdir /s /q "%tcc_dir%">>"!log_file!" 2>NUL |
105 | echo ^> Purge vc repository |
106 | if !flag_verbose! EQU 1 ( |
107 | echo [Debug] rmdir /s /q "%vc_dir%">>"!log_file!" |
108 | echo rmdir /s /q "%vc_dir%" |
109 | ) |
110 | rmdir /s /q "%vc_dir%">>"!log_file!" 2>NUL |
111 | exit /b 0 |
112 | |
113 | :clean |
114 | echo Cleanup build artifacts |
115 | echo ^> Purge debug symbols |
116 | if !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 | ) |
120 | del *.pdb *.lib *.bak *.out *.ilk *.exp *.obj *.o *.a *.so>>"!log_file!" 2>NUL |
121 | echo ^> Delete old V executable |
122 | if !flag_verbose! EQU 1 ( |
123 | echo [Debug] del v_old.exe v*.exe>>"!log_file!" |
124 | echo del v_old.exe v*.exe |
125 | ) |
126 | del v_old.exe v*.exe>>"!log_file!" 2>NUL |
127 | exit /b 0 |
128 | |
129 | :help |
130 | if [!subcmd!] == [] ( |
131 | call :usage 2>NUL |
132 | ) else ( |
133 | call :help_!subcmd! 2>NUL |
134 | ) |
135 | if %ERRORLEVEL% NEQ 0 echo Invalid subcommand: !subcmd! |
136 | exit /b %ERRORLEVEL% |
137 | |
138 | :build |
139 | if !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 | |
174 | echo Building V... |
175 | if not [!compiler!] == [] goto :!compiler!_strap |
176 | |
177 | :clang_strap |
178 | where /q clang |
179 | if %ERRORLEVEL% NEQ 0 ( |
180 | echo ^> Clang not found |
181 | if not [!compiler!] == [] goto :error |
182 | goto :gcc_strap |
183 | ) |
184 | |
185 | echo ^> Attempting to build v_win.c with Clang |
186 | if !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 | ) |
190 | clang -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_file!" 2>NUL |
191 | if %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 | |
197 | echo ^> Compiling with .\v.exe self |
198 | if !flag_verbose! EQU 1 ( |
199 | echo [Debug] v.exe -cc clang self>>"!log_file!" |
200 | echo v.exe -cc clang self |
201 | ) |
202 | v.exe -cc clang self>>"!log_file!" 2>NUL |
203 | if %ERRORLEVEL% NEQ 0 goto :compile_error |
204 | goto :success |
205 | |
206 | :gcc_strap |
207 | where /q gcc |
208 | if %ERRORLEVEL% NEQ 0 ( |
209 | echo ^> GCC not found |
210 | if not [!compiler!] == [] goto :error |
211 | goto :msvc_strap |
212 | ) |
213 | |
214 | echo ^> Attempting to build v_win.c with GCC |
215 | if !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 | ) |
219 | gcc -std=c99 -municode -w -o v.exe .\vc\v_win.c>>"!log_File!" 2>NUL |
220 | if %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 | |
226 | echo ^> Compiling with .\v.exe self |
227 | if !flag_verbose! EQU 1 ( |
228 | echo [Debug] v.exe -cc gcc self>>"!log_file!" |
229 | echo v.exe -cc gcc self |
230 | ) |
231 | v.exe -cc gcc self>>"!log_file!" 2>NUL |
232 | if %ERRORLEVEL% NEQ 0 goto :compile_error |
233 | goto :success |
234 | |
235 | :msvc_strap |
236 | set VsWhereDir=%ProgramFiles(x86)% |
237 | set HostArch=x64 |
238 | if "%PROCESSOR_ARCHITECTURE%" == "x86" ( |
239 | echo Using x86 Build Tools... |
240 | set VsWhereDir=%ProgramFiles% |
241 | set HostArch=x86 |
242 | ) |
243 | |
244 | if 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 | |
250 | for /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 | |
254 | if 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 | |
260 | set ObjFile=.v.c.obj |
261 | |
262 | echo ^> Attempting to build v_win.c with MSVC |
263 | if !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 | ) |
267 | 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!" 2>NUL |
268 | if %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 | |
274 | echo ^> Compiling with .\v.exe self |
275 | if !flag_verbose! EQU 1 ( |
276 | echo [Debug] v.exe -cc msvc self>>"!log_file!" |
277 | echo v.exe -cc msvc self |
278 | ) |
279 | v.exe -cc msvc self>>"!log_file!" 2>NUL |
280 | del %ObjFile%>>"!log_file!" 2>>&1 |
281 | if %ERRORLEVEL% NEQ 0 goto :compile_error |
282 | goto :success |
283 | |
284 | :tcc_strap |
285 | if [!compiler!] == [] set /a invalid_cc=1 |
286 | echo ^> Attempting to build v_win.c with TCC |
287 | if !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 |
292 | if %ERRORLEVEL% NEQ 0 goto :compile_error |
293 | |
294 | echo ^> Compiling with .\v.exe self |
295 | if !flag_verbose! EQU 1 ( |
296 | echo [Debug] v.exe -cc "!tcc_exe!" self>>"!log_file!" |
297 | echo v.exe -cc "!tcc_exe!" self |
298 | ) |
299 | v.exe -cc "!tcc_exe!" self>>"!log_file!" 2>NUL |
300 | if %ERRORLEVEL% NEQ 0 goto :compile_error |
301 | goto :success |
302 | |
303 | :download_tcc |
304 | pushd %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 | ) |
323 | for /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 | ) |
328 | if [!tcc_exe!] == [] echo ^> TCC not found, even after cloning& goto :error |
329 | echo. |
330 | exit /b 0 |
331 | |
332 | :compile_error |
333 | echo. |
334 | type "!log_file!">NUL 2>&1 |
335 | goto :error |
336 | |
337 | :error |
338 | echo. |
339 | echo Exiting from error |
340 | exit /b 1 |
341 | |
342 | :success |
343 | echo ^> V built successfully! |
344 | echo ^> To add V to your PATH, run `.\v.exe symlink`. |
345 | if !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 |
355 | echo. |
356 | echo | set /p="V version: " |
357 | .\v.exe version |
358 | goto :eof |
359 | |
360 | :usage |
361 | echo Usage: |
362 | echo make.bat [target] [compiler] [options] |
363 | echo. |
364 | echo Compiler: |
365 | echo -msvc ^| -gcc ^| -tcc ^| -clang Set C compiler |
366 | echo. |
367 | echo Target: |
368 | echo build[default] Compiles V using the given C compiler |
369 | echo clean Clean build artifacts and debugging symbols |
370 | echo clean-all Cleanup entire ALL build artifacts and vc repository |
371 | echo help Display usage help for the given target |
372 | echo. |
373 | echo Examples: |
374 | echo make.bat -msvc |
375 | echo make.bat -gcc --local --logpath output.log |
376 | echo make.bat build -fresh-tcc --local |
377 | echo make.bat help clean |
378 | echo. |
379 | echo Use "make help <target>" for more information about a target, for instance: "make help clean" |
380 | echo. |
381 | echo Note: Any undefined/unsupported options will be ignored |
382 | exit /b 0 |
383 | |
384 | :help_help |
385 | echo Usage: |
386 | echo make.bat help [target] |
387 | echo. |
388 | echo Target: |
389 | echo build ^| clean ^| clean-all ^| help Query given target |
390 | exit /b 0 |
391 | |
392 | :help_clean |
393 | echo Usage: |
394 | echo make.bat clean |
395 | echo. |
396 | echo Options: |
397 | echo --logfile PATH Use the specified PATH as the log |
398 | echo --verbose Output compilation commands to stdout |
399 | exit /b 0 |
400 | |
401 | :help_cleanall |
402 | echo Usage: |
403 | echo make.bat clean-all |
404 | echo. |
405 | echo Options: |
406 | echo --logfile PATH Use the specified PATH as the log |
407 | echo --verbose Output compilation commands to stdout |
408 | exit /b 0 |
409 | |
410 | :help_build |
411 | echo Usage: |
412 | echo make.bat build [compiler] [options] |
413 | echo. |
414 | echo Compiler: |
415 | echo -msvc ^| -gcc ^| -[fresh-]tcc ^| -clang Set C compiler |
416 | echo. |
417 | echo Options: |
418 | echo --local Use the local vc repository without |
419 | echo syncing with remote |
420 | echo --logfile PATH Use the specified PATH as the log |
421 | echo file |
422 | echo --verbose Output compilation commands to stdout |
423 | exit /b 0 |
424 | |
425 | :eof |
426 | popd |
427 | endlocal |
428 | exit /b 0 |