From 38daa83ff6f73defbeeb3c86a4744ca5ba66c796 Mon Sep 17 00:00:00 2001 From: psi29a Date: Sat, 16 May 2020 21:55:14 +0000 Subject: [PATCH] Merge branch 'ninja' into 'master' Enable Windows Ninja builds See merge request OpenMW/openmw!202 (cherry picked from commit e0b352323226ff11e230f6489e826df332fa681a) c1e673ce Unify path conversion functions fdf0fdbb Fix NMake with MSVC 2019 bdd4a814 Activate MSVC during CMake setup for NMake eae41050 Support sourcing c0d28a0e Warn that MSVC environment will need to be activated bd16ad62 Ninja 7d57e6e2 Support MSVC 2015 3679d329 Check MSVC activated correctly ed4b73b8 Fix post-2015 Visual Studio 4ffa116a Print message when it's necessary instead of when it isn't c6e09461 Add instructions for using VS' non-.sln support d9bb6e63 Activate MSVC later 9ca26358 Create batch script to activate correct MSVC 61df647d Provide scripts to activate selected MSVC in existing shell without kerfuffle --- CI/ActivateMSVC.ps1 | 26 +++++++ CI/activate_msvc.sh | 76 +++++++++++++++++++ CI/before_script.msvc.sh | 153 ++++++++++++++++++++++++++++++++++----- 3 files changed, 236 insertions(+), 19 deletions(-) create mode 100644 CI/ActivateMSVC.ps1 create mode 100644 CI/activate_msvc.sh diff --git a/CI/ActivateMSVC.ps1 b/CI/ActivateMSVC.ps1 new file mode 100644 index 000000000..ca78ef588 --- /dev/null +++ b/CI/ActivateMSVC.ps1 @@ -0,0 +1,26 @@ +& "${env:COMSPEC}" /c ActivateMSVC.bat "&&" set | ForEach-Object { + $name, $value = $_ -split '=', 2 + Set-Content env:\"$name" $value +} + +$MissingTools = $false +$tools = "cl", "link", "rc", "mt", "awooga" +$descriptions = "MSVC Compiler", "MSVC Linker", "MS Windows Resource Compiler", "MS Windows Manifest Tool", "A made up command" +for ($i = 0; $i -lt $tools.Length; $i++) { + $present = $true + try { + Get-Command $tools[$i] *>&1 | Out-Null + $present = $present -and $? + } catch { + $present = $false + } + if (!$present) { + Write-Warning "$($tools[$i]) ($($descriptions[$i])) missing." + $MissingTools = $true + } +} + +if ($MissingTools) { + Write-Error "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing." + exit 1 +} \ No newline at end of file diff --git a/CI/activate_msvc.sh b/CI/activate_msvc.sh new file mode 100644 index 000000000..0764cd02f --- /dev/null +++ b/CI/activate_msvc.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +set -euo pipefail + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + echo "Error: Script not sourced." + echo "You must source this script for it to work, i.e. " + echo "source ./activate_msvc.sh" + echo "or" + echo ". ./activate_msvc.sh" + exit 1 +fi + +command -v unixPathAsWindows >/dev/null 2>&1 || function unixPathAsWindows { + if command -v cygpath >/dev/null 2>&1; then + cygpath -w $1 + else + echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g" + fi +} + +function windowsSystemPathAsUnix { + if command -v cygpath >/dev/null 2>&1; then + cygpath -u -p $1 + else + IFS=';' read -r -a paths <<< "$1" + declare -a convertedPaths + for entry in paths; do + convertedPaths+=(windowsPathAsUnix $entry) + done + convertedPath=printf ":%s" ${convertedPaths[@]} + echo ${convertedPath:1} + fi +} + +# capture CMD environment so we know what's been changed +declare -A originalCmdEnv +originalIFS="$IFS" +IFS=$'\n\r' +for pair in $(cmd //c "set"); do + IFS='=' read -r -a separatedPair <<< "${pair}" + originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}" +done + +# capture CMD environment in a shell with MSVC activated +cmdEnv="$(cmd //c "$(unixPathAsWindows "$(dirname "${BASH_SOURCE[0]}")")\ActivateMSVC.bat" "&&" set)" + +declare -A cmdEnvChanges +for pair in $cmdEnv; do + if [ -n "$pair" ]; then + IFS='=' read -r -a separatedPair <<< "${pair}" + key="${separatedPair[0]}" + value="${separatedPair[1]}" + if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then + if [ $key != 'PATH' ] && [ $key != 'path' ] && [ $key != 'Path' ]; then + export "$key=$value" + else + export PATH=$(windowsSystemPathAsUnix $value) + fi + fi + fi +done + +MISSINGTOOLS=0 + +command -v cl >/dev/null 2>&1 || { echo "Error: cl (MSVC Compiler) missing."; MISSINGTOOLS=1; } +command -v link >/dev/null 2>&1 || { echo "Error: link (MSVC Linker) missing."; MISSINGTOOLS=1; } +command -v rc >/dev/null 2>&1 || { echo "Error: rc (MS Windows Resource Compiler) missing."; MISSINGTOOLS=1; } +command -v mt >/dev/null 2>&1 || { echo "Error: mt (MS Windows Manifest Tool) missing."; MISSINGTOOLS=1; } + +if [ $MISSINGTOOLS -ne 0 ]; then + echo "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing." + return 1 +fi + +IFS="$originalIFS" \ No newline at end of file diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3a0b062e6..bf115d315 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -1,25 +1,49 @@ #!/bin/bash # set -x # turn-on for debugging +function wrappedExit { + if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + exit $1 + else + return $1 + fi +} + MISSINGTOOLS=0 command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; } command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; } if [ $MISSINGTOOLS -ne 0 ]; then - exit 1 + wrappedExit 1 fi WORKINGDIR="$(pwd)" case "$WORKINGDIR" in *[[:space:]]*) echo "Error: Working directory contains spaces." - exit 1 + wrappedExit 1 ;; esac set -euo pipefail +function windowsPathAsUnix { + if command -v cygpath >/dev/null 2>&1; then + cygpath -u $1 + else + echo "$1" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1," + fi +} + +function unixPathAsWindows { + if command -v cygpath >/dev/null 2>&1; then + cygpath -w $1 + else + echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g" + fi +} + APPVEYOR=${APPVEYOR:-} CI=${CI:-} STEP=${STEP:-} @@ -32,12 +56,16 @@ KEEP="" UNITY_BUILD="" VS_VERSION="" NMAKE="" +NINJA="" PLATFORM="" CONFIGURATION="" TEST_FRAMEWORK="" GOOGLE_INSTALL_ROOT="" INSTALL_PREFIX="." +ACTIVATE_MSVC="" +SINGLE_CONFIG="" + while [ $# -gt 0 ]; do ARGSTR=$1 shift @@ -45,7 +73,7 @@ while [ $# -gt 0 ]; do if [ ${ARGSTR:0:1} != "-" ]; then echo "Unknown argument $ARGSTR" echo "Try '$0 -h'" - exit 1 + wrappedExit 1 fi for (( i=1; i<${#ARGSTR}; i++ )); do @@ -72,6 +100,9 @@ while [ $# -gt 0 ]; do n ) NMAKE=true ;; + + N ) + NINJA=true ;; p ) PLATFORM=$1 @@ -111,25 +142,31 @@ Options: -v <2013/2015/2017/2019> Choose the Visual Studio version to use. -n - Produce NMake makefiles instead of a Visual Studio solution. + Produce NMake makefiles instead of a Visual Studio solution. Cannout be used with -N. + -N + Produce Ninja (multi-config if CMake is new enough to support it) files instead of a Visual Studio solution. Cannot be used with -n. -V Run verbosely -i CMake install prefix EOF - exit 0 + wrappedExit 0 ;; * ) echo "Unknown argument $ARG." echo "Try '$0 -h'" - exit 1 ;; + wrappedExit 1 ;; esac done done -if [ -n "$NMAKE" ]; then - command -v nmake -? >/dev/null 2>&1 || { echo "Error: nmake (NMake) is not on the path. Make sure you have the necessary environment variables set for command-line C++ development (for example, by starting from a Developer Command Prompt)."; exit 1; } +if [ -n "$NMAKE" ] || [ -n "$NINJA" ]; then + if [ -n "$NMAKE" ] && [ -n "$NINJA" ]; then + echo "Cannout run in NMake and Ninja mode at the same time." + wrappedExit 1 + fi + ACTIVATE_MSVC=true fi if [ -z $VERBOSE ]; then @@ -139,7 +176,7 @@ fi if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." - DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + DIR=$(windowsPathAsUnix "${BASH_SOURCE[0]}") cd $(dirname "$DIR")/.. else echo "Running prebuild in Appveyor." @@ -322,7 +359,7 @@ case $PLATFORM in * ) echo "Unknown platform $PLATFORM." - exit 1 + wrappedExit 1 ;; esac @@ -349,9 +386,18 @@ fi if [ -n "$NMAKE" ]; then GENERATOR="NMake Makefiles" + SINGLE_CONFIG=true fi -if [ $MSVC_REAL_VER -ge 16 ]; then +if [ -n "$NINJA" ]; then + GENERATOR="Ninja Multi-Config" + if ! cmake -E capabilities | grep -F "$GENERATOR" > /dev/null; then + SINGLE_CONFIG=true + GENERATOR="Ninja" + fi +fi + +if [ $MSVC_REAL_VER -ge 16 ] && [ -z "$NMAKE" ] && [ -z "$NINJA" ]; then if [ $BITS -eq 64 ]; then add_cmake_opts "-G\"$GENERATOR\" -A x64" else @@ -361,7 +407,7 @@ else add_cmake_opts "-G\"$GENERATOR\"" fi -if [ -n "$NMAKE" ]; then +if [ -n "$SINGLE_CONFIG" ]; then add_cmake_opts "-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}" fi @@ -456,7 +502,13 @@ cd .. #/.. BUILD_DIR="MSVC${MSVC_DISPLAY_YEAR}_${BITS}" if [ -n "$NMAKE" ]; then - BUILD_DIR="${BUILD_DIR}_NMake_${BUILD_CONFIG}" + BUILD_DIR="${BUILD_DIR}_NMake" +elif [ -n "$NINJA" ]; then + BUILD_DIR="${BUILD_DIR}_Ninja" +fi + +if [ -n "$SINGLE_CONFIG" ]; then + BUILD_DIR="${BUILD_DIR}_${BUILD_CONFIG}" fi if [ -z $KEEP ]; then @@ -494,10 +546,10 @@ fi # We work around this by installing to root of the current working drive and then move it to our deps # get the current working drive's root, we'll install to that temporarily CWD_DRIVE_ROOT="$(powershell -command '(get-location).Drive.Root')Boost_temp" - CWD_DRIVE_ROOT_BASH=$(echo "$CWD_DRIVE_ROOT" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + CWD_DRIVE_ROOT_BASH=$(windowsPathAsUnix "$CWD_DRIVE_ROOT") if [ -d CWD_DRIVE_ROOT_BASH ]; then printf "Cannot continue, ${CWD_DRIVE_ROOT_BASH} aka ${CWD_DRIVE_ROOT} already exists. Please remove before re-running. "; - exit 1; + wrappedExit 1; fi if [ -d ${BOOST_SDK} ] && grep "BOOST_VERSION ${BOOST_VER_SDK}" Boost/boost/version.hpp > /dev/null; then @@ -695,7 +747,7 @@ fi else SUFFIX="" fi - DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + DIR=$(windowsPathAsUnix "${QT_SDK}") add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll" echo Done. @@ -806,14 +858,15 @@ fi #if [ -z $CI ]; then echo "- Copying Runtime DLLs..." DLL_PREFIX="" - if [ -z $NMAKE ]; then + if [ -z $SINGLE_CONFIG ]; then mkdir -p $BUILD_CONFIG DLL_PREFIX="$BUILD_CONFIG/" fi for DLL in $RUNTIME_DLLS; do TARGET="$(basename "$DLL")" if [[ "$DLL" == *":"* ]]; then - IFS=':'; SPLIT=( ${DLL} ); unset IFS + originalIFS="$IFS" + IFS=':'; SPLIT=( ${DLL} ); IFS=$originalIFS DLL=${SPLIT[0]} TARGET=${SPLIT[1]} fi @@ -836,6 +889,42 @@ fi done echo #fi + +if ! [ -z $ACTIVATE_MSVC ]; then + echo -n "- Activating MSVC in the current shell... " + command -v vswhere >/dev/null 2>&1 || { echo "Error: vswhere is not on the path."; wrappedExit 1; } + + MSVC_INSTALLATION_PATH=$(vswhere -legacy -version "[$MSVC_VER,$(awk "BEGIN { print $MSVC_REAL_VER + 1; exit }"))" -property installationPath) + if [ $MSVC_REAL_VER -ge 15 ]; then + echo "@\"${MSVC_INSTALLATION_PATH}\Common7\Tools\VsDevCmd.bat\" -no_logo -arch=$([ $BITS -eq 64 ] && echo "amd64" || echo "x86") -host_arch=$([ $(uname -m) == 'x86_64' ] && echo "amd64" || echo "x86")" > ActivateMSVC.bat + else + if [ $(uname -m) == 'x86_64' ]; then + if [ $BITS -eq 64 ]; then + compiler=amd64 + else + compiler=amd64_x86 + fi + else + if [ $BITS -eq 64 ]; then + compiler=x86_amd64 + else + compiler=x86 + fi + fi + echo "@\"${MSVC_INSTALLATION_PATH}\VC\vcvarsall.bat\" $compiler" > ActivateMSVC.bat + fi + + cp "../CI/activate_msvc.sh" . + sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" activate_msvc.sh + source ./activate_msvc.sh + + cp "../CI/ActivateMSVC.ps1" . + sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" ActivateMSVC.ps1 + + echo "done." + echo +fi + if [ -z $VERBOSE ]; then printf -- "- Configuring... " else @@ -846,8 +935,34 @@ RET=$? if [ -z $VERBOSE ]; then if [ $RET -eq 0 ]; then echo Done. + if [ -n $ACTIVATE_MSVC ]; then + echo + echo "Note: you must manually activate MSVC for the shell in which you want to do the build." + echo + echo "Some scripts have been created in the build directory to do so in an existing shell." + echo "Bash: source activate_msvc.sh" + echo "CMD: ActivateMSVC.bat" + echo "PowerShell: ActivateMSVC.ps1" + echo + echo "You may find options to launch a Development/Native Tools/Cross Tools shell in your start menu or Visual Studio." + echo + if [ $(uname -m) == 'x86_64' ]; then + if [ $BITS -eq 64 ]; then + inheritEnvironments=msvc_x64_x64 + else + inheritEnvironments=msvc_x64 + fi + else + if [ $BITS -eq 64 ]; then + inheritEnvironments=msvc_x86_x64 + else + inheritEnvironments=msvc_x86 + fi + fi + echo "In Visual Studio 15.3 (2017 Update 3) or later, try setting '\"inheritEnvironments\": [ \"$inheritEnvironments\" ]' in CMakeSettings.json to build in the IDE." + fi else echo Failed. fi fi -exit $RET +wrappedExit $RET