Skip to content

Commit 85e7154

Browse files
authored
Add reusable action for MSVC + Win SDK overrides (#956)
This introduces a new reusable action, `setup-build`, which will eventually replace all of the custom installation steps in the swift-build jobs. Currently it only supports providing explicit versions for MSVC and the Windows SDK. This also adds tests for the `setup-build` action, with a configurable runner, ensuring we can catch issues early as runner images get updated.
1 parent 35955c9 commit 85e7154

File tree

2 files changed

+455
-0
lines changed

2 files changed

+455
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
name: Setup build
2+
description: Sets up the build environment for the current job
3+
4+
inputs:
5+
windows-sdk-version:
6+
description: The Windows SDK version to use, e.g. "10.0.22621.0"
7+
required: false
8+
type: string
9+
msvc-version:
10+
description: The Windows MSVC version to use, e.g. "14.42"
11+
required: false
12+
type: string
13+
setup-vs-dev-env:
14+
description: Whether to set up a Visual Studio Dev Environment
15+
default: false
16+
required: false
17+
type: boolean
18+
host-arch:
19+
description: |
20+
The output's host architecture, "x86", "amd64" or "arm64". Defaults to the build architecture
21+
(a.k.a. the current runner's architecture).
22+
This is the target architecture for the Visual Studio Developer Environment.
23+
required: false
24+
type: string
25+
26+
outputs:
27+
windows-build-tools-version:
28+
description: |
29+
The full version of the Windows build tools installed, eg. "14.42.34433". This is only set
30+
if the `msvc-version` input was provided, and only on Windows.
31+
value: ${{ steps.install-msvc.outputs.windows-build-tools-version }}
32+
33+
runs:
34+
using: composite
35+
steps:
36+
- name: Sanitize input
37+
id: sanitize-input
38+
shell: pwsh
39+
run: |
40+
if ($IsWindows) {
41+
$BuildOS = "windows"
42+
} elseif ($IsMacOS) {
43+
$BuildOS = "macosx"
44+
} else {
45+
Write-Output "::error::Unsupported build OS."
46+
exit 1
47+
}
48+
49+
$Arch = ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture).ToString()
50+
switch ($Arch) {
51+
"X64" { $BuildArch = "amd64" }
52+
"Arm64" { $BuildArch = "arm64" }
53+
default {
54+
Write-Output "::error::Unsupported build architecture: `"$Arch`""
55+
exit 1
56+
}
57+
}
58+
59+
# Validate the MSVC version input.
60+
# If specified, it is expected to have a format "major.minor", without the build and
61+
# revision numbers. When a value such as "14.42" is parsed as a `System.Version`, the build
62+
# and revision numbers in that object are set to -1.
63+
$MSVCVersion = "${{ inputs.msvc-version }}"
64+
if ($MSVCVersion -ne "") {
65+
$ParsedMSVCVersion = [System.Version]::Parse($MSVCVersion)
66+
if ($ParsedMSVCVersion -eq $null) {
67+
Write-Output "::error::Invalid Windows MSVC version: `"${MSVCVersion}`"."
68+
exit 1
69+
}
70+
if ($ParsedMSVCVersion.Major -ne 14) {
71+
Write-Output "::error::Unsupported Windows MSVC version (major version not supported): `"${MSVCVersion}`"."
72+
exit 1
73+
}
74+
if ($ParsedMSVCVersion.Build -ne -1) {
75+
Write-Output "::error::Unsupported Windows MSVC version (build version was specified): `"${MSVCVersion}`"."
76+
exit 1
77+
}
78+
if ($ParsedMSVCVersion.Revision -ne -1) {
79+
Write-Output "::error::Unsupported Windows MSVC version (revision version was specified): `"${MSVCVersion}`"."
80+
exit 1
81+
}
82+
}
83+
84+
if ("${{ inputs.setup-vs-dev-env }}" -eq "true") {
85+
switch ("${{ inputs.host-arch }}") {
86+
"x86" { $HostArch = "x86" }
87+
"amd64" { $HostArch = "amd64" }
88+
"arm64" { $HostArch = "arm64" }
89+
"" { $HostArch = $BuildArch }
90+
default {
91+
Write-Output "::error::Unsupported host architecture: `"${{ inputs.host-arch }}`""
92+
exit 1
93+
}
94+
}
95+
} else {
96+
$HostArch = $BuildArch
97+
}
98+
99+
Write-Output "ℹ️ Build OS: $BuildOS"
100+
Write-Output "ℹ️ Build architecture: $BuildArch"
101+
Write-Output "ℹ️ Host architecture: $HostArch"
102+
103+
@"
104+
build-os=$BuildOS
105+
build-arch=$BuildArch
106+
host-arch=$HostArch
107+
"@ | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
108+
109+
- name: Install Windows SDK version ${{ inputs.windows-sdk-version }}
110+
if: steps.sanitize-input.outputs.build-os == 'windows' && inputs.windows-sdk-version != ''
111+
shell: pwsh
112+
run: |
113+
$WinSdkVersionString = "${{ inputs.windows-sdk-version }}"
114+
$WinSdkVersion = [System.Version]::Parse($WinSdkVersionString)
115+
$WinSdkVersionBuild = $WinSdkVersion.Build
116+
117+
$Win10SdkRoot = Get-ItemPropertyValue `
118+
-Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots" `
119+
-Name "KitsRoot10"
120+
$Win10SdkLib = Join-Path $Win10SdkRoot "Lib"
121+
$Win10SdkInclude = Join-Path $Win10SdkRoot "Include"
122+
$Win10SdkIncludeVersion = Join-Path $Win10SdkInclude $WinSdkVersionString
123+
124+
if (Test-Path -Path $Win10SdkIncludeVersion -PathType Container) {
125+
Write-Output "ℹ️ MSVCPackageVersionWindows SDK ${WinSdkVersionString} already installed."
126+
} else {
127+
# Install the missing SDK.
128+
Write-Output "ℹ️ Installing Windows SDK ${WinSdkVersionString}..."
129+
130+
$InstallerLocation = Join-Path "${env:ProgramFiles(x86)}" "Microsoft Visual Studio" "Installer"
131+
$VSWhere = Join-Path "${InstallerLocation}" "VSWhere.exe"
132+
$VSInstaller = Join-Path "${InstallerLocation}" "vs_installer.exe"
133+
$InstallPath = (& "$VSWhere" -latest -products * -format json | ConvertFrom-Json).installationPath
134+
$process = Start-Process "$VSInstaller" `
135+
-PassThru `
136+
-ArgumentList "modify", `
137+
"--installPath", "`"$InstallPath`"", `
138+
"--channelId", "https://aka.ms/vs/17/release/channel", `
139+
"--quiet", "--norestart", "--nocache", `
140+
"--add", "Microsoft.VisualStudio.Component.Windows11SDK.${WinSdkVersionBuild}"
141+
$process.WaitForExit()
142+
143+
if (Test-Path -Path $Win10SdkIncludeVersion -PathType Container) {
144+
Write-Output "ℹ️ Windows SDK ${WinSdkVersionString} installed successfully."
145+
} else {
146+
Write-Output "::error::Failed to install Windows SDK ${WinSdkVersionString}."
147+
Write-Output "Installer log:"
148+
$log = Get-ChildItem "${env:TEMP}" -Filter "dd_installer_*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
149+
Get-Content $log.FullName
150+
exit 1
151+
}
152+
}
153+
154+
# Remove more recent Windows SDKs, if present. This is used to work
155+
# around issues where LLVM uses the most recent Windows SDK.
156+
# This should be removed once a more permanent solution is found.
157+
# See https://github.com/compnerd/swift-build/issues/958 for details.
158+
Get-ChildItem -Path $Win10SdkInclude -Directory | ForEach-Object {
159+
$IncludeDirName = $_.Name
160+
try {
161+
$IncludeDirVersion = [System.Version]::Parse($IncludeDirName)
162+
if ($IncludeDirVersion -gt $WinSdkVersion) {
163+
$LibDirVersion = Join-Path $Win10SdkLib $IncludeDirName
164+
Write-Output "ℹ️ Removing folders for Windows SDK ${IncludeDirVersion}."
165+
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction Ignore
166+
Remove-Item -Path $LibDirVersion -Recurse -Force -ErrorAction Ignore
167+
}
168+
} catch {
169+
# Skip if the directory cannot be parsed as a version.
170+
}
171+
}
172+
173+
- name: Install Windows MSVC version ${{ inputs.msvc-version }}
174+
if: steps.sanitize-input.outputs.build-os == 'windows' && inputs.msvc-version != ''
175+
id: setup-msvc
176+
shell: pwsh
177+
run: |
178+
# This is assuming a VS2022 toolchain. e.g.
179+
# MSVC 14.42 corresponds to the 14.42.17.12 package.
180+
# MSVC 14.43 corresponds to the 14.43.17.13 package.
181+
$MSVCVersionString = "${{ inputs.msvc-version }}"
182+
183+
$InstallerLocation = Join-Path "${env:ProgramFiles(x86)}" "Microsoft Visual Studio" "Installer"
184+
$VSWhere = Join-Path "${InstallerLocation}" "VSWhere.exe"
185+
$VSInstaller = Join-Path "${InstallerLocation}" "vs_installer.exe"
186+
$InstallPath = (& "$VSWhere" -latest -products * -format json | ConvertFrom-Json).installationPath
187+
$MSVCDir = Join-Path $InstallPath "VC" "Tools" "MSVC"
188+
189+
# Compute the MSVC version package name from the MSVC version, assuming this is coming from
190+
# a VS2022 installation. The version package follows the following format:
191+
# * Major and minor version are the same as the MSVC version.
192+
# * Build version is always 17 (VS2002 is VS17).
193+
# * The revision is set to the number of minor versions since VS17 release.
194+
$MSVCVersion = [System.Version]::Parse($MSVCVersionString)
195+
$MajorVersion = $MSVCVersion.Major
196+
$MinorVersion = $MSVCVersion.Minor
197+
$BuildVersion = 17
198+
$RevisionVersion = $MinorVersion - 30
199+
$MSVCPackageVersion = "${MajorVersion}.${MinorVersion}.${BuildVersion}.${RevisionVersion}"
200+
201+
# Install the missing MSVC version.
202+
Write-Output "ℹ️ Installing MSVC packages for ${MSVCPackageVersion}..."
203+
$process = Start-Process "$VSInstaller" `
204+
-PassThru `
205+
-ArgumentList "modify", `
206+
"--installPath", "`"$InstallPath`"", `
207+
"--channelId", "https://aka.ms/vs/17/release/channel", `
208+
"--quiet", "--norestart", "--nocache", `
209+
"--add", "Microsoft.VisualStudio.Component.VC.${MSVCPackageVersion}.x86.x64", `
210+
"--add", "Microsoft.VisualStudio.Component.VC.${MSVCPackageVersion}.ATL", `
211+
"--add", "Microsoft.VisualStudio.Component.VC.${MSVCPackageVersion}.ARM64", `
212+
"--add", "Microsoft.VisualStudio.Component.VC.${MSVCPackageVersion}.ATL.ARM64"
213+
$process.WaitForExit()
214+
215+
# Check if the MSVC version was installed successfully.
216+
$MSVCBuildToolsVersion = ""
217+
foreach ($dir in Get-ChildItem -Path $MSVCDir -Directory) {
218+
$MSVCDirName = $dir.Name
219+
if ($MSVCDirName.StartsWith($MSVCVersionString)) {
220+
Write-Output "ℹ️ MSVC ${MSVCVersionString} installed successfully."
221+
$MSVCBuildToolsVersion = $MsvcDirName
222+
break
223+
}
224+
}
225+
226+
if ($MSVCBuildToolsVersion -eq "") {
227+
Write-Output "::error::Failed to install MSVC ${MSVCVersionString}."
228+
Write-Output "Installer log:"
229+
$log = Get-ChildItem "${env:TEMP}" -Filter "dd_installer_*.log" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
230+
Get-Content $log.FullName
231+
exit 1
232+
} else {
233+
Write-Output "ℹ️ MSVC ${MSVCBuildToolsVersion} installed successfully."
234+
"windows-build-tools-version=${MSVCBuildToolsVersion}" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
235+
}
236+
237+
- name: Setup Visual Studio Developer Environment
238+
if: steps.sanitize-input.outputs.build-os == 'windows' && inputs.setup-vs-dev-env == 'true'
239+
uses: compnerd/gha-setup-vsdevenv@5eb3eae1490d4f7875d574c4973539f69109700d # main
240+
with:
241+
host_arch: ${{ steps.sanitize-input.outputs.build-arch }}
242+
arch: ${{ steps.sanitize-input.outputs.host-arch }}
243+
winsdk: ${{ inputs.windows-sdk-version }}
244+
toolset_version: ${{ inputs.msvc-version }}

0 commit comments

Comments
 (0)