diff --git a/.github/workflows/cmake-builds.yml b/.github/workflows/cmake-builds.yml index 8c13a664..dec03bb7 100644 --- a/.github/workflows/cmake-builds.yml +++ b/.github/workflows/cmake-builds.yml @@ -127,101 +127,8 @@ jobs: Where-Object { $_ -notlike "*\Strawberry\*" -and $_ -notlike "*/Strawberry/*" }) -join ';' $env:Path = $fixPATH - #+ - # Update the existing Github Visual Studio installation in-place. `vswhere` may find multiple - # VS installations, so iterate through them all. - # - # This is Grey Magic. `vs_installer` exits almost immediately if you run it from the command - # line. However, `vs_installer`'s subprocesses are well known and we look for them and wait - # for them to terminate. - # - # GH Actions does something strange with stdout and stderr, so you won't get any - # indication of failure or output that shows you that something is happening. - # - # The waiting code was adapted from the Chocolatey VS installer scripts. - #- - $vswhere = "${env:ProgramFiles} (x86)\Microsoft Visual Studio\Installer\vswhere" - $vsinstaller = "${env:ProgramFiles} (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" - $vsInstallOut = "$env:TEMP\vsinstall-out.txt" - $vsInstallErr = "$env:TEMP\vsinstall-err.txt" - - & ${vswhere} -property installationPath | ` - Foreach-Object -process { - ## --quiet: Don't open/show UI - ## --force: Terminate any VS instances forcibly - ## --norestart: Delay reboot after install, if needed - ## --installWhileDownloading: Self-explanitory. - $Params = @( - "modify", - "--installPath", "$_", - "--add", "Microsoft.VisualStudio.Component.VC.v141.x86.x64", - "--add", "Microsoft.VisualStudio.Component.WinXP", - "--quiet", "--force", "--norestart", "--installWhileDownloading" - ) - - & $vsInstaller $Params 2> $vsInstallErr > $vsInstallOut - - $vsinstallerProcesses = @('vs_installer', 'vs_installershell', 'vs_installerservice') - $vsInstallerStartup = $true - $vsInstallerStartCount = 10 - - do - { - Write-Debug ('Looking for running VS installer processes') - $vsInstallerRemaining = Get-Process -Name $vsinstallerProcesses -ErrorAction SilentlyContinue | Where-Object { $null -ne $_ -and -not $_.HasExited } - $vsInstallerProcessCount = ($vsInstallerRemaining | Measure-Object).Count - if ($vsInstallerProcessCount -gt 0) - { - ## Installer processes are present, so obviously not starting up. - $vsInstallerStartup = $false - try - { - Write-Debug "Found $vsInstallerProcessCount running Visual Studio installer processes which are known to exit asynchronously:" - $vsInstallerRemaining | Sort-Object -Property Name, Id | ForEach-Object { '[{0}] {1}' -f $_.Id, $_.Name } | Write-Debug - Write-Debug ('Giving the processes some time to exit') - $vsInstallerRemaining | Wait-Process -Timeout 45 -ErrorAction SilentlyContinue - } - finally - { - $vsInstallerRemaining | ForEach-Object { $_.Dispose() } - $vsInstallerRemaining = $null - } - } else { - if ($vsInstallerStartup) { - if ($vsInstallerStartCount -gt 0) { - Write-Debug "No VS installer processes detected; sleeping with $vsInstallerStartCount tries remaining." - Start-Sleep -Seconds 10.0 - $vsInstallerStartCount -= 1 - } else { - $vsInstallerStartup = $false - Write-Debug "VS installer never started? Exiting." - Exit 99 - } - } - } - } - while (($vsInstallerStartup -and $vsInstallerStartCount -gt 0) -or $vsInstallerProcessCount -gt 0) - } - - if ((Test-Path $vsInstallOut -PathType Leaf) -and (Get-Item $vsInstallOut).length -gt 0kb) - { - Write-Output "-- vsinstaller output:" - Get-Content $vsInstallOut - } - else - { - Write-Debug "-- No vsinstaller output." - } - - if ((Test-Path $vsInstallErr -PathType Leaf) -and (Get-Item $vsInstallErr).length -gt 0kb) - { - Write-Output "-- vsinstaller error output:" - Get-Content $vsInstallErr - } - else - { - Write-Debug "-- No vsinstaller error/diag output." - } + ## Install the XP toolkit, aka v141_xp. This script is specific to the Github environment. + ./cmake/github_v141_xp.ps1 #+ # The GH Windows runner image documentation says that the VSSetup module is installed, from @@ -229,7 +136,15 @@ jobs: # paranoia, ensuring that we really, truly and honestly have WinXP support. #- Write-Debug "Get-VSSetupInstance/Select-VSSetupInstance" - Get-VSSetupInstance -All | Select-VSSetupInstance -Require 'Microsoft.VisualStudio.Component.WinXP' -Latest + $instances=$(Get-VSSetupInstance -All | Select-VSSetupInstance -Require 'Microsoft.VisualStudio.Component.WinXP' -Latest) + if ($null -eq $instances) + { + throw "v141_xp didn't install correctly or incomplete install." + } + else + { + $instances | Write-Output + } ## Don't use LTO for XP. XP compatibility comes from VS2017 -- MS is ## at VS2022. There are likely legacy bugs that have been fixed. diff --git a/cmake/CMake-Maintainers.md b/cmake/CMake-Maintainers.md index 786d5bd4..ce44d196 100644 --- a/cmake/CMake-Maintainers.md +++ b/cmake/CMake-Maintainers.md @@ -130,6 +130,8 @@ open-simh This is CMAKE_SOURCE_DIR | | CMakeLists.txt from the makefile | +-- git-commit-id.cmake CMake script to update .git-commit-id and | | .git-commit-id.h +| +-- github_v141_xp.ps1 Visual Studio "XP toolkit" installer PowerShell +| | script | +-- installer-customizations Installer-specific customization files | +-- os-features.cmake Operating system feature probes, e.g., -lm | +-- patches Patches applied to external dependency libs @@ -142,8 +144,6 @@ open-simh This is CMAKE_SOURCE_DIR | | CPack components (simulator "families") | +-- simh-simulators.cmake Simulator add_subdirectory includes, variable | | definitions -| +-- v141_xp_install.ps1 Experimental Powershell script to install XP -| | compatibility support in Visual Studio (unused) | +-- vcpkg-setup.cmake vcpkg package manager setup code ``` diff --git a/cmake/github_v141_xp.ps1 b/cmake/github_v141_xp.ps1 new file mode 100644 index 00000000..bee747d9 --- /dev/null +++ b/cmake/github_v141_xp.ps1 @@ -0,0 +1,153 @@ +<# +.SYNOPSIS +Install Visual Studio's 'v141_xp' XP toolkit on Github. + +.DESCRIPTION +Update the existing Github Visual Studio installation in-place. This script +will iterate through all VS installations identified by the `vswhere` utility. + +This script is Grey Magic. The `vs_installer` installer utility exits almost +immediately if you run it from the command line. `vs_installer`'s subprocesses +are reasonably well known, which allows this script to query the processes and +wait for them to terminate. + +GitHub Actions does something strange with stdout and stderr, so you won't get any +indication of failure or output that shows you that something is happening. + +The waiting code was adapted from the Chocolatey VS installer scripts (Wait-VSIstallerProcesses). + +Ref: https://github.com/jberezanski/ChocolateyPackages/blob/master/chocolatey-visualstudio.extension/extensions/Wait-VSInstallerProcesses.ps1 +#> + +$exitcode = $null +$vswhere = "${env:ProgramFiles} (x86)\Microsoft Visual Studio\Installer\vswhere" +$vsinstaller = "${env:ProgramFiles} (x86)\Microsoft Visual Studio\Installer\vs_installer.exe" +$vsInstallOut = "$env:TEMP\vsinstall-out.txt" +$vsInstallErr = "$env:TEMP\vsinstall-err.txt" + +& ${vswhere} -property installationPath | Foreach-Object -process { + # Save the installlation path for the current iteration + $installPath = $_ + + # Make sure that previously running installers have all exited. + Write-Debug ('Looking for previously running VS installer processes') + $lazyQuitterProcessNames = @('vs_installershell', 'vs_installerservice') + do + { + $lazyQuitterProcesses = Get-Process -Name $lazyQuitterProcessNames -ErrorAction SilentlyContinue | ` + Where-Object { $null -ne $_ -and -not $_.HasExited } + $lazyQuitterProcessCount = ($lazyQuitterProcesses | Measure-Object).Count + if ($lazyQuitterProcessCount -gt 0) + { + try + { + $lazyQuitterProcesses | Sort-Object -Property Name, Id | ForEach-Object { '[{0}] {1}' -f $_.Id, $_.Name } | Write-Debug + $lazyQuitterProcesses | Wait-Process -Timeout 10 -ErrorAction SilentlyContinue + } + finally + { + $lazyQuitterProcesses | ForEach-Object { $_.Dispose() } + $lazyQuitterProcesses = $null + } + } + } + while ($lazyQuitterProcessCount -gt 0) + + ## Now kick off our install: + ## + ## --quiet: Don't open/show UI + ## --force: Terminate any VS instances forcibly + ## --norestart: Delay reboot after install, if needed + ## --installWhileDownloading: Self-explanitory. + ## + ## Note: "--wait" doesn't. + $vsinstallParams = @( + "modify", + "--installPath", "$installPath", + "--add", "Microsoft.VisualStudio.Component.VC.v141.x86.x64", + "--add", "Microsoft.VisualStudio.Component.WinXP", + "--quiet", "--force", "--norestart", "--installWhileDownloading" + ) + + & $vsInstaller $vsinstallParams 2> $vsInstallErr > $vsInstallOut + + ## VS installer processes for which we want to wait because installation isn't complete. Yet. + $vsinstallerProcesses = @( 'vs_bootstrapper', 'vs_setup_bootstrapper', 'vs_installer', 'vs_installershell', ` + 'vs_installerservice', 'setup') + $vsInstallerProcessFilter = { $_.Name -ne 'setup' -or $_.Path -like '*\Microsoft Visual Studio\Installer*\setup.exe' } + do + { + Write-Debug ('Looking for running VS installer processes') + $vsInstallerRemaining = Get-Process -Name $vsinstallerProcesses -ErrorAction SilentlyContinue | ` + Where-Object { $null -ne $_ -and -not $_.HasExited } | ` + Where-Object $vsInstallerProcessFilter + $vsInstallerProcessCount = ($vsInstallerRemaining | Measure-Object).Count + if ($vsInstallerProcessCount -gt 0) + { + try + { + Write-Debug "Found $vsInstallerProcessCount running Visual Studio installer processes:" + $vsInstallerRemaining | Sort-Object -Property Name, Id | ForEach-Object { '[{0}] {1}' -f $_.Id, $_.Name } | Write-Debug + + foreach ($p in $vsInstallerProcesses) + { + [void] $p.Handle # make sure we get the exit code http://stackoverflow.com/a/23797762/266876 + } + + Write-Debug ('Waiting 60 seconds for process(es) to exit...') + $vsInstallerRemaining | Wait-Process -Timeout 60 -ErrorAction SilentlyContinue + + foreach ($proc in $vsInstallerProcesses) + { + if (-not $proc.HasExited) + { + continue + } + if ($null -eq $exitCode) + { + $exitCode = $proc.ExitCode + } + if ($proc.ExitCode -ne 0 -and $null -ne $proc.ExitCode) + { + Write-Debug "$($proc.Name) process $($proc.Id) exited with code $($proc.ExitCode)" + if ($exitCode -eq 0) + { + $exitCode = $proc.ExitCode + } + } + } + } + finally + { + $vsInstallerRemaining | ForEach-Object { $_.Dispose() } + $vsInstallerRemaining = $null + } + } + } + while (($vsInstallerStartup -and $vsInstallerStartCount -gt 0) -or $vsInstallerProcessCount -gt 0) +} + +if ((Test-Path $vsInstallOut -PathType Leaf) -and (Get-Item $vsInstallOut).length -gt 0kb) +{ + Write-Output "-- vsinstaller output:" + Get-Content $vsInstallOut +} +else +{ + Write-Debug "-- No vsinstaller output." +} + +if ((Test-Path $vsInstallErr -PathType Leaf) -and (Get-Item $vsInstallErr).length -gt 0kb) +{ + Write-Output "-- vsinstaller error output:" + Get-Content $vsInstallErr +} +else +{ + Write-Debug "-- No vsinstaller error/diag output." +} + +if ($null -ne $exitcode -and $exitcode -ne 0) +{ + throw "VS installer exited with non-zero exit status: $exitcode" +} diff --git a/cmake/v141_xp_install.ps1 b/cmake/v141_xp_install.ps1 deleted file mode 100644 index c480c7f4..00000000 --- a/cmake/v141_xp_install.ps1 +++ /dev/null @@ -1,84 +0,0 @@ -$vsFlavor=$args[0] -$vsSetupDir="C:\Program Files (x86)\Microsoft Visual Studio\installer" -$vswhere="${vsSetupDir}\vswhere.exe" -$vsinstaller="${vsSetupDir}\vs_installer.exe" - -$vstudios = @{ - "vs2017" = @{ - names = @{ - "Visual Studio Enterprise 2019" = "Microsoft.VisualStudio.Product.Enterprise" - "Visual Studio Professional 2019" = "Microsoft.VisualStudio.Product.Professional" - "Visual Studio Community 2019" = "Microsoft.VisualStudio.Product.Community" - } - channelId = "VisualStudio.15.Release" - v141toolkit = @( "Microsoft.VisualStudio.Component.WinXP" ) - } - "vs2019" = @{ - names = @{ - "Visual Studio Enterprise 2019" = "Microsoft.VisualStudio.Product.Enterprise" - "Visual Studio Professional 2019" = "Microsoft.VisualStudio.Product.Professional" - "Visual Studio Community 2019" = "Microsoft.VisualStudio.Product.Community" - } - displayName = "Visual Studio Community 2019" - channelId = "VisualStudio.16.Release" - v141toolkit = @( "Microsoft.VisualStudio.Component.VC.v141.x86.x64", "Microsoft.VisualStudio.Component.WinXP" ) - } - "vs2022" = @{ - names = @{ - "Visual Studio Enterprise 2022" = "Microsoft.VisualStudio.Product.Enterprise" - "Visual Studio Professional 2022" = "Microsoft.VisualStudio.Product.Professional" - "Visual Studio Community 2022" = "Microsoft.VisualStudio.Product.Community" - } - installedChannelId = "VisualStudio.17.Release" - v141toolkit = @( "Microsoft.VisualStudio.Component.VC.v141.x86.x64", "Microsoft.VisualStudio.Component.WinXP" ) - } -} - -if ($args.length -eq 0) { - "Womabt!!" - exit 1 -} - -$wantedVS = $vstudios[$args[0]] -if ($wantedVS -eq $null) { - "Wibbles." - exit 1 -} - -Set-PSDebug -Trace 1 - -if (Test-Path -Path $vsinstaller) { - if (Test-Path -Path $vswhere) { - $vsinfo=$(& $vswhere -format json | ConvertFrom-JSON) - foreach ($vs in $vsinfo) { - $productId = $wantedVS.names[$vs.displayName] - if ($productId -ne $null) { - Write-Output $("Found: " + $vs.displayName) - - $args = @( "modify", "--quiet") - $args += @( "--channelId", $wantedVS.installedChannelId ) - $args += @( "--productId", $productId ) - - foreach ($c in $wantedVS.v141toolkit) { - $args += @( "--add", $c ) - } - - Write-Output $( ( @("Executing: ", $vsinstaller) + $args ) -join " " ) - - $proc = Start-Process -Verbose -NoNewWindow -PassThru $vsinstaller -ArgumentList $args - $proc.WaitForExit() - - $proc = Start-Process -NoNewWindow -PassThru $vsinstaller -ArgumentList @("export", "--channelId", $wantedVS.installedChannelId, "--productId", $productId, "--config", "vsinstall.after", "--quiet") - $proc.WaitForExit() - - if (Test-Path -Path .\vsinstall.after) { - Get-Content .\vsinstall.after - } - } - } - } else { - Write-Ouput @("vswhere not found or available. ", $vswhere) -join " " - } -} else { - Write-Ouput @("VS installer not found or available. ", $vsinstaller) -join " " -}