Losing debuggability in VS when recompiling game?

Greetings!

I'm having a dilemma that's making me a sad panda.

I run devenv on the platform layer exe, put a breakpoint in the game's DLL code, and it would hit it just fine. However; when I recompile the game's code (which generates a new PDB file), VS no longer can break at my breakpoints (in the game's code) and I lose debuggability until I restart the engine/game, very annoying to say the least. It can still break at the platform's code, but it doesn't even let me step-in to the game's function pointer calls (GameUpdateAndRender etc)

I'm not sure if Casey talked about this or even addressed it but I would really like to find a solution. Have you guys experienced the same problem or is it just me?

Here's my game DLL loading/unloading functions if you're curious:

[Code]

internal void
Win32UnloadGameCode(game_code *GameCode)
{
if (GameCode->CodeDLL)
{
FreeLibrary(GameCode->CodeDLL);
GameCode->CodeDLL = 0;
}

GameCode->GameUpdateAndRender = GameUpdateAndRenderStub;
GameCode->GameInitialize = GameInitializeStub;
GameCode->GameGetInfo = GameGetInfoStub;
GameCode->GameOutputSound = GameOutputSoundStub;
}

internal void
Win32LoadGameCode(game_code *Result, FILETIME WriteTime)
{
CopyFile(Result->DLLPath, Result->TempDLLPath, 0);

Result->LastWriteTime = WriteTime;
Result->CodeDLL = LoadLibrary(Result->TempDLLPath);

if (!Result->CodeDLL)
Result->IsValid = false;
else
{
Result->GameGetInfo = (game_get_info *)
GetProcAddress(Result->CodeDLL, "GameGetInfo");

Result->GameUpdateAndRender = (game_update_and_render *)
GetProcAddress(Result->CodeDLL, "GameUpdateAndRender");

Result->GameInitialize = (game_initialize *)
GetProcAddress(Result->CodeDLL, "GameInitialize");

Result->GameOutputSound = (game_output_sound *)
GetProcAddress(Result->CodeDLL, "GameOutputSound");

Result->IsValid =
Result->GameUpdateAndRender &&
Result->GameInitialize &&
Result->GameGetInfo &&
Result->GameOutputSound;
}

if (!Result->IsValid)
{
Result->GameUpdateAndRender = GameUpdateAndRenderStub;
Result->GameInitialize = GameInitializeStub;
Result->GameGetInfo = GameGetInfoStub;
Result->GameOutputSound = GameOutputSoundStub;
}
}

// Win32 Game Loop
while (!Win32State.Done)
{
FILETIME DLLWriteTime = GetFileWriteTime(GameCode.DLLPath);
if (CompareFileTime(&DLLWriteTime, &GameCode.LastWriteTime) != 0)
{
//TODO: Find out why we're loading twice
Win32UnloadGameCode(&GameCode);
Win32LoadGameCode(&GameCode, DLLWriteTime);
}
// ...
}
[/Code]

Hmm, looking at this code now, I see I already have a TODO that the game's code loading twice when I recompile, not sure if that's something related to the problem but I guess I have to address that too.

Appreciate any help!

Thanks!
elxenoanizd/vexe

Edited by vexe on
How does your build.bat look like? Do you have code for locking game reload while pdb file is created?

It might be the case described in Day 39: https://hero.handmadedev.org/videos/game-architecture/day039.html (Fixing live code loading 0:52:38)

Basically Visual studio first generates dll, and your game notices that and loads it, but only after that Visual Studio creates pdb file. So when your game loads dll file Visual Studio debugger sees only old pdb file. New one is not yet created. That's why you don't see source information for dll.
Thanks a lot! I will watch that video.

This is my build:
[Code]
@echo off

pushd W:\Projects\Breakout\build

set LibDir="W:\lib"
set SrcDir="..\\src\\"

set CommonCompilerFlags=-MTd -nologo -fp:fast -Gm- -GR- -EHa- -Z7 -W3 -wd4996 -wd4201 -wd4100 -wd4189 -wd4505
set CommonLinkerFlags=-incremental:no -opt:ref

REM 32-bit build
REM cl %CommonCompilerFlags% W:\Projects\Breakout\src\Win32Platform.cpp /I %IncDir% /link -subsystem:windows,5.1 %CommonLinkerFlags% user32.lib gdi32.lib

REM Engine exe
cl %CommonCompilerFlags% ..\src\Win32Platform.cpp -FmWin32Platform.map /link %CommonLinkerFlags% user32.lib gdi32.lib

REM Game DLL
call %SrcDir%build_game.bat

REM Generator exe
cl %CommonCompilerFlags% ..\src\CodeGenerator.cpp

popd
[/Code]

And I have a separate batch just to build the game for quicker game recompilation:

[Code]
@echo off

pushd W:\Projects\Breakout\build

set LibDir="W:\lib"
set SrcDir="..\\src\\"
set Game=GLPlayground.cpp

del *.game.pdb

REM Game DLL
set PDBName=Breakout_%RANDOM%.game.pdb
set ExportGameFunctions=/EXPORT:"GameInitialize" /EXPORT:"GameUpdateAndRender" /EXPORT:"GameGetInfo" /EXPORT:"GameOutputSound"
cl -Zi ..\src\%Game% /LD /link %ExportGameFunctions% -PDB:%PDBName%

popd

[/Code]

Edited by vexe on
Yeah, it definitely looks like problem Casey explained there on the stream.

You can easily check that by putting Sleep(5000); before call to Win32LoadGameCode function. Then pdb should generate before you load dll file and all symbol info should be available.
Awesome! Did I tell you before you're a life saver?

Sleep(300) worked for me.
No problem :)
You should understand that this is not a 100% fix. Sometimes when VS will take >300msec to generate pdb file, your dll will still load before pdb is created. Watch day 39 for much better solution. It's a pretty simple change.

Edited by Mārtiņš Možeiko on
Hmm, with the sleep solution, it's still reloading twice. I put a Log after the sleep to see how many times it's reloading. It shows two messages. I also see messages from VS itself (I get those twice)

[Code]
'Win32Platform.exe' (Win32): Unloaded 'W:\Projects\Breakout\build\GLPlayground_temp.dll'
'Win32Platform.exe' (Win32): Loaded 'W:\Projects\Breakout\build\GLPlayground_temp.dll'. Symbols loaded.
[/Code]

I guess I'll watch day 39 and see if it addresses this issue as well. I don't know why it's happening though...

Edited by vexe on