Batch Script Notes

So I have a few things different in the build.bat file that I thought I'd share:

First: /Fm is all you need to get a .map file, it can use a default name.

Second (and I saw this in an earlier thread), you can specify amd64_x86 to build for 32-bit with the 64-bit compiler. I think this makes sense if you're building a lot, and you want to build both at once (which you should to keep from having a version build up compiler errors. It also encourages you to run both builds more often, which is how I caught this bug).

I also cancel the rest of the builds if one errors out, which saves on scrolling through duplicate error messages.

This works with hot reloading because the dll always compiles before the exe, which would fail to compile because the program has the file open. So you'd only ever run in to trouble if you're hot reloading with both builds open at once, at which point you should compile DLLs in one pass, then EXEs (wrote all that just in case someone runs in to that bizarre situation).

I'll include my whole build.bat below, just as an example of how you can organize things:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@echo off
setlocal

IF NOT EXIST build mkdir build
pushd build

IF NOT EXIST x86 mkdir x86
IF NOT EXIST x64 mkdir x64

set BASE_NAME=win32_handmade

set COMPAT=/MT
set OPTIMIZATION=/Gm- /GR- /EHa- /Od /Oi
set WARNINGS=/WX /W4 /wd4201 /wd4100 /wd4189
set GAME_DEFINES=/DHANDMADE_INTERNAL=1 /DHANDMADE_SLOW=1 /DHANDMADE_WIN32=1 
set DEBUG=/FC /Z7 /Fm
set CL_OPTIONS=/nologo %COMPAT% %OPTIMIZATION% %WARNINGS% %GAME_DEFINES% %DEBUG%

set CODE=..\..\code\win32_handmade.cpp
set LIBS=User32.lib Gdi32.lib Winmm.lib
set LINKER_SHARED=/opt:ref -incremental:no
set LINKER_64=/link %LINKER_SHARED% /subsystem:windows
set LINKER_32=/link %LINKER_SHARED% /subsystem:windows,5.1

set DLL_CODE=..\..\code\handmade.cpp
set DLL_EXPORTS=/EXPORT:GameGetSoundSamples /EXPORT:GameUpdateAndRender
set DLL_OPTIONS=/LD /link %LINKER_SHARED% %DLL_EXPORTS%

set TIMESTAMP=%DATE:/=-%.%TIME::=-%
set TIMESTAMP=%TIMESTAMP: =%

echo Building x64
pushd x64
  del *.pdb > NUL 2> NUL
  call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
  cl %CL_OPTIONS% %DLL_CODE% %DLL_OPTIONS% /PDB:handmade_%TIMESTAMP%.pdb 
  if ERRORLEVEL 1 goto :eof
  cl /Fe%BASE_NAME%_x64.exe %CL_OPTIONS% %CODE% %LIBS% %LINKER_64%
  if ERRORLEVEL 1 goto :eof
popd
echo.

echo Building x86
pushd x86
  del *.pdb > NUL 2> NUL
  call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64_x86
  cl %CL_OPTIONS% %DLL_CODE% %DLL_OPTIONS% /PDB:handmade_%TIMESTAMP%.pdb 
  if ERRORLEVEL 1 goto :eof
  cl /Fe%BASE_NAME%_x86.exe %CL_OPTIONS% %CODE% %LIBS% %LINKER_32%
  if ERRORLEVEL 1 goto :eof
popd
echo.

popd
I see issue with this approach that calling "vcvarsall.bat" takes a bit of time. But we want to do build process as fast as possible. For example on my machine calling vcvarsall.bat takes more time that actually calling cl.exe. That's why it's nicer to set environment only once (shell.bat) and then call build.bat as many times as you want.

Also in case of error won't you will be left in x86 or x64 folder? It will be annoying to do "cd .." every time after error happens, right?
calling "vcvarsall.bat" takes a bit of time

I don't know about you, but the recompile takes 3s with my script. So I'm not too worried about that. I might compare times and replace the cls with their full paths if there's a difference, but really 3s is fast enough for me to debate whether it's worth the cognitive load of the 5 minutes of doing that, or the 30 seconds of writing this paragraph.


Also in case of error won't you will be left in x86 or x64 folder?

setlocal keeps script-local changes from bleeding over into your environment. It's also why all those environmental variables don't pollute your shell.
For me 3seconds vs 1second makes a difference. But of course it may be ok with you. That's fine.

Oh right, forgot about what setlocal was doing.
For me 3seconds vs 1second makes a difference.

Whatever floats your boat.
That's a useful tip re: setlocal. Maybe others can post their batch files so we can share hints and tips.

I've set mine up to build into a subfolder of the project called .\build. I can also pass three arguments for different builds, "msvc" to build with cl.exe, this is also the default if no switches are passed. "gcc" to build with gcc and "clean" to delete everything in the build folder.

I like using two compilers since they each have slightly different warnings, and its nice to know code is most likely portable if they both compile without warnings. I'm also using opengl for some stuff so linking with that.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@echo off

if exist .\build goto start
mkdir build

:start
pushd build

if "%1"=="" goto msvc_build
if "%1"=="msvc" goto msvc_build
if "%1"=="gcc" goto gcc_build
if "%1"=="clean" goto clean_build

echo.
echo unknown build switch
goto finish

:msvc_build
cl /MT /nologo /Gm- /EHa- /GR- /Od /Oi /W4 /WX /FC /Z7 /wd4201 /wd4204 ..\win32_main.c /link -opt:ref user32.lib gdi32.lib opengl32.lib
goto finish

:gcc_build
gcc -Wall -Wextra -Wno-unused-function -std=c99 ..\win32_main.c -oa.exe -luser32 -lgdi32 -lopengl32
goto finish

:clean_build
del /Q .
goto finish

:finish
popd