[CmdletBinding()] param( $badParam, [Parameter(Mandatory=$False)][switch]$disableMetrics = $false, [Parameter(Mandatory=$False)][switch]$win64 = $false, [Parameter(Mandatory=$False)][string]$withVSPath = "", [Parameter(Mandatory=$False)][string]$withWinSDK = "" ) Set-StrictMode -Version Latest # Powershell2-compatible way of forcing named-parameters if ($badParam) { if ($disableMetrics -and $badParam -eq "1") { Write-Warning "'disableMetrics 1' is deprecated, please change to 'disableMetrics' (without '1')" } else { throw "Only named parameters are allowed" } } $scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition $withVSPath = $withVSPath -replace "\\$" # Remove potential trailing backslash function vcpkgHasProperty([Parameter(Mandatory=$true)][AllowNull()]$object, [Parameter(Mandatory=$true)]$propertyName) { if ($object -eq $null) { return $false } return [bool]($object.psobject.Properties | Where-Object { $_.Name -eq "$propertyName"}) } function getProgramFiles32bit() { $out = ${env:PROGRAMFILES(X86)} if ($out -eq $null) { $out = ${env:PROGRAMFILES} } if ($out -eq $null) { throw "Could not find [Program Files 32-bit]" } return $out } $vcpkgRootDir = $scriptsDir while (!($vcpkgRootDir -eq "") -and !(Test-Path "$vcpkgRootDir\.vcpkg-root")) { Write-Verbose "Examining $vcpkgRootDir for .vcpkg-root" $vcpkgRootDir = Split-path $vcpkgRootDir -Parent } Write-Verbose "Examining $vcpkgRootDir for .vcpkg-root - Found" $vcpkgSourcesPath = "$vcpkgRootDir\toolsrc" if (!(Test-Path $vcpkgSourcesPath)) { Write-Error "Unable to determine vcpkg sources directory. '$vcpkgSourcesPath' does not exist." return } function getVisualStudioInstances() { $programFiles = getProgramFiles32bit $results = New-Object System.Collections.ArrayList $vswhereExe = "$programFiles\Microsoft Visual Studio\Installer\vswhere.exe" if (Test-Path $vswhereExe) { $output = & $vswhereExe -prerelease -legacy -products * -format xml [xml]$asXml = $output foreach ($instance in $asXml.instances.instance) { $installationPath = $instance.InstallationPath -replace "\\$" # Remove potential trailing backslash $installationVersion = $instance.InstallationVersion $isPrerelease = -7 if (vcpkgHasProperty -object $instance -propertyName "isPrerelease") { $isPrerelease = $instance.isPrerelease } if ($isPrerelease -eq 0) { $releaseType = "PreferenceWeight3::StableRelease" } elseif ($isPrerelease -eq 1) { $releaseType = "PreferenceWeight2::PreRelease" } else { $releaseType = "PreferenceWeight1::Legacy" } # Placed like that for easy sorting according to preference $results.Add("${releaseType}::${installationVersion}::${installationPath}") > $null } } else { Write-Verbose "Could not locate vswhere at $vswhereExe" } if ("$env:vs140comntools" -ne "") { $installationPath = Split-Path -Parent $(Split-Path -Parent "$env:vs140comntools") $clExe = "$installationPath\VC\bin\cl.exe" $vcvarsallbat = "$installationPath\VC\vcvarsall.bat" if ((Test-Path $clExe) -And (Test-Path $vcvarsallbat)) { $results.Add("PreferenceWeight1::Legacy::14.0::$installationPath") > $null } } $installationPath = "$programFiles\Microsoft Visual Studio 14.0" $clExe = "$installationPath\VC\bin\cl.exe" $vcvarsallbat = "$installationPath\VC\vcvarsall.bat" if ((Test-Path $clExe) -And (Test-Path $vcvarsallbat)) { $results.Add("PreferenceWeight1::Legacy::14.0::$installationPath") > $null } $results.Sort() $results.Reverse() return $results } function findAnyMSBuildWithCppPlatformToolset([string]$withVSPath) { $VisualStudioInstances = getVisualStudioInstances if ($VisualStudioInstances -eq $null) { throw "Could not find Visual Studio. VS2015 or VS2017 (with C++) needs to be installed." } Write-Verbose "VS Candidates:`n`r$([system.String]::Join([Environment]::NewLine, $VisualStudioInstances))" foreach ($instanceCandidate in $VisualStudioInstances) { Write-Verbose "Inspecting: $instanceCandidate" $split = $instanceCandidate -split "::" # $preferenceWeight = $split[0] # $releaseType = $split[1] $version = $split[2] $path = $split[3] if ($withVSPath -ne "" -and $withVSPath -ne $path) { Write-Verbose "Skipping: $instanceCandidate" continue } $majorVersion = $version.Substring(0,2); if ($majorVersion -eq "16") { $VCFolder= "$path\VC\Tools\MSVC\" if (Test-Path $VCFolder) { Write-Verbose "Picking: $instanceCandidate" return "$path\MSBuild\Current\Bin\MSBuild.exe", "v142" } } if ($majorVersion -eq "15") { $VCFolder= "$path\VC\Tools\MSVC\" if (Test-Path $VCFolder) { Write-Verbose "Picking: $instanceCandidate" return "$path\MSBuild\15.0\Bin\MSBuild.exe", "v141" } } if ($majorVersion -eq "14") { $clExe= "$path\VC\bin\cl.exe" if (Test-Path $clExe) { Write-Verbose "Picking: $instanceCandidate" $programFilesPath = getProgramFiles32bit return "$programFilesPath\MSBuild\14.0\Bin\MSBuild.exe", "v140" } } } throw "Could not find MSBuild version with C++ support. VS2015, VS2017, or VS2019 (with C++) needs to be installed." } function getWindowsSDK( [Parameter(Mandatory=$False)][switch]$DisableWin10SDK = $False, [Parameter(Mandatory=$False)][switch]$DisableWin81SDK = $False, [Parameter(Mandatory=$False)][string]$withWinSDK) { if ($DisableWin10SDK -and $DisableWin81SDK) { throw "Both Win10SDK and Win81SDK were disabled." } Write-Verbose "Finding WinSDK" $validInstances = New-Object System.Collections.ArrayList # Windows 10 SDK function CheckWindows10SDK($path) { if ($path -eq $null) { return } $folder = (Join-Path $path "Include") if (!(Test-Path $folder)) { Write-Verbose "$folder - Not Found" return } Write-Verbose "$folder - Found" $win10sdkVersions = @(Get-ChildItem $folder | Where-Object {$_.Name -match "^10"} | Sort-Object) [array]::Reverse($win10sdkVersions) # Newest SDK first foreach ($win10sdkV in $win10sdkVersions) { $windowsheader = "$folder\$win10sdkV\um\windows.h" if (!(Test-Path $windowsheader)) { Write-Verbose "$windowsheader - Not Found" continue } Write-Verbose "$windowsheader - Found" $ddkheader = "$folder\$win10sdkV\shared\sdkddkver.h" if (!(Test-Path $ddkheader)) { Write-Verbose "$ddkheader - Not Found" continue } Write-Verbose "$ddkheader - Found" $win10sdkVersionString = $win10sdkV.ToString() Write-Verbose "Found $win10sdkVersionString" $validInstances.Add($win10sdkVersionString) > $null } } Write-Verbose "`n" Write-Verbose "Looking for Windows 10 SDK" $regkey10 = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\' -Name 'KitsRoot10' -ErrorAction SilentlyContinue $regkey10Wow6432 = Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots\' -Name 'KitsRoot10' -ErrorAction SilentlyContinue if (vcpkgHasProperty -object $regkey10 "KitsRoot10") { CheckWindows10SDK($regkey10.KitsRoot10) } if (vcpkgHasProperty -object $regkey10Wow6432 "KitsRoot10") { CheckWindows10SDK($regkey10Wow6432.KitsRoot10) } CheckWindows10SDK("$env:ProgramFiles\Windows Kits\10") CheckWindows10SDK("${env:ProgramFiles(x86)}\Windows Kits\10") # Windows 8.1 SDK function CheckWindows81SDK($path) { if ($path -eq $null) { return } $folder = "$path\Include" if (!(Test-Path $folder)) { Write-Verbose "$folder - Not Found" return } Write-Verbose "$folder - Found" $win81sdkVersionString = "8.1" Write-Verbose "Found $win81sdkVersionString" $validInstances.Add($win81sdkVersionString) > $null } Write-Verbose "`n" Write-Verbose "Looking for Windows 8.1 SDK" $regkey81 = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots\' -Name 'KitsRoot81' -ErrorAction SilentlyContinue $regkey81Wow6432 = Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots\' -Name 'KitsRoot81' -ErrorAction SilentlyContinue if (vcpkgHasProperty -object $regkey81 "KitsRoot81") { CheckWindows81SDK($regkey81.KitsRoot81) } if (vcpkgHasProperty -object $regkey81Wow6432 "KitsRoot81") { CheckWindows81SDK($regkey81Wow6432.KitsRoot81) } CheckWindows81SDK("$env:ProgramFiles\Windows Kits\8.1") CheckWindows81SDK("${env:ProgramFiles(x86)}\Windows Kits\8.1") Write-Verbose "`n`n`n" Write-Verbose "The following Windows SDKs were found:" foreach ($instance in $validInstances) { Write-Verbose $instance } # Selecting if ($withWinSDK -ne "") { foreach ($instance in $validInstances) { if ($instance -eq $withWinSDK) { return $instance } } throw "Could not find the requested Windows SDK version: $withWinSDK" } foreach ($instance in $validInstances) { if (!$DisableWin10SDK -and $instance -match "10.") { return $instance } if (!$DisableWin81SDK -and $instance -match "8.1") { return $instance } } throw "Could not detect a Windows SDK / TargetPlatformVersion" } $msbuildExeWithPlatformToolset = findAnyMSBuildWithCppPlatformToolset $withVSPath $msbuildExe = $msbuildExeWithPlatformToolset[0] $platformToolset = $msbuildExeWithPlatformToolset[1] $windowsSDK = getWindowsSDK -withWinSDK $withWinSDK $disableMetricsValue = "0" if ($disableMetrics) { $disableMetricsValue = "1" } $platform = "x86" $vcpkgReleaseDir = "$vcpkgSourcesPath\msbuild.x86.release" if ($win64) { $architecture=(Get-WmiObject win32_operatingsystem | Select-Object osarchitecture).osarchitecture if (-not $architecture -like "*64*") { throw "Cannot build 64-bit on non-64-bit system" } $platform = "x64" $vcpkgReleaseDir = "$vcpkgSourcesPath\msbuild.x64.release" } $arguments = ( "`"/p:VCPKG_VERSION=-nohash`"", "`"/p:DISABLE_METRICS=$disableMetricsValue`"", "/p:Configuration=Release", "/p:Platform=$platform", "/p:PlatformToolset=$platformToolset", "/p:TargetPlatformVersion=$windowsSDK", "/p:PreferredToolArchitecture=x64", "/verbosity:minimal", "/m", "/nologo", "`"$vcpkgSourcesPath\dirs.proj`"") -join " " function vcpkgInvokeCommandClean() { param ( [Parameter(Mandatory=$true)][string]$executable, [string]$arguments = "") Write-Verbose "Clean-Executing: ${executable} ${arguments}" $scriptsDir = split-path -parent $script:MyInvocation.MyCommand.Definition $cleanEnvScript = "$scriptsDir\cleanEnvironmentHelper.ps1" $tripleQuotes = "`"`"`"" $argumentsWithEscapedQuotes = $arguments -replace "`"", $tripleQuotes $command = ". $tripleQuotes$cleanEnvScript$tripleQuotes; & $tripleQuotes$executable$tripleQuotes $argumentsWithEscapedQuotes" $arg = "-NoProfile", "-ExecutionPolicy Bypass", "-command $command" $process = Start-Process -FilePath powershell.exe -ArgumentList $arg -PassThru -NoNewWindow Wait-Process -InputObject $process $ec = $process.ExitCode Write-Verbose "Execution terminated with exit code $ec." return $ec } # vcpkgInvokeCommandClean cmd "/c echo %PATH%" Write-Host "`nBuilding vcpkg.exe ...`n" $ec = vcpkgInvokeCommandClean $msbuildExe $arguments if ($ec -ne 0) { Write-Error "Building vcpkg.exe failed. Please ensure you have installed Visual Studio with the Desktop C++ workload and the Windows SDK for Desktop C++." return } Write-Host "`nBuilding vcpkg.exe... done.`n" Write-Verbose "Placing vcpkg.exe in the correct location" Copy-Item "$vcpkgReleaseDir\vcpkg.exe" "$vcpkgRootDir\vcpkg.exe" Copy-Item "$vcpkgReleaseDir\vcpkgmetricsuploader.exe" "$vcpkgRootDir\scripts\vcpkgmetricsuploader.exe" Remove-Item "$vcpkgReleaseDir" -Force -Recurse -ErrorAction SilentlyContinue