From d4b7518a9469c255cf92c2c5764ad2900ff079dd Mon Sep 17 00:00:00 2001 From: David Piuva Date: Sun, 2 Feb 2025 09:10:16 +0100 Subject: [PATCH] Ported the build scripts to MS-Windows for running tests. --- .github/workflows/ci.yml | 10 ++- .github/workflows/ci.yml.tabs | 10 ++- Source/test.bat | 67 ++++++++++++++++++++ Source/tools/buildScripts/build.bat | 72 ++++++++++++++++++++++ Source/tools/buildScripts/build.sh | 5 +- Source/tools/buildScripts/buildAndRun.bat | 23 +++++++ Source/tools/buildScripts/buildLibrary.bat | 66 ++++++++++++++++++++ Source/tools/buildScripts/clean.bat | 17 +++++ 8 files changed, 265 insertions(+), 5 deletions(-) create mode 100755 Source/test.bat create mode 100755 Source/tools/buildScripts/build.bat create mode 100755 Source/tools/buildScripts/buildAndRun.bat create mode 100755 Source/tools/buildScripts/buildLibrary.bat create mode 100755 Source/tools/buildScripts/clean.bat diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32c81ff6..119aadfb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,12 +7,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] architecture: [x86_32, x86_64, arm, arm64] steps: - name: Checkout uses: actions/checkout@v4 - - name: Run tests + - name: Run tests on Linux and macOS + if: matrix.os != 'windows-latest' run: | cd ./Source ./test.sh + - name: Run tests on Windows + if: matrix.os == 'windows-latest' + run: | + cd %CD%/Source + test.bat diff --git a/.github/workflows/ci.yml.tabs b/.github/workflows/ci.yml.tabs index 8362b6b4..e95ca4a6 100644 --- a/.github/workflows/ci.yml.tabs +++ b/.github/workflows/ci.yml.tabs @@ -6,12 +6,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] architecture: [x86_32, x86_64, arm, arm64] steps: - name: Checkout uses: actions/checkout@v4 - - name: Run tests + - name: Run tests on Linux and macOS + if: matrix.os != 'windows-latest' run: | cd ./Source ./test.sh + - name: Run tests on Windows + if: matrix.os == 'windows-latest' + run: | + cd %CD%/Source + test.bat diff --git a/Source/test.bat b/Source/test.bat new file mode 100755 index 00000000..5c8b5a5b --- /dev/null +++ b/Source/test.bat @@ -0,0 +1,67 @@ +REM @echo off +setlocal enabledelayedexpansion + +REM Ugly hack hard-coding the Github path because %CD% does not work on the test servers. +set ROOT_PATH="D:\a\DFPSR\DFPSR\Source" +set TEMP_ROOT="%ROOT_PATH%\..\..\temporary" +set CPP_VERSION="-std=c++14" +set MODE="-DDEBUG" +set DEBUGGER="-g" +set SIMD="-march=native" +set O_LEVEL="-O2" + +echo "ROOT_PATH is %ROOT_PATH%" +echo "TEMP_ROOT is %TEMP_ROOT%" +echo "CPP_VERSION is %CPP_VERSION%" +echo "MODE is %MODE%" +echo "DEBUGGER is %DEBUGGER%" +echo "SIMD is %SIMD%" +echo "O_LEVEL is %O_LEVEL%" + +REM Allow calling the build script +call "%ROOT_PATH%\tools\build.bat" +call "%ROOT_PATH%\tools\buildScripts\build.bat" "NONE" "NONE" "%ROOT_PATH%" "%TEMP_ROOT%" "NONE" "%MODE% %DEBUGGER% %SIMD% %CPP_VERSION% %O_LEVEL%" +if errorlevel 1 ( + exit /b 1 +) + +REM Get the specific temporary sub-folder for the compilation settings +set TEMP_DIR="%MODE%_%DEBUGGER%_%SIMD%_%CPP_VERSION%_%O_LEVEL%" + +REM Remove previous test case and application +del /f /q "%TEMP_DIR%\*_test.o" +del /f /q "%TEMP_DIR%\application" + +REM Compile and run test cases +for %%F in (.\test\tests\*.cpp) do ( + if exist "%%F" ( + set "name=%%~nxF" + set "base=%%~nF" + echo Compiling !name! + g++ %CPP_VERSION% %MODE% %DEBUGGER% %SIMD% -c "%%F" -o "%TEMP_DIR%\!base!_test.o" + if errorlevel 1 ( + exit /b 1 + ) + + REM Linking with frameworks + echo Linking !name! + g++ "%TEMP_DIR%\*.o" "%TEMP_DIR%\*.a" -lm -pthread -o "%TEMP_DIR%\application" + if errorlevel 1 ( + exit /b 1 + ) + + REM Run the test case + echo Executing !name! + "%TEMP_DIR%\application" + if errorlevel 0 ( + echo Passed !name! + ) else ( + echo Failed !name! + REM Re-run with a memory debugger (gdb) + gdb -ex "run" -ex "bt" -ex "quit" --args "%TEMP_DIR%\application" + exit /b 1 + ) + ) +) + +endlocal diff --git a/Source/tools/buildScripts/build.bat b/Source/tools/buildScripts/build.bat new file mode 100755 index 00000000..6a216c2c --- /dev/null +++ b/Source/tools/buildScripts/build.bat @@ -0,0 +1,72 @@ +REM @echo off +setlocal enabledelayedexpansion + +REM Load arguments into named variables in order +set PROJECT_FOLDERS=%1 REM Where your code is as a space separated list of folders in a quote +set TARGET_FILE=%2 REM Your executable to build +set ROOT_PATH=%3 REM The parent folder of DFPSR, SDK and tools +set TEMP_ROOT=%4 REM Where your temporary objects should be +set WINDOW_MANAGER=%5 REM Which library to use for creating a window +set COMPILER_FLAGS=%6 REM -DDEBUG/-DNDEBUG -std=c++14/-std=c++17 -O2/-O3 +set LINKER_FLAGS=%7 REM Additional linker flags for libraries and such + +REM Replace space with underscore +set TEMP_SUB="%COMPILER_FLAGS: =_%" +REM Replace + with p +set TEMP_SUB="%TEMP_SUB:+=p%" +REM Remove = and - +SET "TEMP_SUB=%TEMP_SUB:=-=%" + +set TEMP_DIR="%TEMP_ROOT%\%TEMP_SUB%" +echo Building version %TEMP_SUB% + +REM Allow calling other scripts +chmod +x "%ROOT_PATH%\tools\buildScripts\clean.bat" +chmod +x "%ROOT_PATH%\tools\buildScripts\buildLibrary.bat" + +REM Make a clean folder +call "%ROOT_PATH%\tools\buildScripts\clean.bat" "%TEMP_DIR%" + +echo Compiling renderer framework. +call "%ROOT_PATH%\tools\buildScripts\buildLibrary.bat" g++ "%ROOT_PATH%\DFPSR" "%TEMP_DIR%" "dfpsr" "%COMPILER_FLAGS%" LAZY +if errorlevel 1 ( + exit /b 1 +) + +REM Abort if the project folder is replaced with the NONE keyword +if "%PROJECT_FOLDERS%"=="NONE" ( + exit /b 0 +) + +echo Compiling application. +call "%ROOT_PATH%\tools\buildScripts\buildLibrary.bat" g++ "%PROJECT_FOLDERS%" "%TEMP_DIR%" "application" "%COMPILER_FLAGS%" CLEAN +if errorlevel 1 ( + exit /b 1 +) + +REM Select the base libraries needed by the framework itself +set BASELIBS=-lm -pthread + +REM Select window manager to compile and libraries to link +if "%WINDOW_MANAGER%"=="NONE" ( + REM Embedded/terminal mode + set WINDOW_SOURCE=%ROOT_PATH%\windowManagers\NoWindow.cpp + set LIBS=%BASELIBS% %LINKER_FLAGS% +) else ( + REM Desktop GUI mode + set WINDOW_SOURCE=%ROOT_PATH%\windowManagers\%WINDOW_MANAGER%Window.cpp + set LIBS=%BASELIBS% %LINKER_FLAGS% -l%WINDOW_MANAGER% +) + +echo Compiling window manager (%WINDOW_SOURCE%) +g++ %COMPILER_FLAGS% -Wall -c "%WINDOW_SOURCE%" -o "%TEMP_DIR%\NativeWindow.o" +if errorlevel 1 ( + exit /b 1 +) + +echo Linking application with libraries (%LIBS%) +REM Main must exist in the first library when linking +g++ "%TEMP_DIR%\application.a" "%TEMP_DIR%\NativeWindow.o" %LIBS% "%TEMP_DIR%\dfpsr.a" -o "%TARGET_FILE%" +if errorlevel 1 ( + exit /b 1 +) diff --git a/Source/tools/buildScripts/build.sh b/Source/tools/buildScripts/build.sh index 7fbe88b2..f6ea25d9 100755 --- a/Source/tools/buildScripts/build.sh +++ b/Source/tools/buildScripts/build.sh @@ -9,9 +9,12 @@ WINDOW_MANAGER=$5 # Which library to use for creating a window COMPILER_FLAGS=$6 # -DDEBUG/-DNDEBUG -std=c++14/-std=c++17 -O2/-O3 LINKER_FLAGS=$7 # Additional linker flags for libraries and such +# Replace space with underscore TEMP_SUB="${COMPILER_FLAGS// /_}" +# Replace + with p TEMP_SUB=$(echo $TEMP_SUB | tr "+" "p") -TEMP_SUB=$(echo $TEMP_SUB | tr -d " =-") +# Remove = and - +TEMP_SUB=$(echo $TEMP_SUB | tr -d "=-") TEMP_DIR=${TEMP_ROOT}/${TEMP_SUB} echo "Building version ${TEMP_SUB}" diff --git a/Source/tools/buildScripts/buildAndRun.bat b/Source/tools/buildScripts/buildAndRun.bat new file mode 100755 index 00000000..913b6698 --- /dev/null +++ b/Source/tools/buildScripts/buildAndRun.bat @@ -0,0 +1,23 @@ +REM @echo off +setlocal enabledelayedexpansion + +REM Load arguments into named variables in order +set PROJECT_FOLDERS=%1 REM Where your code is as a space separated list of folders in a quote +set TARGET_FILE=%2 REM Your executable to build +set ROOT_PATH=%3 REM The parent folder of DFPSR, SDK and tools +set TEMP_ROOT=%4 REM Where your temporary objects should be +set WINDOW_MANAGER=%5 REM Which library to use for creating a window +set COMPILER_FLAGS=%6 REM -DDEBUG/-DNDEBUG -std=c++14/-std=c++17 -O2/-O3 +set LINKER_FLAGS=%7 REM Additional linker flags for libraries and such + +REM Allow calling the build script +call "%ROOT_PATH%\tools\buildScripts\build.bat" + +REM Compile and link +call "%ROOT_PATH%\tools\buildScripts\build.bat" "%PROJECT_FOLDERS%" "%TARGET_FILE%" "%ROOT_PATH%" "%TEMP_ROOT%" "%WINDOW_MANAGER%" "%COMPILER_FLAGS%" "%LINKER_FLAGS%" +if errorlevel 1 ( + exit /b 1 +) + +echo Starting application at %TARGET_FILE% +"%TARGET_FILE%" diff --git a/Source/tools/buildScripts/buildLibrary.bat b/Source/tools/buildScripts/buildLibrary.bat new file mode 100755 index 00000000..6ac0903f --- /dev/null +++ b/Source/tools/buildScripts/buildLibrary.bat @@ -0,0 +1,66 @@ +REM @echo off +setlocal enabledelayedexpansion + +REM Compile all cpp files in a folder and all of its sub-folders into a static library using the GNU c++ compiler + +REM The global command for running the compiler (tested with g++ and clang++) +set COMPILER=%1 +REM The root of each folder containing source files +set SOURCE_FOLDERS=%2 +REM The target folder where the library will be created +set TARGET=%3 +REM The name of your library without any path nor extension +set LIBRARY_NAME=%4 +set OBJECT_POSTFIX=_%LIBRARY_NAME%_TEMP.o +REM Compiler flags +set COMPILER_FLAGS=%5 + +set LIBRARY_FILENAME=%TARGET%\%LIBRARY_NAME%.a +set SUM_FILENAME=%TARGET%\%LIBRARY_NAME%.md5 + +REM Clean building, because lazy building is not yet implemented on MS-Windows. +del /f /q "%LIBRARY_FILENAME%" + +REM Check if the target library already exists +if not exist "%LIBRARY_FILENAME%" ( + REM Argument: %1 as the folder to compile recursively + call :compileFolder "%SOURCE_FOLDERS%" + + REM Assembling static library + echo Assembling object files into %LIBRARY_NAME%.a. + ar rcs "%LIBRARY_FILENAME%" "%TARGET%\*%OBJECT_POSTFIX%" + + REM Cleaning up temporary objects + echo Cleaning up temporary %LIBRARY_NAME% object files. + del /f /q "%TARGET%\*%OBJECT_POSTFIX%" +) + +exit /b + +:compileFolder +set FOLDER=%1 +if not exist "!FOLDER!" ( + echo Failed to compile files in !FOLDER! because the folder does not exist! + exit /b 1 +) + +REM Compile files in the folder +for %%F in ("!FOLDER!\*.cpp") do ( + if exist "%%F" ( + set "name=%%~nxF" + set "base=%%~nF" + echo C++ %%F + %COMPILER% %COMPILER_FLAGS% -Wall -c "%%F" -o "%TARGET%\!base!%OBJECT_POSTFIX%" + if errorlevel 1 ( + echo Failed to compile %%F! + exit /b 1 + ) + ) +) + +REM Recursively compile other folders +for /d %%D in ("!FOLDER!\*") do ( + call :compileFolder "%%D" +) + +exit /b diff --git a/Source/tools/buildScripts/clean.bat b/Source/tools/buildScripts/clean.bat new file mode 100755 index 00000000..25952419 --- /dev/null +++ b/Source/tools/buildScripts/clean.bat @@ -0,0 +1,17 @@ +@echo off +setlocal + +REM Load arguments into named variables in order + +REM Which folder to create or clear +set TEMP_DIR=%1 + +REM Create a temporary folder +if not exist "%TEMP_DIR%" ( + mkdir "%TEMP_DIR%" +) + +REM Remove objects, but keep libraries +del /f /q "%TEMP_DIR%\*.o" + +endlocal