u3d-community / U3D

Open-source, cross-platform 2D and 3D game engine built in C++
https://u3d.io
MIT License
167 stars 29 forks source link

Infinite Loop in `script/cmake_generic.bat` #59

Open SirNate0 opened 10 months ago

SirNate0 commented 10 months ago

It is easy to reach an infinite loop when using the windows cmake scripts. For example, if you call script\cmake_vs2022.bat build -DURHO3D_HOME="C:\Path\To\U3D\Build", you will get such a loop, as cmake_generic.bat only recognizes -D options when they are followed by a space.

The loop

:loop
if not "%~1" == "" (
    if "%~1" == "-D" (
        if "%~2" == "MINGW" if "%~3" == "1" set "OPTS=-G "MinGW Makefiles""
        if "%~2" == "URHO3D_64BIT" if "%~3" == "1" set "arch=-A x64"
        if "%~2" == "URHO3D_64BIT" if "%~3" == "0" set "arch=-A Win32"
        set "BUILD_OPTS=%BUILD_OPTS% -D %~2=%~3"
        shift
        shift
        shift
    )
    if "%~1" == "-VS" (
        set "OPTS=-G "Visual Studio %~2" %arch% %TOOLSET%"
        shift
        shift
    )
    if "%~1" == "-G" (
        set "OPTS=%OPTS% -G %~2"
        shift
        shift
    )
    goto loop
)

should be changed to something like

:loop
if not "%~1" == "" (
    if "%~1" == "-D" (
        if "%~2" == "MINGW" if "%~3" == "1" set "OPTS=-G "MinGW Makefiles""
        if "%~2" == "URHO3D_64BIT" if "%~3" == "1" set "arch=-A x64"
        if "%~2" == "URHO3D_64BIT" if "%~3" == "0" set "arch=-A Win32"
        set "BUILD_OPTS=%BUILD_OPTS% -D %~2=%~3"
        shift
        shift
        shift
    )
    else if "%~1" == "-VS" (
        set "OPTS=-G "Visual Studio %~2" %arch% %TOOLSET%"
        shift
        shift
    )
    else if "%~1" == "-G" (
        set "OPTS=%OPTS% -G %~2"
        shift
        shift
    )
    else (
        set "OPTS=%OPTS% %~1"
        shift
    )
    goto loop
)

to prevent the possibility of endlessly looping on an unrecognized argument.

BlueMagnificent commented 10 months ago

Good observation. I ran into this somedays back while using Emcripten's emcmake which emits the CMAKE_TOOLCHAIN_FILE and CMAKE_CROSSCOMPILING_EMULATOR build options with no space after -D. I have a slightly different change I made to the loop section:

:loop
:: Cache the first argument so substring operation can be performed on it
set "ARG1=%~1"
if not "%~1" == "" (
    if "%~1" == "-D" (
        if "%~2" == "MINGW" if "%~3" == "1" set "OPTS=-G "MinGW Makefiles""
        if "%~2" == "URHO3D_64BIT" if "%~3" == "1" set "arch=-A x64"
        if "%~2" == "URHO3D_64BIT" if "%~3" == "0" set "arch=-A Win32"
        set "BUILD_OPTS=%BUILD_OPTS% -D %~2=%~3"
        shift
        shift
        shift
    ) else if "%ARG1:~0,2%" == "-D" (
        :: Handle case where there is no space after "-D" in the options
        set "BUILD_OPTS=%BUILD_OPTS% %~1=%~2"
        shift
        shift
    )
    if "%~1" == "-VS" (
        set "OPTS=-G "Visual Studio %~2" %arch% %TOOLSET%"
        shift
        shift
    )
    if "%~1" == "-G" (
        :: Add quote to MinGW Makefiles flag since Emscripten's `emcmake` emits them without quotes and this breaks CMake
        if "%~2" == "MinGW Makefiles" (
            set "OPTS=%OPTS% -G "%~2""
        ) else (
            set "OPTS=%OPTS% -G %~2"
        )
        shift
        shift
    )
    goto loop
)

Right after checking if "%~1" == "-D" an else part checks if %~1 starts with -D and if so appends %~1=%~2 to %BUILD_OPTS%.

I also noticed that emcmake emits the MinGW makefiles generator flag without quotes around MinGW Makefiles and this breaks CMake. This is also handled in the change I made.