Skip to content
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
3 changes: 2 additions & 1 deletion Build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
<ItemGroup>
<!-- Microsoft.WindowsDesktop.App shared framework -->
<ProjectReference Include="src\windowsdesktop\src\sfx\**\*.sfxproj" />
<ProjectReference Include="src\windowsdesktop\src\bundle\**\*.bundleproj" />
<!-- Windows Desktop Runtime Bundle -->
<ProjectReference Include="src\windowsdesktop\src\bundle\**\*.wixproj" />
<ProjectReference Include="src\windowsdesktop\tests\**\*.Tests.csproj" />

<!-- Microsoft.Windows.Compatibility nuget meta package -->
Expand Down
83 changes: 81 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,8 +1,51 @@
<Project>

<Import Project="Sdk.props" Sdk="Microsoft.DotNet.Arcade.Sdk" />

<PropertyGroup>
<!-- WiX v5 Configuration -->
<UseWix5>true</UseWix5>

<!-- WiX v5 PDB Type Fix -->
<WixToolsetCompilerPdbType>full</WixToolsetCompilerPdbType>
<WixToolsetLinkerPdbType>full</WixToolsetLinkerPdbType>

<!-- Force sequential builds to prevent file locking issues -->
<!-- Override MSBuild's default /m flag behavior -->
<BuildInParallel>false</BuildInParallel>
<MaxCpuCount>1</MaxCpuCount>

<!-- Additional sequential build enforcement -->
<MSBuildDisableNodeReuse>true</MSBuildDisableNodeReuse>
<UseSharedCompilation>false</UseSharedCompilation>

<!-- Ensure Wixpack generation is enabled for all build types -->
<WixCreateWixPackOutput Condition="'$(OutputType)' == 'Bundle'">true</WixCreateWixPackOutput>

<!-- Ensure Wixpack targets run in CI/PR builds and local builds -->
<RunWixpackTargets Condition="'$(TF_BUILD)' == 'true' OR '$(CI)' == 'true' OR '$(ContinuousIntegrationBuild)' == 'true'">true</RunWixpackTargets>
<RunWixpackTargets Condition="'$(RunWixpackTargets)' == ''">true</RunWixpackTargets>

<!-- Project-level parallelism controls -->
<BuildProjectReferences>true</BuildProjectReferences>
<BuildInParallel Condition="'$(BuildingInstallers)' == 'true'">false</BuildInParallel>
<MaxCpuCount Condition="'$(BuildingInstallers)' == 'true'">1</MaxCpuCount>
<MaxCpuCount Condition="'$(PlatformPackageType)' == 'RuntimePack'">1</MaxCpuCount>

<!-- CI build stability measures -->
<BuildInParallel Condition="'$(TF_BUILD)' == 'true' OR '$(CI)' == 'true'">false</BuildInParallel>
<MaxCpuCount Condition="'$(TF_BUILD)' == 'true' OR '$(CI)' == 'true'">1</MaxCpuCount>

<!-- WindowsDesktop uses transport packages with pre-compiled R2R assemblies -->
<!-- Local CrossGen2 compilation settings removed - rely on transport packages -->

<!-- Disable parallel builds entirely for RuntimePack to prevent all file conflicts -->
<ContinueOnError Condition="'$(PlatformPackageType)' == 'RuntimePack'">false</ContinueOnError>

<!-- Process timeout settings to prevent hanging builds -->
<MSBuildNodeAndChildProcessTimeout>600000</MSBuildNodeAndChildProcessTimeout>
<MSBuildProcessTimeout>600000</MSBuildProcessTimeout>
<TaskTimeout>600</TaskTimeout>

<!-- Packaging properties -->
<RepositoryUrl>https://github.com/dotnet/windowsdesktop</RepositoryUrl>
<PackageProjectUrl>https://dot.net</PackageProjectUrl>
Expand All @@ -15,12 +58,16 @@
<PackageThirdPartyNoticesFile>$(MSBuildThisFileDirectory)THIRD-PARTY-NOTICES.TXT</PackageThirdPartyNoticesFile>
<PackageReleaseNotes>https://go.microsoft.com/fwlink/?LinkID=799421</PackageReleaseNotes>



<!-- Set up handling of build warnings -->
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

<!-- Platform detection -->
<TargetArchitecture Condition="'$(TargetArchitecture)' == ''">x64</TargetArchitecture>
<!-- Map Platform property to TargetArchitecture, but skip AnyCPU which is not valid for WiX -->
<TargetArchitecture Condition="'$(TargetArchitecture)' == '' AND '$(Platform)' != '' AND '$(Platform)' != 'AnyCPU'">$(Platform)</TargetArchitecture>
<TargetArchitecture Condition="'$(TargetArchitecture)' == ''">x64</TargetArchitecture>

<!-- Only upgrade NuGetAudit warnings to errors for official builds. -->
<WarningsNotAsErrors Condition="'$(OfficialBuild)' != 'true'">$(WarningsNotAsErrors);NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors>
Expand All @@ -29,4 +76,36 @@
<PortableBuild Condition="'$(PortableBuild)' != 'false'">true</PortableBuild>
</PropertyGroup>

<PropertyGroup>
<OfficialBaseURL>https://builds.dotnet.microsoft.com/dotnet/</OfficialBaseURL>
<!-- Allow overriding the public base URL for Unified Build scenarios to pull assets from a local build. -->
<PublicBaseURL Condition="'$(PublicBaseURL)' == ''">https://ci.dot.net/public/</PublicBaseURL>
<InternalBaseURL>https://ci.dot.net/internal/</InternalBaseURL>
<!-- Allow overriding where installers are pulled in from previously completed jobs in Unified Build scenarios. -->
<AddVersionToCrossArchitectureInstallerBasePath Condition="'$(CrossArchitectureInstallerBasePath)' != ''">true</AddVersionToCrossArchitectureInstallerBasePath>
<CrossArchitectureInstallerBasePath Condition="'$(CrossArchitectureInstallerBasePath)' == ''">$(ArtifactsShippingPackagesDir)</CrossArchitectureInstallerBasePath>
</PropertyGroup>

<!-- Try various places to find the runtime. It's either released (use official version),
public but un-released (use dotnetbuilds/public), or internal and unreleased (use dotnetbuilds/internal) -->
<ItemGroup Condition="'$(DotNetBuild)' != 'true'">
<RemoteAssetBaseURL Include="$(OfficialBaseURL)" />
<RemoteAssetBaseURL Include="$(PublicBaseURL)" />
<!-- Include the token here as we'll generate the URLs to download based on this item group. -->
<RemoteAssetBaseURL Include="$(InternalBaseURL)"
Condition=" '$(DotnetRuntimeSourceFeedKey)' != '' ">
<token>$(DotnetRuntimeSourceFeedKey)</token>
</RemoteAssetBaseURL>
</ItemGroup>

<!--
Only try downloading from the "public" base URL when doing a vertical build.
In a vertical build, the public URL will be overwritten to point to local build artifacts.
-->
<ItemGroup Condition="'$(DotNetBuild)' == 'true'">
<!-- MSBuild removes the '//' slashes when passing PublicBaseURL from the outer to the inner build. -->
<RemoteAssetBaseURL Condition="$(PublicBaseURL.StartsWith('file:')) and '$(OS)' != 'Windows_NT'" Include="$([System.Text.RegularExpressions.Regex]::Replace('$(PublicBaseURL)', '%28file:\/{1,}%29%28.+%29', 'file:///%242'))" />
<RemoteAssetBaseURL Condition="!$(PublicBaseURL.StartsWith('file:')) or '$(OS)' == 'Windows_NT'" Include="$(PublicBaseURL)" />
</ItemGroup>

</Project>
9 changes: 9 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@
<!-- WPF dependencies-->
<PackageVersion Include="Microsoft.DotNet.Wpf.GitHub" Version="$(MicrosoftDotNetWpfGitHubVersion)" />
<PackageVersion Include="Microsoft.Internal.Runtime.WindowsDesktop.Transport" Version="$(MicrosoftInternalRuntimeWindowsDesktopTransportVersion)" />

<!-- WiX dependencies -->
<PackageVersion Include="Microsoft.Wix" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Bal.wixext" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Dependency.wixext" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Heat" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.UI.wixext" Version="$(MicrosoftWixToolsetSdkVersion)" />
<PackageVersion Include="Microsoft.WixToolset.Util.wixext" Version="$(MicrosoftWixToolsetSdkVersion)" />

</ItemGroup>

</Project>
61 changes: 61 additions & 0 deletions WindowsDesktop.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "eng", "eng", "{7525B257-249C-EE79-B10A-65D0BC27ABA9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "common", "common", "{C3C130B5-2C3F-D4B2-E3F3-EC385075C7AB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools", "eng\common\internal\Tools.csproj", "{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Windows.Compatibility", "Microsoft.Windows.Compatibility", "{292A50E1-7820-1638-6BA6-14FBE6B99F15}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "runtime.native.System.IO.Ports", "src\Microsoft.Windows.Compatibility\package\runtime.native.System.IO.Ports.csproj", "{E47F785E-FA7A-58A1-D296-8C8F02432E6F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Compatibility", "src\Microsoft.Windows.Compatibility\src\Microsoft.Windows.Compatibility.csproj", "{B4E26156-D23F-346E-920D-DB46A8C16C8E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windowsdesktop", "windowsdesktop", "{B1DEBE5E-C067-B350-5F22-0DD39AD9FFE8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.WindowsDesktop.App.Tests", "src\windowsdesktop\tests\Microsoft.WindowsDesktop.App.Tests.csproj", "{DDF86961-3AF2-FBA0-E08B-F367E1ABC517}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5}.Release|Any CPU.Build.0 = Release|Any CPU
{E47F785E-FA7A-58A1-D296-8C8F02432E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E47F785E-FA7A-58A1-D296-8C8F02432E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E47F785E-FA7A-58A1-D296-8C8F02432E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E47F785E-FA7A-58A1-D296-8C8F02432E6F}.Release|Any CPU.Build.0 = Release|Any CPU
{B4E26156-D23F-346E-920D-DB46A8C16C8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B4E26156-D23F-346E-920D-DB46A8C16C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B4E26156-D23F-346E-920D-DB46A8C16C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B4E26156-D23F-346E-920D-DB46A8C16C8E}.Release|Any CPU.Build.0 = Release|Any CPU
{DDF86961-3AF2-FBA0-E08B-F367E1ABC517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DDF86961-3AF2-FBA0-E08B-F367E1ABC517}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDF86961-3AF2-FBA0-E08B-F367E1ABC517}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDF86961-3AF2-FBA0-E08B-F367E1ABC517}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C3C130B5-2C3F-D4B2-E3F3-EC385075C7AB} = {7525B257-249C-EE79-B10A-65D0BC27ABA9}
{4F21FD48-C11F-D5EF-ADE2-1691A92E45C5} = {C3C130B5-2C3F-D4B2-E3F3-EC385075C7AB}
{292A50E1-7820-1638-6BA6-14FBE6B99F15} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{E47F785E-FA7A-58A1-D296-8C8F02432E6F} = {292A50E1-7820-1638-6BA6-14FBE6B99F15}
{B4E26156-D23F-346E-920D-DB46A8C16C8E} = {292A50E1-7820-1638-6BA6-14FBE6B99F15}
{B1DEBE5E-C067-B350-5F22-0DD39AD9FFE8} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{DDF86961-3AF2-FBA0-E08B-F367E1ABC517} = {B1DEBE5E-C067-B350-5F22-0DD39AD9FFE8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B96CF507-B5D5-4809-9C1C-7948C55C80FB}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion azure-pipelines-PR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ variables:
value: .NETCoreValidation

# Produce test-signed build for PR and Public builds
- name: SignType
- name: _SignType
value: test

stages:
Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ variables:
value: .NETCoreValidation

# Produce test-signed build for PR and Public builds
- name: SignType
- name: _SignType
value: $[ coalesce(variables.OfficialSignType, 'real') ]

resources:
Expand Down
45 changes: 45 additions & 0 deletions build-all-architectures.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env pwsh

param(
[string]$target = "Build",
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$args
)

Write-Host "Building Windows Desktop Runtime for all architectures..."

$architectures = @("x86", "x64", "arm64")
$failed = @()

if ($target -eq "pack") {
$target = "Build" # The 'Pack' target is part of the 'Build' target in Build.proj
}

$extraArgs = $args -join " "

foreach ($arch in $architectures) {
Write-Host "Building for architecture: $arch" -ForegroundColor Green

# Build the main projects with specific architecture
$command = "dotnet build Build.proj -t:$target -c Release -p:Platform=$arch -p:TargetArchitecture=$arch $extraArgs"
Write-Host "Executing: $command"
Invoke-Expression -Command $command

if ($LASTEXITCODE -ne 0) {
$failed += $arch
Write-Host "Failed to build $arch architecture" -ForegroundColor Red
} else {
Write-Host "Successfully built $arch architecture" -ForegroundColor Green
}
}

if ($failed.Count -gt 0) {
Write-Host "Failed architectures: $($failed -join ', ')" -ForegroundColor Red
exit 1
} else {
Write-Host "All architectures built successfully!" -ForegroundColor Green

# Show the results
Write-Host "`nGenerated installers:" -ForegroundColor Yellow
Get-ChildItem -Path artifacts -Recurse -Filter "windowsdesktop-runtime-*-win-*.exe" -ErrorAction SilentlyContinue | Select-Object Name, FullName
}
17 changes: 17 additions & 0 deletions build-sequential.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@echo off
setlocal

echo Cleaning up any existing build processes...
for /f "tokens=2" %%i in ('tasklist /fi "imagename eq dotnet.exe" /fo table /nh 2^>nul ^| findstr /i "WindowsDesktop"') do (
echo Killing process %%i
taskkill /f /pid %%i >nul 2>&1
)

echo Starting sequential build...
powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0eng\common\Build.ps1""" -nodeReuse:$false -maxCpuCount:1 -restore -build %*"

echo Build completed. Cleaning up any remaining processes...
for /f "tokens=2" %%i in ('tasklist /fi "imagename eq dotnet.exe" /fo table /nh 2^>nul ^| findstr /i "WindowsDesktop"') do (
echo Killing remaining process %%i
taskkill /f /pid %%i >nul 2>&1
)
72 changes: 72 additions & 0 deletions build-sequential.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[CmdletBinding()]
param(
[switch]$restore,
[switch]$build,
[switch]$clean,
[string]$configuration = "Debug",
[Parameter(ValueFromRemainingArguments=$true)]
[string[]]$RemainingArgs = @()
)

function Stop-WindowsDesktopProcesses {
Write-Host "Cleaning up WindowsDesktop build processes..." -ForegroundColor Yellow

$processes = Get-Process | Where-Object {
$_.ProcessName -eq "dotnet" -and
$_.Path -like "*WindowsDesktop*"
}

if ($processes) {
$processes | ForEach-Object {
Write-Host " Stopping process $($_.Id) ($($_.ProcessName))" -ForegroundColor Gray
try {
Stop-Process -Id $_.Id -Force -ErrorAction SilentlyContinue
} catch {
Write-Warning "Failed to stop process $($_.Id): $_"
}
}
Start-Sleep -Seconds 2
} else {
Write-Host " No WindowsDesktop processes found." -ForegroundColor Gray
}
}



# Main execution
try {
# Clean up any existing processes
Stop-WindowsDesktopProcesses

# Prepare arguments for Build.ps1
$buildArguments = @()
if ($restore) { $buildArguments += '-restore' }
if ($build) { $buildArguments += '-build' }
if ($clean) { $buildArguments += '-clean' }
if ($configuration) {
$buildArguments += '-configuration'
$buildArguments += $configuration
}
$buildArguments += $RemainingArgs

Write-Host "Starting sequential build with single CPU..." -ForegroundColor Green
Write-Host "Arguments: $($buildArguments -join ' ')" -ForegroundColor Gray

# Run the build with sequential settings
try {
& "$PSScriptRoot\eng\common\Build.ps1" -nodeReuse $false @buildArguments "/maxcpucount:1"
$exitCode = $LASTEXITCODE
} catch {
Write-Error "Build failed: $_"
$exitCode = 1
}

Write-Host "`nBuild completed with exit code: $exitCode" -ForegroundColor $(if ($exitCode -eq 0) { 'Green' } else { 'Red' })

} finally {
# Always clean up processes after build
Write-Host "`nCleaning up processes after build..." -ForegroundColor Yellow
Stop-WindowsDesktopProcesses
}

exit $exitCode
7 changes: 7 additions & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,12 @@
<SystemSecurityPrincipalWindowsVersion>5.0.0</SystemSecurityPrincipalWindowsVersion>
<!-- wcf -->
<SystemServiceModelVersion>8.1.2</SystemServiceModelVersion>
<!-- WiX -->
<MicrosoftWixToolsetSdkVersion Condition="'$(MicrosoftWixToolsetSdkVersion)' == '' and '$(DefaultWixSdkVersion)' != ''">$(DefaultWixSdkVersion)</MicrosoftWixToolsetSdkVersion>

<!-- Runtime version variables for CI builds (missing variables causing CI issues) -->
<DotNetRuntimeVersion>$(MicrosoftNETCoreAppRefVersion)</DotNetRuntimeVersion>
<AspNetCoreVersion>$(MicrosoftNETCoreAppRefVersion)</AspNetCoreVersion>
<!-- Transport package version for VS insertion packages is defined in Version.Details.props -->
</PropertyGroup>
</Project>
28 changes: 28 additions & 0 deletions eng/pipelines/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Pipeline Notes

This directory contains templates that compose the main Azure DevOps pipeline for WindowsDesktop.

## Runtime MSI Acquisition

The WiX bundle build depends on three runtime prerequisite MSIs being present under `artifacts/prereqs/<arch>`. Historically these were staged manually, but the CI pipeline now prepares them automatically before MSBuild executes.

Each architecture job defined in `jobs/windows-build.yml` performs the following steps prior to invoking `eng/common/cibuild.cmd`:

1. Import the internal runtime feed credentials via the `enable-internal-runtimes.yml` template, which retrieves the `dotnetbuilds-internal-container-read-token` SAS secret.
2. Pass the runtime source feed and token to Arcade (`-RuntimeSourceFeed` / `-RuntimeSourceFeedKey` and their MSBuild equivalents) so that `eng/common/build.ps1` downloads the required runtime packs on-demand.
3. Allow the bundle build to normalize the host/hostfxr/runtime MSIs into `artifacts/prereqs/<arch>` as part of the existing `StagePrereqRuntimeMsis` target execution.

During the WiX build, the `StagePrereqRuntimeMsis` target (in `src/windowsdesktop/src/bundle/Wix.targets`) detects these staged files and sets `IncludeRuntimeMSIs=true`, ensuring the bundle carries the latest runtime from Maestro.

### Local Repro

To emulate the CI behavior locally:

```powershell
$token = '<base64-encoded SAS token>'
pwsh eng/common/build.ps1 -restore -build -pack -runtimeSourceFeed "https://ci.dot.net/internal" -runtimeSourceFeedKey $token
```

The command above mirrors the CI configuration by pointing Arcade at the internal runtime feed. Provide a base64-encoded SAS token with read permissions (matching the `dotnetbuilds-internal` secret) and repeat per architecture if needed using `/p:TargetArchitecture=<arch>`.

Maintain this document if additional preparatory stages are introduced so build orchestration remains discoverable.
Loading