From ee509e0ae293ef94d0bbfa43c37b7223c59bf923 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Sat, 3 Jul 2021 22:15:09 -0700 Subject: [PATCH] Add a simple Windows command-line build script Batch file that offers a single command line and sensible defaults to: initialize the primary Visual Studio build environment, handle directory creation/cleaning, run cmake, launch msbuild, etc. --- build_win.bat | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 build_win.bat diff --git a/build_win.bat b/build_win.bat new file mode 100644 index 00000000000..b2bdf9aec53 --- /dev/null +++ b/build_win.bat @@ -0,0 +1,190 @@ +@setlocal disableDelayedExpansion enableExtensions +@echo off +GOTO :MAIN +:HELP +@ECHO Performs initial build or rebuild of the app (build) and deps (build/deps). +@ECHO Default options are determined from build directories and system state. +@ECHO. +@ECHO Usage: build_win [-ARCH ^] [-CONFIG ^] [-DESTDIR ^] +@ECHO [-STEPS ^] +@ECHO. +@ECHO -a -ARCH Target processor architecture +@ECHO Default: %PS_ARCH_HOST% +@ECHO -c -CONFIG MSVC project config +@ECHO Default: %PS_CONFIG_DEFAULT% +@ECHO -s -STEPS Performs only the specified build steps: +@ECHO all - clean and build deps and app +@ECHO all-dirty - build deps and app without cleaning +@ECHO app - build main project/application +@ECHO app-dirty - does not build main project/application +@ECHO deps - clean and build deps +@ECHO deps-dirty - build deps without cleaning +@ECHO Default: %PS_STEPS_DEFAULT% +@ECHO -d -DESTDIR Deps destination directory +@ECHO %PS_DESTDIR_DEFAULT_MSG% +@ECHO. +@ECHO Example usage: +@ECHO First build: build_win -d "c:\src\PrusaSlicer-deps" +@ECHO Deps change: build_win -s all +@ECHO App rebuild: build_win +GOTO :END + +:MAIN +SET START_TIME=%TIME% +pushd %~dp0 +REM Probe build directories and sytem state for reasonable default arguments +SET PS_CONFIG=RelWithDebInfo +SET PS_ARCH=%PROCESSOR_ARCHITECTURE% +CALL :TOLOWER PS_ARCH +SET DEPS_PATH_FILE=%~dp0deps\build\.DEPS_PATH.txt +SET PS_DESTDIR= +IF EXIST %DEPS_PATH_FILE% ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%DEPS_PATH_FILE%") DO SET PS_DESTDIR=%%I + IF EXIST build/ALL_BUILD.vcxproj ( + SET PS_STEPS=app-dirty + ) ELSE SET PS_STEPS=app +) ELSE SET PS_STEPS=all + +REM Set up parameters used by help menu +SET PS_CONFIG_DEFAULT=%PS_CONFIG% +SET PS_ARCH_HOST=%PS_ARCH% +SET PS_STEPS_DEFAULT=%PS_STEPS% +IF "%PS_DESTDIR%" NEQ "" ( + SET PS_DESTDIR_DEFAULT_MSG=Default: %PS_DESTDIR% +) ELSE ( + SET PS_DESTDIR_DEFAULT_MSG=Argument required ^(no default available^) +) + +REM Parse arguments +SET EXIT_STATUS=1 +SET PARSER_STATE= +SET PARSER_FAIL= +FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS" PARSER_STATE "%%~I" +IF "%PARSER_FAIL%%PARSER_STATE%" NEQ "" GOTO :HELP + +REM Validate arguments +CALL :PARSE_OPTION_NAME "all all-dirty deps-dirty deps app-dirty app" PS_STEPS -%PS_STEPS% +IF "%PS_STEPS%" EQU "" GOTO :HELP +(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 +CALL :TOLOWER PS_STEPS +CALL :TOLOWER PS_ARCH +IF "%OPTION_NAME%" NEQ "" GOTO :HELP +IF "%PS_STEPS_DIRTY%%PS_DESTDIR%" EQU "" GOTO :HELP + +REM Set up MSVC environment +SET EXIT_STATUS=2 +@ECHO ********************************************************************** +@ECHO ** Build Config: %PS_CONFIG% +@ECHO ** Target Arch: %PS_ARCH% +@ECHO ** Build Steps: %PS_STEPS% +@ECHO ** Using Microsoft Visual Studio installation found at: +SET VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +IF NOT EXIST %VSWHERE% SET VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" +FOR /F "tokens=* USEBACKQ" %%I IN (`%VSWHERE% -nologo -property installationPath`) DO SET MSVC_DIR=%%I +@ECHO ** %MSVC_DIR% +CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop || GOTO :END +IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP + +REM Build deps +:BUILD_DEPS +SET EXIT_STATUS=3 +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build +cd deps\build || GOTO :END +IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END +(echo %PS_DESTDIR%)> "%DEPS_PATH_FILE%" +msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +cd ..\.. +IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :PROLOGUE + +REM Build app +:BUILD_APP +SET EXIT_STATUS=4 +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build +cd build || GOTO :END +IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" || GOTO :END +msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END + +:PROLOGUE +SET EXIT_STATUS=%ERRORLEVEL% +:END +@ECHO Script started at %START_TIME% and completed at %TIME%. +popd +endlocal +exit /B %EXIT_STATUS% + +GOTO :EOF +REM Functions and stubs start here. + +:PARSE_OPTION +REM Argument parser called for each argument +REM %1 - Valid option list +REM %2 - Variable name for parser state; must be unset when parsing finished +REM %3 - Current argument value +REM PARSER_FAIL will be set on an error +REM Note: Must avoid delayed expansion since filenames may contain ! character +setlocal disableDelayedExpansion +CALL SET LAST_ARG=%%%2%% +IF "%LAST_ARG%" EQU "" ( + CALL :PARSE_OPTION_NAME %1 %~2 %~3 1 + SET ARG_TYPE=NAME +) ELSE ( + SET PS_SET_COMMAND=^&SET PS_%LAST_ARG%=%~3 + SET ARG_TYPE=LAST_ARG + SET %~2= +) +CALL SET LAST_ARG=%%%2%% +IF "%LAST_ARG%" EQU "" IF "%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=1 +endlocal & (SET PARSER_FAIL=%PARSER_FAIL%) & (SET %~2=%LAST_ARG%) %PS_SET_COMMAND% +GOTO :EOF + +:PARSE_OPTION_NAME +REM Parses an option name +REM %1 - Valid option list +REM %2 - Out variable name; unset on error +REM %3 - Current argument value +REM $4 - Boolean indicating single character switches are valid +REM Note: Delayed expansion safe because ! character is invalid in option name +setlocal enableDelayedExpansion +IF "%4" NEQ "" FOR %%I IN (%~1) DO ( + SET SHORT_NAME=%%~I + SET SHORT_ARG_!SHORT_NAME:~0,1!=%%~I +) +SET OPTION_NAME=%~3 +(echo %OPTION_NAME%)| findstr /R /C:"[-/]..*">nul || GOTO :PARSE_OPTION_NAME_FAIL +SET OPTION_NAME=%OPTION_NAME:~1% +IF "%4" NEQ "" ( + IF "%OPTION_NAME%" EQU "%OPTION_NAME:~0,1%" ( + IF "!SHORT_ARG_%OPTION_NAME:~0,1%!" NEQ "" SET OPTION_NAME=!SHORT_ARG_%OPTION_NAME:~0,1%! + ) +) +(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL +(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL +endlocal & SET %~2=%OPTION_NAME% +GOTO :EOF +:PARSE_OPTION_NAME_FAIL +endlocal & SET %~2= +GOTO :EOF + +:MAKE_OR_CLEAN_DIRECTORY +REM Create directory if it doesn't exist or clean it if it does +REM %1 - Directory path to clean or create +setlocal disableDelayedExpansion +IF NOT EXIST "%~1" ( + ECHO Creating %~1 + mkdir "%~1" && GOTO :EOF +) +ECHO Cleaning %~1 ... +for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do ( + (rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I") +GOTO :EOF + +:TOLOWER +REM Converts supplied environment variable to lowercase +REM %1 - Input/output variable name +REM Note: This is slow on very long strings, but is used only on very short ones +setlocal disableDelayedExpansion +FOR %%b IN (a b c d e f g h i j k l m n o p q r s t u v w x y z) DO CALL set %~1=%%%1:%%b=%%b%% +CALL SET OUTPUT=%%%~1%% +endlocal & SET %~1=%OUTPUT% +GOTO :EOF +