1 ################################################################################
2 # Windows SRT Build Script
3 #============================
4 # Usable on a Windows PC with Powershell and Visual studio,
5 # or called by CI systems like AppVeyor
6 #
7 # By default produces a VS2019 64-bit Release binary using C++11 threads, without
8 # encryption or unit tests enabled, but including test apps.
9 # Before enabling any encryption options, install OpenSSL or set VCKPG flag to build
10 ################################################################################
11 
12 param (
13     [Parameter()][String]$VS_VERSION = "2019",
14     [Parameter()][String]$CONFIGURATION = "Release",
15     [Parameter()][String]$DEVENV_PLATFORM = "x64",
16     [Parameter()][String]$ENABLE_ENCRYPTION = "OFF",
17     [Parameter()][String]$STATIC_LINK_SSL = "OFF",
18     [Parameter()][String]$CXX11 = "ON",
19     [Parameter()][String]$BUILD_APPS = "ON",
20     [Parameter()][String]$UNIT_TESTS = "OFF",
21     [Parameter()][String]$BUILD_DIR = "_build",
22     [Parameter()][String]$VCPKG_OPENSSL = "OFF"
23 )
24 
25 # cmake can be optionally installed (useful when running interactively on a developer station).
26 # The URL for automatic download is defined later in the script, but it should be possible to just vary the
27 # specific version set below and the URL should be stable enough to still work - you have been warned.
28 $cmakeVersion = "3.17.3"
29 
30 # make all errors trigger a script stop, rather than just carry on
31 $ErrorActionPreference = "Stop"
32 
33 $projectRoot = Join-Path $PSScriptRoot "/.." -Resolve
34 
35 # if running within AppVeyor, use environment variables to set params instead of passed-in values
36 if ( $Env:APPVEYOR ) {
37     if ( $Env:PLATFORM -eq 'x86' ) { $DEVENV_PLATFORM = 'Win32' } else { $DEVENV_PLATFORM = 'x64' }
38     if ( $Env:APPVEYOR_BUILD_WORKER_IMAGE -eq 'Visual Studio 2019' ) { $VS_VERSION='2019' }
39     if ( $Env:APPVEYOR_BUILD_WORKER_IMAGE -eq 'Visual Studio 2015' ) { $VS_VERSION='2015' }
40     if ( $Env:APPVEYOR_BUILD_WORKER_IMAGE -eq 'Visual Studio 2013' ) { $VS_VERSION='2013' }
41 
42     #if not statically linking OpenSSL, set flag to gather the specific openssl package from the build server into package
43     if ( $STATIC_LINK_SSL -eq 'OFF' ) { $Env:GATHER_SSL_INTO_PACKAGE = $true }
44 
45     #if unit tests are on, set flag to actually execute ctest step
46     if ( $UNIT_TESTS -eq 'ON' ) { $Env:RUN_UNIT_TESTS = $true }
47 
48     $CONFIGURATION = $Env:CONFIGURATION
49 
50     #appveyor has many openssl installations - place the latest one in the default location unless VS2013
51     if( $VS_VERSION -ne '2013' ) {
52         Remove-Item -Path "C:\OpenSSL-Win32" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
53         Remove-Item -Path "C:\OpenSSL-Win64" -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
54         Copy-Item -Path "C:\OpenSSL-v111-Win32" "C:\OpenSSL-Win32" -Recurse | Out-Null
55         Copy-Item -Path "C:\OpenSSL-v111-Win64" "C:\OpenSSL-Win64" -Recurse | Out-Null
56     }
57 }
58 
59 # persist VS_VERSION so it can be used in an artifact name later
60 $Env:VS_VERSION = $VS_VERSION
61 
62 # select the appropriate cmake generator string given the environment
63 if ( $VS_VERSION -eq '2019' ) { $CMAKE_GENERATOR = 'Visual Studio 16 2019'; $MSBUILDVER = "16.0"; }
64 if ( $VS_VERSION -eq '2015' -and $DEVENV_PLATFORM -eq 'Win32' ) { $CMAKE_GENERATOR = 'Visual Studio 14 2015'; $MSBUILDVER = "14.0"; }
65 if ( $VS_VERSION -eq '2015' -and $DEVENV_PLATFORM -eq 'x64' ) { $CMAKE_GENERATOR = 'Visual Studio 14 2015 Win64'; $MSBUILDVER = "14.0"; }
66 if ( $VS_VERSION -eq '2013' -and $DEVENV_PLATFORM -eq 'Win32' ) { $CMAKE_GENERATOR = 'Visual Studio 12 2013'; $MSBUILDVER = "12.0"; }
67 if ( $VS_VERSION -eq '2013' -and $DEVENV_PLATFORM -eq 'x64' ) { $CMAKE_GENERATOR = 'Visual Studio 12 2013 Win64'; $MSBUILDVER = "12.0"; }
68 
69 # clear any previous build and create & enter the build directory
70 $buildDir = Join-Path "$projectRoot" "$BUILD_DIR"
71 Write-Output "Creating (or cleaning if already existing) the folder $buildDir for project files and outputs"
72 Remove-Item -Path $buildDir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
73 New-Item -ItemType Directory -Path $buildDir -ErrorAction SilentlyContinue | Out-Null
74 Push-Location $buildDir
75 
76 # check cmake is installed
77 if ( $null -eq (Get-Command "cmake.exe" -ErrorAction SilentlyContinue) ) {
78     $installCmake = Read-Host "Unable to find cmake in your PATH - would you like to download and install automatically? [yes/no]"
79 
80     if ( $installCmake -eq "y" -or $installCmake -eq "yes" ) {
81         # download cmake and run MSI for user
82         $client = New-Object System.Net.WebClient
83         $tempDownloadFile = New-TemporaryFile
84 
85         $cmakeUrl = "https://github.com/Kitware/CMake/releases/download/v$cmakeVersion/cmake-$cmakeVersion-win64-x64.msi"
86         $cmakeMsiFile = "$tempDownloadFile.cmake-$cmakeVersion-win64-x64.msi"
87         Write-Output "Downloading cmake from $cmakeUrl (temporary file location $cmakeMsiFile)"
88         Write-Output "Note: select the option to add cmake to path for this script to operate"
89         $client.DownloadFile("$cmakeUrl", "$cmakeMsiFile")
90         Start-Process $cmakeMsiFile -Wait
91         Remove-Item $cmakeMsiFile
92         Write-Output "Cmake should have installed, this script will now exit because of path updates - please now re-run this script"
93         throw
94     }
95     else{
96         Write-Output "Quitting because cmake is required"
97         throw
98     }
99 }
100 
101 # get pthreads from nuget if CXX11 is not enabled
102 if ( $CXX11 -eq "OFF" ) {
103     # get pthreads (this is legacy, and is only availble in nuget for VS2015 and VS2013)
104     if ( $VS_VERSION -gt 2015 ) {
105         Write-Output "Pthreads is not recommended for use beyond VS2015 and is not supported by this build script - aborting build"
106         throw
107     }
108     if ( $DEVENV_PLATFORM -eq 'Win32' ) {
109         nuget install cinegy.pthreads-win32-$VS_VERSION -version 2.9.1.24 -OutputDirectory ../_packages
110     }
111     else {
112         nuget install cinegy.pthreads-win64-$VS_VERSION -version 2.9.1.24 -OutputDirectory ../_packages
113     }
114 }
115 
116 # check to see if static SSL linking was requested, and enable encryption if not already ON
117 if ( $STATIC_LINK_SSL -eq "ON" ) {
118     if ( $ENABLE_ENCRYPTION -eq "OFF" ) {
119         # requesting a static link implicitly requires encryption support
120         Write-Output "Static linking to OpenSSL requested, will force encryption feature ON"
121         $ENABLE_ENCRYPTION = "ON"
122     }
123 }
124 
125 # check to see if VCPKG is marked to provide OpenSSL, and enable encryption if not already ON
126 if ( $VCPKG_OPENSSL -eq "ON" ) {
127     if ( $ENABLE_ENCRYPTION -eq "OFF" ) {
128         # requesting VCPKG to provide OpenSSL requires encryption support
129         Write-Output "VCPKG compilation of OpenSSL requested, will force encryption feature ON"
130         $ENABLE_ENCRYPTION = "ON"
131     }
132 }
133 
134 # build the cmake command flags from arguments
135 $cmakeFlags = "-DCMAKE_BUILD_TYPE=$CONFIGURATION " +
136                 "-DENABLE_STDCXX_SYNC=$CXX11 " +
137                 "-DENABLE_APPS=$BUILD_APPS " +
138                 "-DENABLE_ENCRYPTION=$ENABLE_ENCRYPTION " +
139                 "-DENABLE_UNITTESTS=$UNIT_TESTS"
140 
141 # if VCPKG is flagged to provide OpenSSL, checkout VCPKG and install package
142 if ( $VCPKG_OPENSSL -eq 'ON' ) {
143     Push-Location $projectRoot
144     Write-Output "Cloning VCPKG into: $(Get-Location)"
145     if (Test-Path -Path ".\vcpkg") {
146         Set-Location .\vcpkg
147         git pull
148     } else {
149         git clone https://github.com/microsoft/vcpkg
150         Set-Location .\vcpkg
151     }
152 
153     .\bootstrap-vcpkg.bat
154 
155     if($DEVENV_PLATFORM -EQ "x64"){
156         if($STATIC_LINK_SSL -EQ "ON"){
157             .\vcpkg install openssl:x64-windows-static
158             $cmakeFlags += " -DVCPKG_TARGET_TRIPLET=x64-windows-static"
159         }
160         else{
161             .\vcpkg install openssl:x64-windows
162         }
163     }
164     else{
165         if($STATIC_LINK_SSL -EQ "ON"){
166             .\vcpkg install openssl:x86-windows-static
167             $cmakeFlags += " -DVCPKG_TARGET_TRIPLET=x86-windows-static"
168         }
169         else{
170             .\vcpkg install openssl:x86-windows
171         }
172     }
173 
174     .\vcpkg integrate install
175     Pop-Location
176     $cmakeFlags += " -DCMAKE_TOOLCHAIN_FILE=$projectRoot\vcpkg\scripts\buildsystems\vcpkg.cmake"
177 }
178 else {
179     $cmakeFlags += " -DOPENSSL_USE_STATIC_LIBS=$STATIC_LINK_SSL "
180 }
181 
182 # cmake uses a flag for architecture from vs2019, so add that as a suffix
183 if ( $VS_VERSION -eq '2019' ) {
184     $cmakeFlags += " -A `"$DEVENV_PLATFORM`""
185 }
186 
187 # fire cmake to build project files
188 $execVar = "cmake ../ -G`"$CMAKE_GENERATOR`" $cmakeFlags"
189 Write-Output $execVar
190 
191 # Reset reaction to Continue for cmake as it sometimes tends to print
192 # things on stderr, which is understood by PowerShell as error. The
193 # exit code from cmake will be checked anyway.
194 $ErrorActionPreference = "Continue"
195 Invoke-Expression "& $execVar"
196 
197 # check build ran OK, exit if cmake failed
198 if( $LASTEXITCODE -ne 0 ) {
199     Write-Output "Non-zero exit code from cmake: $LASTEXITCODE"
200     throw
201 }
202 
203 $ErrorActionPreference = "Stop"
204 
205 # run the set-version-metadata script to inject build numbers into appveyors console and the resulting DLL
206 . $PSScriptRoot/set-version-metadata.ps1
207 
208 # look for msbuild
209 $msBuildPath = Get-Command "msbuild.exe" -ErrorAction SilentlyContinue
210 if ( $null -eq $msBuildPath ) {
211     # no mbsuild in the path, so try to locate with 'vswhere'
212     $vsWherePath = Get-Command "vswhere.exe" -ErrorAction SilentlyContinue
213     if ( $null -eq $vsWherePath ) {
214         # no vswhere in the path, so check the Microsoft published location (true since VS2017 Update 2)
215         $vsWherePath = Get-Command "${Env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -ErrorAction SilentlyContinue
216         if ( $null -eq $vsWherePath ) {
217             Write-Output "Cannot find vswhere (used to locate msbuild). Please install VS2017 update 2 (or later) or add vswhere to your path and try again"
218             throw
219         }
220     }
221     $msBuildPath = & $vsWherePath -products * -version $MSBUILDVER -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
222 	if ( $null -eq $msBuildPath ) {
223 		Write-Output "vswhere.exe cannot find msbuild for the specified Visual Studio version - please check the installation"
224 		throw
225 	}
226 }
227 
228 & $msBuildPath SRT.sln -m /p:Configuration=$CONFIGURATION /p:Platform=$DEVENV_PLATFORM
229 
230 # return to the directory previously occupied before running the script
231 Pop-Location
232 
233 # if msbuild returned non-zero, throw to cause failure in CI
234 if( $LASTEXITCODE -ne 0 ) {
235     throw
236 }
237