Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Visual Studio BuildTools as a MinGW alternative #23212

Merged
merged 1 commit into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions build_windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Windows.
- [Git and go](#git-and-go)
- [Pandoc](#pandoc)
- [.NET SDK](#net-sdk)
- [Visual Studio Build Tools](#visual-studio-build-tools)
- [Virtualization Provider](#virtualization-provider)
- [WSL](#wsl)
- [Hyper-V](#hyper-v)
Expand Down Expand Up @@ -87,6 +88,30 @@ used too and can be installed using `dotnet install`:
dotnet tool install --global wix
```

### Visual Studio Build Tools

The installer includes a C program that checks the installation of the
pre-required virtualization providers (WSL or Hyper-V). Building this program
requires the
[Microsoft C/C++ compiler](https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170) and the
[PowerShell Moduel VSSetup](https://github.com/microsoft/vssetup.powershell):

1. Download the Build Tools for Visual Studio 2022 installer
```pwsh
Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile "$env:TEMP\vs_BuildTools.exe"
```
2. Run the installer with the parameter to include the optional C/C++ Tools
```pwsh
& "$env:TEMP\vs_BuildTools.exe" --passive --wait `
--add Microsoft.VisualStudio.Workload.VCTools `
--includeRecommended `
--remove Microsoft.VisualStudio.Component.VC.CMake.Project
```
3. Install the PowerShell Module VSSetup
```pwsh
Install-Module VSSetup
```

### Virtualization Provider

Running Podman on Windows requires a virtualization provider. The supported
Expand Down Expand Up @@ -340,6 +365,9 @@ otherwise):
contrib\win-installer\podman-5.1.0-dev-setup.exe /install /log podman-setup.log /quiet MachineProvider=wsl WSLCheckbox=0 HyperVCheckbox=0
```

:information_source: The `winmake.ps1` target `installertest` automatically
tests installing and uninstalling Podman.

### Build and test the standalone `podman.msi` file

Building and testing the standalone `podman.msi` package during development may
Expand Down
56 changes: 11 additions & 45 deletions contrib/cirrus/win-installer-main.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,21 @@ if ($Env:CI -eq "true") {
$ENV:CONTAINERS_MACHINE_PROVIDER = "wsl"
}

$ConfFilePath = "$env:ProgramData\containers\containers.conf.d\99-podman-machine-provider.conf"
$WindowsPathsToTest = @("C:\Program Files\RedHat\Podman\podman.exe",
"C:\Program Files\RedHat\Podman\win-sshproxy.exe",
"$ConfFilePath",
"HKLM:\SOFTWARE\Red Hat\Podman")

Push-Location $WIN_INST_FOLDER

# Build Installer
# Note: consumes podman-remote-release-windows_amd64.zip from repo.tbz2
Run-Command ".\build.ps1 $Env:WIN_INST_VER dev `"$RELEASE_DIR`""

# Run the installer silently and WSL/HyperV install options disabled (prevent reboots)
# We need AllowOldWin=1 for server 2019 (cirrus image), can be dropped after server 2022
$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/install /quiet MachineProvider=$ENV:CONTAINERS_MACHINE_PROVIDER WSLCheckbox=0 HyperVCheckbox=0 AllowOldWin=1 /log inst.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Install failed, dumping log"
Get-Content inst.log
Pop-Location
throw "Exit code is $($ret.ExitCode)"
}
$WindowsPathsToTest | ForEach-Object {
if (! (Test-Path -Path $_) ) {
Pop-Location
throw "Expected $_ but it's not present after uninstall"
}
}
$machineProvider = Get-Content $ConfFilePath | Select-Object -Skip 1 | ConvertFrom-StringData | ForEach-Object { $_.provider }
if ( $machineProvider -ne "`"$ENV:CONTAINERS_MACHINE_PROVIDER`"" ) {
Pop-Location
throw "Expected `"$ENV:CONTAINERS_MACHINE_PROVIDER`" as default machine provider but got $machineProvider"
}

Write-Host "Installer verification successful!"

# Run the uninstaller silently to verify that it cleans up properly
$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/uninstall /quiet /log uninst.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Uninstall failed, dumping log"
Get-Content uninst.log
Pop-Location
throw "Exit code is $($ret.ExitCode)"
}
$WindowsPathsToTest | ForEach-Object {
if ( Test-Path -Path $_ ) {
Pop-Location
throw "Path $_ is still present after uninstall"
}
}

Write-Host "Uninstaller verification successful!"
Pop-Location

# Run the installer silently and WSL/HyperV install options disabled (prevent reboots)
# We need -skipWinVersionCheck for server 2019 (cirrus image), can be dropped after server 2022
$command = "$WIN_INST_FOLDER\test-installer.ps1 "
$command += "-operation all "
$command += "-provider $ENV:CONTAINERS_MACHINE_PROVIDER "
$command += "-setupExePath `"$WIN_INST_FOLDER\podman-$ENV:WIN_INST_VER-dev-setup.exe`" "
$command += "-installWSL:`$false "
$command += "-installHyperV:`$false "
$command += "-skipWinVersionCheck:`$true"
Run-Command "${command}"
6 changes: 0 additions & 6 deletions contrib/win-installer/build-hooks.bat

This file was deleted.

67 changes: 67 additions & 0 deletions contrib/win-installer/build-hooks.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function Build-WSLKernelInstaller {
param (
[string]$wslkerninstFolder,
[string]$artifactsFolder
);
Set-Variable GOARCH=amd64
go build -ldflags -H=windowsgui -o "$artifactsFolder\podman-wslkerninst.exe" "$wslkerninstFolder"
}

function Build-MSIHooks {
param (
[string]$msiHooksFolder,
[string]$artifactsFolder
);

# Build using x86 toolchain, see comments in check.c for rationale and details
if ( Get-MingW ) {
Build-MSIHooks-Using-MingW $msiHooksFolder $artifactsFolder
} elseif ( Get-VSBuildTools ) {
$vsinstance = Get-VSSetupInstance | Select-VSSetupInstance -Product Microsoft.VisualStudio.Product.BuildTools
Build-MSIHooks-Using-VSBuildTools $msiHooksFolder $artifactsFolder $vsinstance
} else {
$msg = "A C/C++ compiler is required to build `"$msiHooksFolder\check.c`". "
$msg += "Supported compilers are MinGW CC (`"x86_64-w64-mingw32-gcc`") and the "
$msg += "`"Microsoft.VisualStudio.Product.BuildTools`" with `"VSSetup`" PowerShell extension."
Write-Error -Message $msg -ErrorAction Stop
}
}

function Get-MingW {
return Get-Command "x86_64-w64-mingw32-gcc" -errorAction SilentlyContinue
}

function Get-VSBuildTools {
return ((Get-Command "Get-VSSetupInstance" -errorAction SilentlyContinue) -and `
(@(Get-VSSetupInstance | Select-VSSetupInstance -Product "Microsoft.VisualStudio.Product.BuildTools").Count -gt 0))
}

function Build-MSIHooks-Using-MingW {
param (
[string]$msiHooksFolder,
[string]$artifactsFolder
);
Set-Variable GOARCH=amd64
x86_64-w64-mingw32-gcc $msiHooksFolder/check.c -shared -lmsi -mwindows -o $artifactsFolder/podman-msihooks.dll
}

function Build-MSIHooks-Using-VSBuildTools {
param (
[string]$msiHooksFolder,
[string]$artifactsFolder,
[Microsoft.VisualStudio.Setup.Instance]$vsinstance
);
$vspath = $vsinstance.InstallationPath
$vsinstanceid = $vsinstance.InstanceId

Import-Module "$vspath\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
Enter-VsDevShell $vsinstanceid -DevCmdArguments '-arch=amd64 -host_arch=amd64'
cl.exe /W4 /Fo$artifactsFolder\ $msiHooksFolder\check.c Advapi32.lib Msi.lib /link /DLL /out:$artifactsFolder\podman-msihooks.dll
}

$wslkerninstFolder="$PSScriptRoot\..\..\cmd\podman-wslkerninst"
$msiHooksFolder="$PSScriptRoot\podman-msihooks"
$artifactsFolder="$PSScriptRoot\artifacts"

Build-WSLKernelInstaller $wslkerninstFolder $artifactsFolder
Build-MSIHooks $msiHooksFolder $artifactsFolder
3 changes: 1 addition & 2 deletions contrib/win-installer/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ function CheckCommand() {
}

function CheckRequirements() {
CheckCommand "gcc" "MingW CC"
CheckCommand "wix" "WiX Toolset"
CheckCommand "go" "Golang"
}
Expand Down Expand Up @@ -104,7 +103,7 @@ if ($ENV:INSTVER -eq "") {
Exit 1
}

.\build-hooks.bat; ExitOnError
.\build-hooks.ps1; ExitOnError
SignItem @("artifacts/win-sshproxy.exe",
"artifacts/podman.exe",
"artifacts/podman-msihooks.dll",
Expand Down
93 changes: 93 additions & 0 deletions contrib/win-installer/test-installer.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env pwsh

# The Param statement must be the first statement, except for comments and any #Require statements.
param (
[Parameter(Mandatory)]
[ValidateSet("install", "uninstall", "all")]
[string]$operation,
[Parameter(Mandatory)]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$setupExePath,
[ValidateSet("wsl", "hyperv")]
[string]$provider="wsl",
[switch]$installWSL=$false,
[switch]$installHyperV=$false,
[switch]$skipWinVersionCheck=$false
)

$ConfFilePath = "$env:ProgramData\containers\containers.conf.d\99-podman-machine-provider.conf"
$WindowsPathsToTest = @("C:\Program Files\RedHat\Podman\podman.exe",
"C:\Program Files\RedHat\Podman\win-sshproxy.exe",
"$ConfFilePath",
"HKLM:\SOFTWARE\Red Hat\Podman")

function Test-Installation {
if ($installWSL) {$wslCheckboxVar = "1"} else {$wslCheckboxVar = "0"}
if ($installHyperV) {$hypervCheckboxVar = "1"} else {$hypervCheckboxVar = "0"}
if ($skipWinVersionCheck) {$allowOldWinVar = "1"} else {$allowOldWinVar = "0"}

Write-Host "Running the installer (provider=`"$provider`")..."
$ret = Start-Process -Wait `
-PassThru "$setupExePath" `
-ArgumentList "/install /quiet `
MachineProvider=${provider} `
WSLCheckbox=${wslCheckboxVar} `
HyperVCheckbox=${hypervCheckboxVar} `
AllowOldWin=${allowOldWinVar} `
/log $PSScriptRoot\podman-setup.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Install failed, dumping log"
Get-Content $PSScriptRoot\podman-setup.log
throw "Exit code is $($ret.ExitCode)"
}

Write-Host "Verifying that the installer has created the expected files, folders and registry entries..."
$WindowsPathsToTest | ForEach-Object {
if (! (Test-Path -Path $_) ) {
throw "Expected $_ but it's not present after uninstall"
}
}

Write-Host "Verifying that the machine provider configuration is correct..."
$machineProvider = Get-Content $ConfFilePath | Select-Object -Skip 1 | ConvertFrom-StringData | ForEach-Object { $_.provider }
if ( $machineProvider -ne "`"$provider`"" ) {
throw "Expected `"$provider`" as default machine provider but got $machineProvider"
}

Write-Host "The installation verification was successful!`n"
}

function Test-Uninstallation {
Write-Host "Running the uninstaller"
$ret = Start-Process -Wait `
-PassThru "$setupExePath" `
-ArgumentList "/uninstall `
/quiet /log $PSScriptRoot\podman-setup-uninstall.log"
if ($ret.ExitCode -ne 0) {
Write-Host "Uninstall failed, dumping log"
Get-Content $PSScriptRoot\podman-setup-uninstall.log
throw "Exit code is $($ret.ExitCode)"
}

Write-Host "Verifying that the uninstaller has removed files, folders and registry entries as expected..."
$WindowsPathsToTest | ForEach-Object {
if ( Test-Path -Path $_ ) {
throw "Path $_ is still present after uninstall"
}
}

Write-Host "The uninstallation verification was successful!`n"
}

switch ($operation) {
'install' {
Test-Installation
}
'uninstall' {
Test-Uninstallation
}
'all' {
Test-Installation
Test-Uninstallation
}
}
48 changes: 48 additions & 0 deletions winmake.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,44 @@ function Installer{
Pop-Location
}

function Test-Installer{
param (
[string]$version,
[ValidateSet("dev", "prod")]
[string]$flavor = "dev",
[ValidateSet("wsl", "hyperv")]
[string]$provider = "wsl"
);

if (-Not $version) {
# Get Podman version from local source code
$version = Get-Podman-Version
}

if ($flavor -eq "prod") {
$suffix = ""
} else {
$suffix = "-dev"
}

$setupExePath = "$PSScriptRoot\contrib\win-installer\podman-${version}${suffix}-setup.exe"
if (!(Test-Path -Path $setupExePath -PathType Leaf)) {
Write-Host "Setup executable not found in path $setupExePath."
Write-Host "Make 'installer' before making the installer test:"
Write-Host " .\winmake.ps1 installer"
Exit 1
}

$command = "$PSScriptRoot\contrib\win-installer\test-installer.ps1"
$command += " -operation all"
$command += " -provider $provider"
$command += " -setupExePath $setupExePath"
$command += " -installWSL:`$false"
$command += " -installHyperV:`$false"
$command += " -skipWinVersionCheck:`$true"
Run-Command "${command}"
}

function Documentation{
Write-Host "Generating the documentation artifacts"
# Check that pandoc is installed
Expand Down Expand Up @@ -249,6 +287,13 @@ switch ($target) {
'installer' {
Installer
}
'installertest' {
if ($args.Count -gt 1) {
Test-Installer -provider $args[1]
} else {
Test-Installer
}
}
'docs' {
Documentation
}
Expand Down Expand Up @@ -276,6 +321,9 @@ switch ($target) {
Write-Host "Example: Build the windows installer"
Write-Host " .\winmake installer"
Write-Host
Write-Host "Example: Run windows installer tests"
Write-Host " .\winmake installertest"
Write-Host
Write-Host "Example: Generate the documetation artifacts"
Write-Host " .\winmake docs"
Write-Host
Expand Down