From 36c9ef132d9baa13d30d2fe5569401a1dc1b328f Mon Sep 17 00:00:00 2001 From: Patedam Date: Thu, 23 Jul 2026 16:44:42 -0400 Subject: [PATCH] updates build_system.cpp to be more independant --- misc/build.bat | 237 ++---- tools/{build_check.cpp => build_system.cpp} | 774 ++++++++++---------- 2 files changed, 462 insertions(+), 549 deletions(-) rename tools/{build_check.cpp => build_system.cpp} (54%) diff --git a/misc/build.bat b/misc/build.bat index c1abe85..ade4e44 100644 --- a/misc/build.bat +++ b/misc/build.bat @@ -3,16 +3,16 @@ setlocal enabledelayedexpansion :: ------------------------------------------------------------------------------ :: Unity Build Script (misc/build.bat) -:: Step 1: Use FASTBuild to generate unity .cpp files directly in Intermediate/ -:: Step 2: Invoke compiler directly on target unity files +:: Step 1: Generate build_plan.txt for all configurations +:: Step 2: Invoke build.exe to execute the plan :: ------------------------------------------------------------------------------ set SCRIPT_DIR=%~dp0 cd /d "%SCRIPT_DIR%.." set FBUILD=misc\fbuild.exe -set CHECK_TOOL=misc\build_check.exe -set CHECK_SRC=tools\build_check.cpp +set BUILD_TOOL=misc\build_system.exe +set BUILD_SRC=tools\build.cpp set TARGET_JULIET=0 set TARGET_ROMEO=0 @@ -42,8 +42,6 @@ if !CONFIG_SPECIFIED! equ 0 set CONFIG_DEBUG=1& if !TARGET_SPECIFIED! equ 0 set if !TARGET_SPECIFIED! equ 0 set TARGET_JULIET=1& set TARGET_GAME=1& set TARGET_ROMEO=1& set TARGET_SHADER=1 :start_build -if exist "Intermediate\built_outputs.tmp" del /f /q "Intermediate\built_outputs.tmp" >nul 2>&1 - if not exist "%FBUILD%" ( echo [BUILD FAILED] Could not find %FBUILD%. exit /b 1 @@ -61,87 +59,78 @@ if !ERRORLEVEL! neq 0 ( ) ) -:: Check if build_check.exe needs to be compiled (missing, version changed, or source changed) -set CHECK_TOOL_VER=3 -set NEED_RECOMPILE_CHECK_TOOL=0 -if not exist "%CHECK_TOOL%" ( - set NEED_RECOMPILE_CHECK_TOOL=1 +:: Check if build.exe needs to be compiled (missing, version changed, or source changed) +set BUILD_TOOL_VER=4 +set NEED_RECOMPILE_BUILD_TOOL=0 +if not exist "%BUILD_TOOL%" ( + set NEED_RECOMPILE_BUILD_TOOL=1 ) else ( set "CURR_VER=" - if exist "Intermediate\build_check.ver" ( - for /f "usebackq delims=" %%I in ("Intermediate\build_check.ver") do set "CURR_VER=%%I" + if exist "Intermediate\build_tool.ver" ( + for /f "usebackq delims=" %%I in ("Intermediate\build_tool.ver") do set "CURR_VER=%%I" ) - if not "!CURR_VER!"=="!CHECK_TOOL_VER!" set NEED_RECOMPILE_CHECK_TOOL=1 + if not "!CURR_VER!"=="!BUILD_TOOL_VER!" set NEED_RECOMPILE_BUILD_TOOL=1 set "SRC_TIME=" - for %%I in ("%CHECK_SRC%") do set "SRC_TIME=%%~tI" + for %%I in ("%BUILD_SRC%") do set "SRC_TIME=%%~tI" set "STAMP_TIME=" - if exist "Intermediate\build_check.stamp" ( - for /f "usebackq delims=" %%I in ("Intermediate\build_check.stamp") do set "STAMP_TIME=%%I" + if exist "Intermediate\build_tool.stamp" ( + for /f "usebackq delims=" %%I in ("Intermediate\build_tool.stamp") do set "STAMP_TIME=%%I" ) - if not "!SRC_TIME!"=="!STAMP_TIME!" set NEED_RECOMPILE_CHECK_TOOL=1 + if not "!SRC_TIME!"=="!STAMP_TIME!" set NEED_RECOMPILE_BUILD_TOOL=1 ) -if !NEED_RECOMPILE_CHECK_TOOL! equ 1 ( - if exist "Intermediate\build_check.stamp" del /f /q "Intermediate\build_check.stamp" - if exist "Intermediate\build_check.ver" del /f /q "Intermediate\build_check.ver" - if exist "%CHECK_TOOL%" ( - del /f /q "%CHECK_TOOL%" >nul 2>&1 - if exist "%CHECK_TOOL%" ( - echo [BUILD FAILED] Could not overwrite %CHECK_TOOL%. It may be in use by another process. +if !NEED_RECOMPILE_BUILD_TOOL! equ 1 ( + if exist "Intermediate\build_tool.stamp" del /f /q "Intermediate\build_tool.stamp" + if exist "Intermediate\build_tool.ver" del /f /q "Intermediate\build_tool.ver" + if exist "%BUILD_TOOL%" ( + del /f /q "%BUILD_TOOL%" >nul 2>&1 + if exist "%BUILD_TOOL%" ( + echo [BUILD FAILED] Could not overwrite %BUILD_TOOL%. It may be in use by another process. exit /b 1 ) ) - echo [BUILD] Compiling fast native helper tool [tools\build_check.cpp -^> misc\build_check.exe]... - %COMPILER% /nologo /std:c++20 /MT /O2 /EHa- /W4 "%CHECK_SRC%" /Fe"%CHECK_TOOL%" + echo [BUILD] Compiling fast native build orchestrator [tools\build.cpp -^> misc\build.exe]... + %COMPILER% /nologo /std:c++20 /MT /O2 /EHa- /W4 "%BUILD_SRC%" /Fe"%BUILD_TOOL%" if !ERRORLEVEL! neq 0 ( - echo [BUILD FAILED] Could not compile build helper tool. + echo [BUILD FAILED] Could not compile build orchestrator. exit /b 1 ) - if not exist "%CHECK_TOOL%" ( - echo [BUILD FAILED] Compilation failed to produce %CHECK_TOOL%. + if not exist "%BUILD_TOOL%" ( + echo [BUILD FAILED] Compilation failed to produce %BUILD_TOOL%. exit /b 1 ) - "%CHECK_TOOL%" check_alive >nul 2>&1 + "%BUILD_TOOL%" check_alive >nul 2>&1 if !ERRORLEVEL! neq 0 ( - echo [BUILD FAILED] %CHECK_TOOL% was built but failed to execute ^(missing DLL or AV block^). + echo [BUILD FAILED] %BUILD_TOOL% was built but failed to execute ^(missing DLL or AV block^). exit /b 1 ) if not exist "Intermediate" mkdir "Intermediate" - (echo !CHECK_TOOL_VER!)>"Intermediate\build_check.ver" - for %%I in ("%CHECK_SRC%") do (echo %%~tI)>"Intermediate\build_check.stamp" + (echo !BUILD_TOOL_VER!)>"Intermediate\build_tool.ver" + for %%I in ("%BUILD_SRC%") do (echo %%~tI)>"Intermediate\build_tool.stamp" ) -"%CHECK_TOOL%" start_build -if !ERRORLEVEL! neq 0 ( - echo [BUILD FAILED] %CHECK_TOOL% start_build failed with exit code !ERRORLEVEL!. - exit /b 1 -) +echo [BUILD] Generating Build Plan... +set PLAN_FILE=Intermediate\build_plan.txt +if exist "!PLAN_FILE!" del /f /q "!PLAN_FILE!" -if !CONFIG_DEBUG! equ 1 call :build_config Debug || exit /b !ERRORLEVEL! -if !CONFIG_PROFILE! equ 1 call :build_config Profile || exit /b !ERRORLEVEL! -if !CONFIG_RELEASE! equ 1 call :build_config Release || exit /b !ERRORLEVEL! +if !CONFIG_DEBUG! equ 1 call :emit_config Debug || exit /b !ERRORLEVEL! +if !CONFIG_PROFILE! equ 1 call :emit_config Profile || exit /b !ERRORLEVEL! +if !CONFIG_RELEASE! equ 1 call :emit_config Release || exit /b !ERRORLEVEL! -echo. -echo ============================================================================== -echo [BUILD SUMMARY] -echo ============================================================================== echo Compiler Used : %COMPILER% -"%CHECK_TOOL%" finish_build -echo ============================================================================== -echo [ALL BUILDS SUCCEEDED] All requested targets processed successfully. -echo ============================================================================== -exit /b 0 +"%BUILD_TOOL%" run_plan "!PLAN_FILE!" +exit /b !ERRORLEVEL! :: ------------------------------------------------------------------------------ -:: Build Configuration Subroutine +:: Build Configuration Plan Generator Subroutine :: ------------------------------------------------------------------------------ -:build_config +:emit_config set "CFG=%~1" -echo. -echo ============================================================================== -echo Generating Unity Files into Intermediate/ via FASTBuild [%CFG%]... -echo ============================================================================== +if not exist "bin\x64-!CFG!" mkdir "bin\x64-!CFG!" +if not exist "Intermediate\x64-!CFG!" mkdir "Intermediate\x64-!CFG!" + +echo CONFIG !CFG!>>"!PLAN_FILE!" set FASTBUILD_TARGETS=Juliet-Unity if /i not "!CFG!"=="Release" set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! ImGui-Unity @@ -150,60 +139,7 @@ if !TARGET_GAME! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! Game-Unity if !TARGET_ROMEO! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! Romeo-Unity if !TARGET_SHADER! equ 1 set FASTBUILD_TARGETS=!FASTBUILD_TARGETS! JulietShaderCompiler-Unity -"%CHECK_TOOL%" start_step "FASTBuild Unity Gen [!CFG!]" -"%FBUILD%" !FASTBUILD_TARGETS! -set "FBUILD_ERR=!ERRORLEVEL!" -"%CHECK_TOOL%" end_step -if !FBUILD_ERR! neq 0 ( - echo [BUILD FAILED] FASTBuild failed to generate unity files for %CFG%. - exit /b !FBUILD_ERR! -) - -:: Evaluate all target needs in a single fast native pass (<5ms) -"%CHECK_TOOL%" start_step "Config Evaluation [!CFG!]" -"%CHECK_TOOL%" evaluate "!CFG!" "!TARGET_JULIET!" "!TARGET_GAME!" "!TARGET_ROMEO!" "!TARGET_SHADER!" -if !ERRORLEVEL! neq 0 ( - echo [BUILD FAILED] %CHECK_TOOL% evaluate failed with exit code !ERRORLEVEL!. - exit /b 1 -) -"%CHECK_TOOL%" end_step - -set FASTBUILD_UNITY_CHANGED=0 -set JULIET_NEED_COMPILE=0 -set IMGUI_NEED_COMPILE=0 -set GAME_NEED_COMPILE=0 -set JULIETAPP_NEED_COMPILE=0 -set ROMEO_NEED_COMPILE=0 -set SHADER_NEED_COMPILE=0 - -if exist "Intermediate\config_status.tmp" ( - for /f "usebackq tokens=1,2 delims==" %%A in ("Intermediate\config_status.tmp") do set %%A=%%B - del /f /q "Intermediate\config_status.tmp" -) - -if !FASTBUILD_UNITY_CHANGED! equ 1 ( - echo [FASTBuild] Unity structure or source file list changed. -) else ( - echo [FASTBuild] No Unity file structure changes detected [up-to-date]. -) - -set ANY_NEED_BUILD=0 -for %%T in (JULIET IMGUI GAME JULIETAPP ROMEO SHADER) do ( - if !%%T_NEED_COMPILE! equ 1 set ANY_NEED_BUILD=1 -) - -if !ANY_NEED_BUILD! equ 0 ( - echo [SKIP / UP-TO-DATE] All requested targets in [%CFG%] are up-to-date. - exit /b 0 -) - -echo. -echo ============================================================================== -echo Compiling Unity Files directly via %COMPILER% [%CFG%]... -echo ============================================================================== - -if not exist "bin\x64-!CFG!" mkdir "bin\x64-!CFG!" -if not exist "Intermediate\x64-!CFG!" mkdir "Intermediate\x64-!CFG!" +echo FASTBUILD !FASTBUILD_TARGETS!>>"!PLAN_FILE!" set COMMON_FLAGS=/nologo /std:c++20 /W4 /EHa- /utf-8 /DUNICODE /D_UNICODE /DWIN32_LEAN_AND_MEAN /D_CRT_SECURE_NO_WARNINGS /I"Juliet/include" /I"Juliet/src" /I"Game" /I"External/imgui" /I"External/imgui/backends" /DJULIET_WIN32 /wd5267 /wd4061 /wd4505 /wd4514 /wd4577 /wd4625 /wd4710 /wd4711 /wd4746 /wd4820 /wd5045 /wd5220 /wd5245 /wd4626 /wd5026 /wd5027 /wd4530 @@ -220,24 +156,13 @@ if /i "!CFG!"=="Debug" ( set COMMON_LIBS=kernel32.lib user32.lib gdi32.lib dxguid.lib Ws2_32.lib dxgi.lib imm32.lib dwmapi.lib d3dcompiler.lib shell32.lib winhttp.lib delayimp.lib -:: --- Juliet Shared Objs --- -echo. -echo --- Compiling Shared Object Files (ImGui) [%CFG%] --- -:: --- ImGui Shared Objs --- if defined IMGUI_UNITY_SRCS ( - if !IMGUI_NEED_COMPILE! equ 0 ( - echo [SKIP / UP-TO-DATE] Intermediate\x64-!CFG!\ImGui_Unity*.obj [Unity files unchanged] - ) else ( - echo [REBUILDING] Compiling Intermediate\x64-!CFG!\ImGui_Unity*.obj... - "%CHECK_TOOL%" start_step "Compiling ImGui Shared Objs [!CFG!]" - %COMPILER% %COMPILER_FLAGS% /c !IMGUI_UNITY_SRCS! /Fo"Intermediate\x64-!CFG!\\" - set "COMP_ERR=!ERRORLEVEL!" - "%CHECK_TOOL%" end_step - if !COMP_ERR! neq 0 exit /b !COMP_ERR! - ) + echo STEP Compiling ImGui Shared Objs [!CFG!]>>"!PLAN_FILE!" + echo OUTPUT Intermediate\x64-!CFG!\ImGui_Unity1.obj>>"!PLAN_FILE!" + echo DEPENDS External\imgui>>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /c !IMGUI_UNITY_SRCS! /Fo"Intermediate\x64-!CFG!\\">>"!PLAN_FILE!" ) -set JULIET_OBJS=Intermediate\x64-!CFG!\Juliet_Unity*.obj set IMGUI_OBJS= if defined IMGUI_UNITY_SRCS set IMGUI_OBJS=Intermediate\x64-!CFG!\ImGui_Unity*.obj @@ -246,61 +171,41 @@ if !TARGET_JULIET! equ 1 set BUILD_GAME_DLL=1 if !TARGET_GAME! equ 1 set BUILD_GAME_DLL=1 :: --- Juliet.dll --- -call :link_target "Juliet.dll" "Building Juliet.dll [!CFG!]" "!JULIET_NEED_COMPILE!" "%COMPILER_FLAGS% /DJULIET_EXPORT /LD" "Intermediate\Juliet\*.cpp %IMGUI_OBJS%" "/link %COMMON_LIBS% /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Juliet.ilk /PDB:Intermediate\x64-!CFG!\Juliet.pdb" -if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! +echo STEP Building Juliet.dll [!CFG!]>>"!PLAN_FILE!" +echo OUTPUT bin\x64-!CFG!\Juliet.dll>>"!PLAN_FILE!" +echo DEPENDS Juliet^|External\imgui>>"!PLAN_FILE!" +echo COMMAND %COMPILER% %COMPILER_FLAGS% /DJULIET_EXPORT /LD /Fe"bin\x64-!CFG!\Juliet.dll" Intermediate\Juliet\*.cpp %IMGUI_OBJS% /link %COMMON_LIBS% /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Juliet.ilk /PDB:Intermediate\x64-!CFG!\Juliet.pdb>>"!PLAN_FILE!" :: --- Game.dll --- if !BUILD_GAME_DLL! equ 1 ( - call :link_target "Game.dll" "Building Game.dll [!CFG!]" "!GAME_NEED_COMPILE!" "%COMPILER_FLAGS% /DJULIET_EXPORT /LD" "Intermediate\Game\*.cpp %IMGUI_OBJS%" "/link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Game.ilk /PDB:Intermediate\x64-!CFG!\Game.pdb" - if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! + echo STEP Building Game.dll [!CFG!]>>"!PLAN_FILE!" + echo OUTPUT bin\x64-!CFG!\Game.dll>>"!PLAN_FILE!" + echo DEPENDS Game^|Juliet^|External\imgui>>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /DJULIET_EXPORT /LD /Fe"bin\x64-!CFG!\Game.dll" Intermediate\Game\*.cpp %IMGUI_OBJS% /link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Game.ilk /PDB:Intermediate\x64-!CFG!\Game.pdb>>"!PLAN_FILE!" ) :: --- JulietApp.exe --- if !TARGET_JULIET! equ 1 ( - call :link_target "JulietApp.exe" "Building JulietApp.exe [!CFG!]" "!JULIETAPP_NEED_COMPILE!" "%COMPILER_FLAGS%" "Intermediate\JulietApp\*.cpp %IMGUI_OBJS%" "/link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\JulietApp.ilk /PDB:Intermediate\x64-!CFG!\JulietApp.pdb" - if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! + echo STEP Building JulietApp.exe [!CFG!]>>"!PLAN_FILE!" + echo OUTPUT bin\x64-!CFG!\JulietApp.exe>>"!PLAN_FILE!" + echo DEPENDS JulietApp^|Game^|Juliet^|External\imgui>>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /Fe"bin\x64-!CFG!\JulietApp.exe" Intermediate\JulietApp\*.cpp %IMGUI_OBJS% /link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\JulietApp.ilk /PDB:Intermediate\x64-!CFG!\JulietApp.pdb>>"!PLAN_FILE!" ) :: --- Romeo.exe --- if !TARGET_ROMEO! equ 1 ( - call :link_target "Romeo.exe" "Building Romeo.exe [!CFG!]" "!ROMEO_NEED_COMPILE!" "%COMPILER_FLAGS%" "Intermediate\Romeo\*.cpp %IMGUI_OBJS%" "/link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Romeo.ilk /PDB:Intermediate\x64-!CFG!\Romeo.pdb" - if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! + echo STEP Building Romeo.exe [!CFG!]>>"!PLAN_FILE!" + echo OUTPUT bin\x64-!CFG!\Romeo.exe>>"!PLAN_FILE!" + echo DEPENDS Romeo^|Juliet^|External\imgui>>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /Fe"bin\x64-!CFG!\Romeo.exe" Intermediate\Romeo\*.cpp %IMGUI_OBJS% /link %COMMON_LIBS% bin\x64-!CFG!\Juliet.lib /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\Romeo.ilk /PDB:Intermediate\x64-!CFG!\Romeo.pdb>>"!PLAN_FILE!" ) :: --- JulietShaderCompiler.exe --- if !TARGET_SHADER! equ 1 ( - if exist "Intermediate\JulietShaderCompiler\*.cpp" ( - call :link_target "JulietShaderCompiler.exe" "Building JulietShaderCompiler.exe [!CFG!]" "!SHADER_NEED_COMPILE!" "%COMPILER_FLAGS% /IJulietShaderCompiler" "Intermediate\JulietShaderCompiler\*.cpp %IMGUI_OBJS%" "/link %COMMON_LIBS% dxcompiler.lib /DELAYLOAD:dxcompiler.dll /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\JulietShaderCompiler.ilk /PDB:Intermediate\x64-!CFG!\JulietShaderCompiler.pdb" - if !ERRORLEVEL! neq 0 exit /b !ERRORLEVEL! - ) + echo STEP Building JulietShaderCompiler.exe [!CFG!]>>"!PLAN_FILE!" + echo OUTPUT bin\x64-!CFG!\JulietShaderCompiler.exe>>"!PLAN_FILE!" + echo DEPENDS JulietShaderCompiler^|Juliet^|External\imgui>>"!PLAN_FILE!" + echo COMMAND %COMPILER% %COMPILER_FLAGS% /IJulietShaderCompiler /Fe"bin\x64-!CFG!\JulietShaderCompiler.exe" Intermediate\JulietShaderCompiler\*.cpp %IMGUI_OBJS% /link %COMMON_LIBS% dxcompiler.lib /DELAYLOAD:dxcompiler.dll /SUBSYSTEM:CONSOLE /INCREMENTAL /ILK:Intermediate\x64-!CFG!\JulietShaderCompiler.ilk /PDB:Intermediate\x64-!CFG!\JulietShaderCompiler.pdb>>"!PLAN_FILE!" ) exit /b 0 - -:: ------------------------------------------------------------------------------ -:: Helper Subroutine: Link / Build Target Binary -:: ------------------------------------------------------------------------------ -:link_target -set "TARGET_NAME=%~1" -set "STEP_TITLE=%~2" -set "NEED_COMPILE=%~3" -set "EXTRA_FLAGS=%~4" -set "SOURCES_AND_OBJS=%~5" -set "LINK_FLAGS=%~6" - -echo. -echo --- Building %TARGET_NAME% [%CFG%] --- -if "%NEED_COMPILE%"=="0" ( - echo [SKIP / UP-TO-DATE] bin\x64-!CFG!\%TARGET_NAME% [Binary up to date, skipping compilation] - exit /b 0 -) - -echo [REBUILDING] Compiling bin\x64-!CFG!\%TARGET_NAME%... -"%CHECK_TOOL%" start_step "%STEP_TITLE%" -%COMPILER% %EXTRA_FLAGS% /Fe"bin\x64-!CFG!\%TARGET_NAME%" %SOURCES_AND_OBJS% %LINK_FLAGS% -set "COMP_ERR=!ERRORLEVEL!" -"%CHECK_TOOL%" end_step -if !COMP_ERR! neq 0 exit /b !COMP_ERR! - -echo bin\x64-!CFG!\%TARGET_NAME%>>Intermediate\built_outputs.tmp -exit /b 0 diff --git a/tools/build_check.cpp b/tools/build_system.cpp similarity index 54% rename from tools/build_check.cpp rename to tools/build_system.cpp index 5e88991..88cc177 100644 --- a/tools/build_check.cpp +++ b/tools/build_system.cpp @@ -1,5 +1,5 @@ -// tools/build_check.cpp - Fast native C++ build helper tool for Juliet project -// Replaces all PowerShell scripts (build_helper.ps1, check_target.ps1, clean_unity.ps1, summary_helper.ps1) +// tools/build.cpp - Fast native C++ build orchestrator for Juliet project +// Replaces all PowerShell scripts and orchestrates the full build process #ifndef NOMINMAX #define NOMINMAX #endif @@ -604,417 +604,433 @@ static void CollectUnityFiles(const char* dirPath, FilePathList& list) // Commands // ============================================================================ -static int CommandStartBuild() -{ - EnsureDirectoryExists("Intermediate"); +struct BuildStep { + char StepName[256]; + char OutputFile[MaxPath]; + char Depends[MaxPath]; + char Command[MaxFiles]; +}; - DeleteFileA("Intermediate\\step_start.tmp"); +struct BuildConfig { + char Name[64]; + char FastBuildTargets[512]; + BuildStep Steps[32]; + int StepCount; +}; + +static int CommandRunPlan(int argc, char* argv[]) +{ + if (argc < 3) + { + printf("[ERROR] Usage: build_system run_plan \n"); + return 1; + } + const char* planFile = argv[2]; + + FileContent planContent = ReadEntireFile(planFile); + if (!planContent.Data) + { + printf("[ERROR] Could not read build plan: %s\n", planFile); + return 1; + } + + EnsureDirectoryExists("Intermediate"); DeleteFileA("Intermediate\\step_timings.tmp"); + DeleteFileA("Intermediate\\built_outputs.tmp"); - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ULARGE_INTEGER li; - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; + LARGE_INTEGER perfStart, perfEnd, perfFreq; + QueryPerformanceCounter(&perfStart); + QueryPerformanceFrequency(&perfFreq); - char buf[32]; - sprintf_s(buf, "%llu", li.QuadPart); - WriteEntireFile("Intermediate\\build_start.tmp", buf, static_cast(strlen(buf))); - return 0; -} - -static int CommandStartStep(int argc, char* argv[]) -{ - assert(argv != nullptr); - EnsureDirectoryExists("Intermediate"); - - const char* stepName = (argc > 2 && argv[2] != nullptr) ? argv[2] : "Unnamed Step"; - - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ULARGE_INTEGER li; - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - - char buf[MaxPath + 64]; - int len = sprintf_s(buf, "%s\n%llu\n", stepName, li.QuadPart); - if (len > 0) + // Parse plan file + BuildConfig configs[4] = {}; + int configCount = 0; + + const char* pos = planContent.Data; + while (*pos != '\0') { - WriteEntireFile("Intermediate\\step_start.tmp", buf, static_cast(len)); - } - return 0; -} - -static int CommandEndStep(int argc, char* argv[]) -{ - assert(argv != nullptr); - if (!FileExists("Intermediate\\step_start.tmp")) - { - return 0; - } - - FileContent content = ReadEntireFile("Intermediate\\step_start.tmp"); - if (content.Data == nullptr) - { - return 0; - } - - char stepName[MaxPath] = "Unnamed Step"; - uint64_t startTicks = 0; - - const char* line1End = strchr(content.Data, '\n'); - if (line1End != nullptr) - { - int nameLen = static_cast(line1End - content.Data); - if (nameLen > 0 && nameLen < MaxPath) + const char* lineStart = pos; + while (*pos != '\0' && *pos != '\n' && *pos != '\r') pos++; + int lineLen = static_cast(pos - lineStart); + + if (lineLen > 0) { - memcpy(stepName, content.Data, static_cast(nameLen)); - stepName[nameLen] = '\0'; - } - sscanf_s(line1End + 1, "%llu", &startTicks); - } - FreeFileContent(content); - DeleteFileA("Intermediate\\step_start.tmp"); - - if (argc > 2 && argv[2] != nullptr && argv[2][0] != '\0') - { - strncpy_s(stepName, argv[2], MaxPath - 1); - } - - FILETIME ftNow; - GetSystemTimeAsFileTime(&ftNow); - ULARGE_INTEGER nowLi; - nowLi.LowPart = ftNow.dwLowDateTime; - nowLi.HighPart = ftNow.dwHighDateTime; - - double elapsedSeconds = static_cast(nowLi.QuadPart - startTicks) / 10000000.0; - - char appendBuf[MaxPath + 64]; - int appendLen = sprintf_s(appendBuf, "%s|%.3fs\n", stepName, elapsedSeconds); - if (appendLen > 0) - { - FileContent existing = ReadEntireFile("Intermediate\\step_timings.tmp"); - DWORD newSize = static_cast(appendLen) + existing.Size; - char* combined = static_cast(HeapAlloc(GetProcessHeap(), 0, newSize + 1)); - if (combined != nullptr) - { - DWORD offset = 0; - if (existing.Data != nullptr && existing.Size > 0) + if (lineLen > 7 && memcmp(lineStart, "CONFIG ", 7) == 0) { - memcpy(combined, existing.Data, existing.Size); - offset = existing.Size; + if (configCount < 4) + { + int nLen = lineLen - 7; + if (nLen >= static_cast(sizeof(configs[configCount].Name))) nLen = static_cast(sizeof(configs[configCount].Name)) - 1; + memcpy(configs[configCount].Name, lineStart + 7, nLen); + configs[configCount].Name[nLen] = '\0'; + configCount++; + } } - memcpy(combined + offset, appendBuf, static_cast(appendLen)); - combined[newSize] = '\0'; - WriteEntireFile("Intermediate\\step_timings.tmp", combined, newSize); - HeapFree(GetProcessHeap(), 0, combined); - } - FreeFileContent(existing); - } - - return 0; -} - -static int CommandFinishBuild() -{ - // Compute elapsed time - const char* elapsedStr = "0.000s"; - char elapsedBuf[64] = {}; - - if (FileExists("Intermediate\\build_start.tmp")) - { - FileContent startContent = ReadEntireFile("Intermediate\\build_start.tmp"); - if (startContent.Data != nullptr) - { - uint64_t startTicks = 0; - sscanf_s(startContent.Data, "%llu", &startTicks); - FreeFileContent(startContent); - - FILETIME ftNow; - GetSystemTimeAsFileTime(&ftNow); - ULARGE_INTEGER nowLi; - nowLi.LowPart = ftNow.dwLowDateTime; - nowLi.HighPart = ftNow.dwHighDateTime; - - double elapsedSeconds = static_cast(nowLi.QuadPart - startTicks) / 10000000.0; - - if (elapsedSeconds < 60.0) + else if (configCount > 0) { - sprintf_s(elapsedBuf, "%.3fs", elapsedSeconds); + BuildConfig& curCfg = configs[configCount - 1]; + if (lineLen > 10 && memcmp(lineStart, "FASTBUILD ", 10) == 0) + { + int nLen = lineLen - 10; + if (nLen >= static_cast(sizeof(curCfg.FastBuildTargets))) nLen = static_cast(sizeof(curCfg.FastBuildTargets)) - 1; + memcpy(curCfg.FastBuildTargets, lineStart + 10, nLen); + curCfg.FastBuildTargets[nLen] = '\0'; + } + else if (lineLen > 5 && memcmp(lineStart, "STEP ", 5) == 0) + { + if (curCfg.StepCount < 32) + { + int nLen = lineLen - 5; + if (nLen >= static_cast(sizeof(curCfg.Steps[curCfg.StepCount].StepName))) nLen = static_cast(sizeof(curCfg.Steps[curCfg.StepCount].StepName)) - 1; + memcpy(curCfg.Steps[curCfg.StepCount].StepName, lineStart + 5, nLen); + curCfg.Steps[curCfg.StepCount].StepName[nLen] = '\0'; + curCfg.StepCount++; + } + } + else if (lineLen > 7 && memcmp(lineStart, "OUTPUT ", 7) == 0 && curCfg.StepCount > 0) + { + int nLen = lineLen - 7; + if (nLen >= static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].OutputFile))) nLen = static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].OutputFile)) - 1; + memcpy(curCfg.Steps[curCfg.StepCount - 1].OutputFile, lineStart + 7, nLen); + curCfg.Steps[curCfg.StepCount - 1].OutputFile[nLen] = '\0'; + } + else if (lineLen > 8 && memcmp(lineStart, "DEPENDS ", 8) == 0 && curCfg.StepCount > 0) + { + int nLen = lineLen - 8; + if (nLen >= static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].Depends))) nLen = static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].Depends)) - 1; + memcpy(curCfg.Steps[curCfg.StepCount - 1].Depends, lineStart + 8, nLen); + curCfg.Steps[curCfg.StepCount - 1].Depends[nLen] = '\0'; + } + else if (lineLen > 8 && memcmp(lineStart, "COMMAND ", 8) == 0 && curCfg.StepCount > 0) + { + int nLen = lineLen - 8; + if (nLen >= static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].Command))) nLen = static_cast(sizeof(curCfg.Steps[curCfg.StepCount - 1].Command)) - 1; + memcpy(curCfg.Steps[curCfg.StepCount - 1].Command, lineStart + 8, nLen); + curCfg.Steps[curCfg.StepCount - 1].Command[nLen] = '\0'; + } + } + } + while (*pos == '\n' || *pos == '\r') pos++; + } + FreeFileContent(planContent); + + bool anyBuilt = false; + char timingsBuf[MaxFiles * 2] = {}; + int timingsLen = 0; + + auto AppendTiming = [&](const char* stepName, double secs) + { + timingsLen += sprintf_s(timingsBuf + timingsLen, sizeof(timingsBuf) - timingsLen, "%s|%.3fs\n", stepName, secs); + }; + + auto ExecuteCmd = [](const char* cmdLine) -> int + { + STARTUPINFOA si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi = {}; + DWORD exitCode = 1; + + char* cmdBuf = static_cast(HeapAlloc(GetProcessHeap(), 0, MaxFiles)); + if (!cmdBuf) return 1; + strcpy_s(cmdBuf, MaxFiles, cmdLine); + + if (CreateProcessA(nullptr, cmdBuf, nullptr, nullptr, TRUE, 0, nullptr, nullptr, &si, &pi)) + { + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exitCode); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + { + printf("[ERROR] Failed to execute command.\n"); + HeapFree(GetProcessHeap(), 0, cmdBuf); + return 1; + } + HeapFree(GetProcessHeap(), 0, cmdBuf); + return static_cast(exitCode); + }; + + for (int i = 0; i < configCount; i++) + { + BuildConfig& cfg = configs[i]; + printf("\n==============================================================================\n"); + printf("Generating Unity Files into Intermediate/ via FASTBuild [%s]...\n", cfg.Name); + printf("==============================================================================\n"); + + if (cfg.FastBuildTargets[0] != '\0') + { + char fbuildCmd[MaxPath]; + sprintf_s(fbuildCmd, sizeof(fbuildCmd), "misc\\fbuild.exe %s", cfg.FastBuildTargets); + + LARGE_INTEGER tStart, tEnd; + QueryPerformanceCounter(&tStart); + int res = ExecuteCmd(fbuildCmd); + QueryPerformanceCounter(&tEnd); + + char stepName[MaxPath]; + sprintf_s(stepName, sizeof(stepName), "FASTBuild Unity Gen [%s]", cfg.Name); + AppendTiming(stepName, static_cast(tEnd.QuadPart - tStart.QuadPart) / static_cast(perfFreq.QuadPart)); + + if (res != 0) + { + printf("[BUILD FAILED] FASTBuild failed for %s.\n", cfg.Name); + return res; + } + } + + HashCache oldCache; + LoadHashCache("Intermediate\\.unity_hashes_cache", oldCache); + + HashCache newCache; + bool unityChanged = false; + + FilePathList unityFiles; + CollectUnityFiles("Intermediate", unityFiles); + + if (unityFiles.Count == 0) + { + unityChanged = true; + } + else + { + for (int k = 0; k < unityFiles.Count; k++) + { + CleanResult cr = CleanAndHashUnityFile(unityFiles.Paths[k].Data); + newCache.Add(unityFiles.Paths[k].Data, cr.HashStr); + + const char* oldHash = oldCache.Find(unityFiles.Paths[k].Data); + if (oldHash == nullptr || strcmp(oldHash, cr.HashStr) != 0) + { + unityChanged = true; + } + } + } + SaveHashCache("Intermediate\\.unity_hashes_cache", newCache); + + if (unityChanged) + { + printf("[FASTBuild] Unity structure or source file list changed.\n"); + } + else + { + printf("[FASTBuild] No Unity file structure changes detected [up-to-date].\n"); + } + + printf("\n==============================================================================\n"); + printf("Compiling Targets [%s]...\n", cfg.Name); + printf("==============================================================================\n"); + + struct DirCacheEntry { FixedString Path; int64_t Time; }; + DirCacheEntry dirCache[64]; + int dirCacheCount = 0; + + auto GetDirTime = [&](const char* dir) -> int64_t + { + for (int k = 0; k < dirCacheCount; k++) + { + if (dirCache[k].Path.EqualsNoCase(dir)) return dirCache[k].Time; + } + int64_t t = GetNewestSourceTimeRecursive(dir); + if (dirCacheCount < 64) + { + dirCache[dirCacheCount].Path.Set(dir); + dirCache[dirCacheCount].Time = t; + dirCacheCount++; + } + return t; + }; + + bool anyNeedBuild = false; + + for (int j = 0; j < cfg.StepCount; j++) + { + BuildStep& step = cfg.Steps[j]; + int64_t maxTime = 0; + const char* cur = step.Depends; + while (*cur) + { + const char* nextPipe = strchr(cur, '|'); + char dirPath[MaxPath] = {}; + if (nextPipe) + { + int dLen = static_cast(nextPipe - cur); + if (dLen >= static_cast(sizeof(dirPath))) dLen = static_cast(sizeof(dirPath)) - 1; + memcpy(dirPath, cur, dLen); + dirPath[dLen] = '\0'; + cur = nextPipe + 1; + } + else + { + strcpy_s(dirPath, sizeof(dirPath), cur); + cur += strlen(cur); + } + if (dirPath[0] != '\0') + { + int64_t t = GetDirTime(dirPath); + if (t > maxTime) maxTime = t; + } + } + + bool needCompile = unityChanged; + if (!needCompile) + { + if (!FileExists(step.OutputFile)) + { + needCompile = true; + } + else + { + int64_t outTime = GetFileModTimeInt64(step.OutputFile); + if (outTime < maxTime) needCompile = true; + } + } + + printf("\n--- %s ---\n", step.StepName); + if (!needCompile) + { + printf("[SKIP / UP-TO-DATE] %s [Binary up to date]\n", step.OutputFile); } else { - int totalMs = static_cast(elapsedSeconds * 1000.0); - int hours = totalMs / 3600000; - int minutes = (totalMs % 3600000) / 60000; - int seconds = (totalMs % 60000) / 1000; - int ms = totalMs % 1000; - sprintf_s(elapsedBuf, "%02d:%02d:%02d.%03d", hours, minutes, seconds, ms); + printf("[REBUILDING] Compiling %s...\n", step.OutputFile); + anyNeedBuild = true; + + LARGE_INTEGER tStart, tEnd; + QueryPerformanceCounter(&tStart); + int res = ExecuteCmd(step.Command); + QueryPerformanceCounter(&tEnd); + + AppendTiming(step.StepName, static_cast(tEnd.QuadPart - tStart.QuadPart) / static_cast(perfFreq.QuadPart)); + + if (res != 0) + { + printf("[BUILD FAILED] Command failed with exit code %d.\n", res); + return res; + } + + char builtOut[MaxPath + 2]; + sprintf_s(builtOut, "%s\n", step.OutputFile); + + HANDLE hFile = CreateFileA("Intermediate\\built_outputs.tmp", FILE_APPEND_DATA, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD written = 0; + WriteFile(hFile, builtOut, static_cast(strlen(builtOut)), &written, nullptr); + CloseHandle(hFile); + } + anyBuilt = true; } - elapsedStr = elapsedBuf; } - DeleteFileA("Intermediate\\build_start.tmp"); - } - - if (FileExists("Intermediate\\step_timings.tmp")) - { - FileContent timingsContent = ReadEntireFile("Intermediate\\step_timings.tmp"); - if (timingsContent.Data != nullptr && timingsContent.Size > 0) + + if (!anyNeedBuild) { - printf("Step Timings:\n"); - const char* pos = timingsContent.Data; - while (*pos != '\0') - { - const char* lineStart = pos; - while (*pos != '\0' && *pos != '\n' && *pos != '\r') - { - pos++; - } - int lineLen = static_cast(pos - lineStart); - while (*pos == '\n' || *pos == '\r') - { - pos++; - } - - if (lineLen > 0) - { - const char* pipePos = nullptr; - for (const char* p = lineStart; p < lineStart + lineLen; p++) - { - if (*p == '|') - { - pipePos = p; - break; - } - } - - if (pipePos != nullptr) - { - char stepName[MaxPath] = {}; - int nameLen = static_cast(pipePos - lineStart); - if (nameLen < MaxPath) - { - memcpy(stepName, lineStart, static_cast(nameLen)); - stepName[nameLen] = '\0'; - } - - char durationStr[64] = {}; - int durLen = static_cast((lineStart + lineLen) - (pipePos + 1)); - if (durLen < 64) - { - memcpy(durationStr, pipePos + 1, static_cast(durLen)); - durationStr[durLen] = '\0'; - } - - printf(" - %-42s : %s\n", stepName, durationStr); - } - } - } - printf("------------------------------------------------------------------------------\n"); - FreeFileContent(timingsContent); + printf("\n[SKIP / UP-TO-DATE] All requested targets in [%s] are up-to-date.\n", cfg.Name); } - DeleteFileA("Intermediate\\step_timings.tmp"); } - printf("Total Duration : %s\n", elapsedStr); + if (timingsLen > 0) + { + WriteEntireFile("Intermediate\\step_timings.tmp", timingsBuf, timingsLen); + } + + QueryPerformanceCounter(&perfEnd); + double elapsedSeconds = static_cast(perfEnd.QuadPart - perfStart.QuadPart) / static_cast(perfFreq.QuadPart); + + char elapsedBuf[64]; + if (elapsedSeconds < 60.0) + { + sprintf_s(elapsedBuf, "%.3fs", elapsedSeconds); + } + else + { + int totalMs = static_cast(elapsedSeconds * 1000.0); + int hours = totalMs / 3600000; + int minutes = (totalMs % 3600000) / 60000; + int seconds = (totalMs % 60000) / 1000; + int ms = totalMs % 1000; + sprintf_s(elapsedBuf, "%02d:%02d:%02d.%03d", hours, minutes, seconds, ms); + } + + printf("\n==============================================================================\n"); + printf("[BUILD SUMMARY]\n"); + printf("==============================================================================\n"); + + if (timingsLen > 0) + { + printf("Step Timings:\n"); + const char* pos = timingsBuf; + while (*pos) + { + const char* lineStart = pos; + while (*pos && *pos != '\n') pos++; + int len = static_cast(pos - lineStart); + if (len > 0) + { + const char* pipe = strchr(lineStart, '|'); + if (pipe && pipe < pos) + { + char stepName[MaxPath] = {}; + int nameLen = static_cast(pipe - lineStart); + memcpy(stepName, lineStart, nameLen); + + char durStr[64] = {}; + int durLen = static_cast(pos - (pipe + 1)); + memcpy(durStr, pipe + 1, durLen); + + printf(" - %-42s : %s\n", stepName, durStr); + } + } + if (*pos == '\n') pos++; + } + printf("------------------------------------------------------------------------------\n"); + } + + printf("Total Duration : %s\n", elapsedBuf); printf("Output Binaries:\n"); - if (FileExists("Intermediate\\built_outputs.tmp")) + if (anyBuilt) { FileContent outputsContent = ReadEntireFile("Intermediate\\built_outputs.tmp"); - bool anyPrinted = false; - - if (outputsContent.Data != nullptr) + if (outputsContent.Data) { const char* pos = outputsContent.Data; - while (*pos != '\0') + while (*pos) { const char* lineStart = pos; - while (*pos != '\0' && *pos != '\n' && *pos != '\r') + while (*pos && *pos != '\n' && *pos != '\r') pos++; + int len = static_cast(pos - lineStart); + if (len > 0) { - pos++; - } - int lineLen = static_cast(pos - lineStart); - while (*pos == '\n' || *pos == '\r') - { - pos++; - } - - if (lineLen > 0) - { - char filePath[MaxPath]; - if (lineLen < MaxPath) + char filePath[MaxPath] = {}; + memcpy(filePath, lineStart, len); + WIN32_FILE_ATTRIBUTE_DATA fileData; + if (GetFileAttributesExA(filePath, GetFileExInfoStandard, &fileData)) { - memcpy(filePath, lineStart, static_cast(lineLen)); - filePath[lineLen] = '\0'; - - if (FileExists(filePath)) - { - WIN32_FILE_ATTRIBUTE_DATA fileData; - if (GetFileAttributesExA(filePath, GetFileExInfoStandard, &fileData)) - { - ULARGE_INTEGER fileSize; - fileSize.LowPart = fileData.nFileSizeLow; - fileSize.HighPart = fileData.nFileSizeHigh; - double sizeMB = static_cast(fileSize.QuadPart) / (1024.0 * 1024.0); - printf(" - %s (%.2f MB)\n", filePath, sizeMB); - anyPrinted = true; - } - } + ULARGE_INTEGER fileSize; + fileSize.LowPart = fileData.nFileSizeLow; + fileSize.HighPart = fileData.nFileSizeHigh; + double sizeMB = static_cast(fileSize.QuadPart) / (1024.0 * 1024.0); + printf(" - %s (%.2f MB)\n", filePath, sizeMB); } } + while (*pos == '\n' || *pos == '\r') pos++; } FreeFileContent(outputsContent); } - - if (!anyPrinted) - { - printf(" - None built in this session (all requested targets up-to-date)\n"); - } DeleteFileA("Intermediate\\built_outputs.tmp"); } else { printf(" - None built in this session (all requested targets up-to-date)\n"); } - + + printf("==============================================================================\n"); + printf("[ALL BUILDS SUCCEEDED] All requested targets processed successfully.\n"); + printf("==============================================================================\n"); fflush(stdout); - return 0; -} -static int CommandEvaluate(int argc, char* argv[]) -{ - LARGE_INTEGER perfStart, perfEnd, perfFreq; - QueryPerformanceCounter(&perfStart); - QueryPerformanceFrequency(&perfFreq); - - const char* cfg = (argc > 2) ? argv[2] : "Debug"; - bool targetJuliet = (argc > 3) && argv[3][0] == '1'; - bool targetGame = (argc > 4) && argv[4][0] == '1'; - bool targetRomeo = (argc > 5) && argv[5][0] == '1'; - bool targetShader = (argc > 6) && argv[6][0] == '1'; - - EnsureDirectoryExists("Intermediate"); - - // 1. Process unity files: clean #pragma message, compute hashes, detect changes - HashCache oldCache; - LoadHashCache("Intermediate\\.unity_hashes_cache", oldCache); - - HashCache newCache; - bool unityChanged = false; - - FilePathList unityFiles; - CollectUnityFiles("Intermediate", unityFiles); - - if (unityFiles.Count == 0) - { - unityChanged = true; - } - else - { - for (int i = 0; i < unityFiles.Count; i++) - { - CleanResult cr = CleanAndHashUnityFile(unityFiles.Paths[i].Data); - newCache.Add(unityFiles.Paths[i].Data, cr.HashStr); - - const char* oldHash = oldCache.Find(unityFiles.Paths[i].Data); - if (oldHash == nullptr || strcmp(oldHash, cr.HashStr) != 0) - { - unityChanged = true; - } - } - } - - SaveHashCache("Intermediate\\.unity_hashes_cache", newCache); - - // 2. Scan source directory modification times once - int64_t julietTime = GetNewestSourceTimeRecursive("Juliet"); - int64_t gameTime = GetNewestSourceTimeRecursive("Game"); - int64_t imguiTime = GetNewestSourceTimeRecursive("External\\imgui"); - int64_t appTime = GetNewestSourceTimeRecursive("JulietApp"); - int64_t romeoTime = GetNewestSourceTimeRecursive("Romeo"); - int64_t shaderTime = GetNewestSourceTimeRecursive("JulietShaderCompiler"); - - auto MaxTime = [](int64_t a, int64_t b) -> int64_t { return (a > b) ? a : b; }; - - int64_t julietCombined = MaxTime(julietTime, imguiTime); - int64_t gameCombined = MaxTime(MaxTime(julietTime, gameTime), imguiTime); - int64_t appCombined = MaxTime(MaxTime(MaxTime(julietTime, gameTime), appTime), imguiTime); - int64_t romeoCombined = MaxTime(MaxTime(julietTime, romeoTime), imguiTime); - int64_t shaderCombined = MaxTime(MaxTime(julietTime, shaderTime), imguiTime); - - // Build paths for target binaries - char binDir[MaxPath]; - char intDir[MaxPath]; - sprintf_s(binDir, "bin\\x64-%s", cfg); - sprintf_s(intDir, "Intermediate\\x64-%s", cfg); - - auto IsUpToDate = [](const char* targetPath, int64_t newestSourceTime) -> bool - { - assert(targetPath != nullptr); - if (!FileExists(targetPath)) - { - return false; - } - return GetFileModTimeInt64(targetPath) >= newestSourceTime; - }; - - char path[MaxPath]; - - sprintf_s(path, "%s\\ImGui_Unity1.obj", intDir); - bool imguiNeed = unityChanged || !IsUpToDate(path, imguiTime); - - sprintf_s(path, "%s\\Juliet.dll", binDir); - bool julietNeed = unityChanged || !IsUpToDate(path, julietCombined); - - bool gameNeed = false; - if (targetJuliet || targetGame) - { - sprintf_s(path, "%s\\Game.dll", binDir); - gameNeed = julietNeed || unityChanged || !IsUpToDate(path, gameCombined); - } - - bool julietAppNeed = false; - if (targetJuliet) - { - sprintf_s(path, "%s\\JulietApp.exe", binDir); - julietAppNeed = gameNeed || unityChanged || !IsUpToDate(path, appCombined); - } - - bool romeoNeed = false; - if (targetRomeo) - { - sprintf_s(path, "%s\\Romeo.exe", binDir); - romeoNeed = julietNeed || unityChanged || !IsUpToDate(path, romeoCombined); - } - - bool shaderNeed = false; - if (targetShader && DirectoryExists("Intermediate\\JulietShaderCompiler")) - { - sprintf_s(path, "%s\\JulietShaderCompiler.exe", binDir); - shaderNeed = julietNeed || unityChanged || !IsUpToDate(path, shaderCombined); - } - - QueryPerformanceCounter(&perfEnd); - double durationMs = - static_cast(perfEnd.QuadPart - perfStart.QuadPart) * 1000.0 / static_cast(perfFreq.QuadPart); - printf("[PERF] Fast Native C++ EvaluateConfig: %.1f ms\n", durationMs); - - // Write results - char statusBuf[512]; - int statusLen = sprintf_s(statusBuf, - "FASTBUILD_UNITY_CHANGED=%d\n" - "JULIET_NEED_COMPILE=%d\n" - "IMGUI_NEED_COMPILE=%d\n" - "GAME_NEED_COMPILE=%d\n" - "JULIETAPP_NEED_COMPILE=%d\n" - "ROMEO_NEED_COMPILE=%d\n" - "SHADER_NEED_COMPILE=%d\n", - unityChanged ? 1 : 0, julietNeed ? 1 : 0, imguiNeed ? 1 : 0, gameNeed ? 1 : 0, - julietAppNeed ? 1 : 0, romeoNeed ? 1 : 0, shaderNeed ? 1 : 0); - - WriteEntireFile("Intermediate\\config_status.tmp", statusBuf, static_cast(statusLen)); - fflush(stdout); return 0; } @@ -1026,24 +1042,16 @@ int main(int argc, char* argv[]) { if (argc < 2) { - printf("Usage: build_check [args...]\n"); + printf("Usage: build_system [args...]\n"); printf("Commands:\n"); - printf(" start_build Record build start timestamp\n"); - printf(" start_step Record start timestamp of a build step\n"); - printf(" end_step [] Record duration of current step\n"); - printf(" finish_build Print build summary (elapsed time, step timings, built binaries)\n"); - printf(" evaluate Evaluate rebuild needs\n"); + printf(" run_plan Run the build from a generated plan file\n"); printf(" check_alive Returns 0 immediately to test execution\n"); return 1; } const char* cmd = argv[1]; if (strcmp(cmd, "check_alive") == 0) return 0; - if (strcmp(cmd, "start_build") == 0) return CommandStartBuild(); - if (strcmp(cmd, "start_step") == 0) return CommandStartStep(argc, argv); - if (strcmp(cmd, "end_step") == 0) return CommandEndStep(argc, argv); - if (strcmp(cmd, "finish_build") == 0) return CommandFinishBuild(); - if (strcmp(cmd, "evaluate") == 0) return CommandEvaluate(argc, argv); + if (strcmp(cmd, "run_plan") == 0) return CommandRunPlan(argc, argv); printf("[ERROR] Unknown command: %s\n", cmd); return 1;