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

Finished MultiTarget support for solution generation #200

Merged
merged 8 commits into from
Aug 1, 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
11 changes: 8 additions & 3 deletions Build-Toolkit-Components.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@
#>
Param (
[ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$MultiTargets = @('all'),
[Alias("mt")]
[string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings

[ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$ExcludeMultiTargets = @('wpf', 'linuxgtk', 'macos', 'ios', 'android'),
[string[]]$ExcludeMultiTargets = @(), # default settings

[Alias("c")]
[string[]]$Components = @("all"),

[string[]]$ExcludeComponents,
Expand All @@ -76,10 +78,13 @@ Param (
[Alias("bl")]
[switch]$EnableBinLogs,

[Alias("blo")]
[string]$BinlogOutput,


[Alias("p")]
[hashtable]$AdditionalProperties,

[Alias("winui")]
[int]$WinUIMajorVersion = 2,

[string]$ComponentDir = "src",
Expand Down
19 changes: 12 additions & 7 deletions Build-Toolkit-Gallery.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build: 'wpf', 'linuxgtk', 'macos', 'ios', and 'android'. Run uno-check to install the required workloads.

.PARAMETER Heads
The heads to include in the build. Default is 'Uwp', 'WinAppSdk', 'Wasm'.
The heads to include in the build. Default is 'Uwp', 'Wasdk', 'Wasm'.

.PARAMETER ExcludeHeads
The heads to exclude from the build. Default is none.
Expand Down Expand Up @@ -47,26 +47,31 @@
#>
Param (
[ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$MultiTargets = @('all'),
[Alias("mt")]
[string[]]$MultiTargets = @('uwp', 'wasdk', 'wasm'), # default settings

[ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$ExcludeMultiTargets = @('wpf', 'linuxgtk', 'macos', 'ios', 'android'),
[string[]]$ExcludeMultiTargets = @() # default settings

[ValidateSet('all', 'Uwp', 'WinAppSdk', 'Wasm', 'Tests.Uwp', 'Tests.WinAppSdk')]
[string[]]$Heads = @('Uwp', 'WinAppSdk', 'Wasm'),
[ValidateSet('all', 'Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')]
[string[]]$Heads = @('Uwp', 'Wasdk', 'Wasm'),

[ValidateSet('Uwp', 'WinAppSdk', 'Wasm', 'Tests.Uwp', 'Tests.WinAppSdk')]
[ValidateSet('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')]
[string[]]$ExcludeHeads,

[Alias("bl")]
[switch]$EnableBinLogs,

[Alias("blo")]
[string]$BinlogOutput,

[Alias("p")]
[hashtable]$AdditionalProperties,

[Alias("winui")]
[int]$WinUIMajorVersion = 2,

[Alias("c")]
[string[]]$Components = @("all"),

[string[]]$ExcludeComponents,
Expand Down Expand Up @@ -113,7 +118,7 @@ if ($Components -notcontains 'Converters') {
& $PSScriptRoot\MultiTarget\GenerateAllProjectReferences.ps1 -MultiTarget $MultiTargets -Components $Components

if ($Heads -eq 'all') {
$Heads = @('Uwp', 'WinAppSdk', 'Wasm', 'Tests.Uwp', 'Tests.WinAppSdk')
$Heads = @('Uwp', 'Wasdk', 'Wasm', 'Tests.Uwp', 'Tests.Wasdk')
}

function Invoke-MSBuildWithBinlog {
Expand Down
108 changes: 86 additions & 22 deletions GenerateAllSolution.ps1
Original file line number Diff line number Diff line change
@@ -1,35 +1,73 @@
<#
.SYNOPSIS
Generates the solution file comprising of platform heads for samples, individual component projects, and tests.

.DESCRIPTION
Used mostly for CI building of everything and testing end-to-end scenarios involving the full
sample app experience.

Otherwise it is recommended to focus on an individual component's solution instead.
.PARAMETER IncludeHeads
List of TFM based projects to include. This can be 'all', 'uwp', or 'winappsdk'.

Defaults to 'all' for local-use.
.PARAMETER MultiTargets
Specifies the MultiTarget TFM(s) to include for building the components. The default value is 'all'.

.PARAMETER ExcludeMultiTargets
Specifies the MultiTarget TFM(s) to exclude for building the components. The default value excludes targets that require additional tooling or workloads to build. Run uno-check to install the required workloads.

.PARAMETER Components
The names of the components to generate project and solution references for. Defaults to all components.

.PARAMETER ExcludeComponents
The names of the components to exclude when generating solution and project references. Defaults to none.

.PARAMETER WinUIMajorVersion
Specifies the WinUI major version to use when building an Uno head. Also decides the package id and dependency variant. The default value is '2'.

.PARAMETER UseDiagnostics
Add extra diagnostic output to running slngen, such as a binlog, etc...

.EXAMPLE
C:\PS> .\GenerateAllSolution -IncludeHeads winappsdk
C:\PS> .\GenerateAllSolution -MultiTargets wasdk
Build a solution that doesn't contain UWP projects.

.NOTES
Author: Windows Community Toolkit Labs Team
Date: April 27, 2022
#>
Param (
[Parameter(HelpMessage = "The heads to include for building platform samples and tests.", ParameterSetName = "IncludeHeads")]
[ValidateSet('all', 'uwp', 'winappsdk')]
[string]$IncludeHeads = 'all',
[ValidateSet('all', 'wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')]
[Alias("mt")]
[string[]]$MultiTargets = @('uwp', 'wasm', 'wasdk'),

[ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$ExcludeMultiTargets = @(), # default settings

[Alias("c")]
[string[]]$Components = @('all'),

[Alias("winui")]
[int]$WinUIMajorVersion = 2,

[string[]]$ExcludeComponents,

[Parameter(HelpMessage = "Add extra diagnostic output to slngen generator.")]
[switch]$UseDiagnostics = $false
)

if ($MultiTargets.Contains('all')) {
$MultiTargets = @('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android')
}

if ($null -eq $ExcludeMultiTargets)
{
$ExcludeMultiTargets = @()
}

$MultiTargets = $MultiTargets | Where-Object { $_ -notin $ExcludeMultiTargets }

# Generate required props for "All" solution.
& ./tooling/MultiTarget/GenerateAllProjectReferences.ps1
& ./tooling/MultiTarget/GenerateAllProjectReferences.ps1 -MultiTargets $MultiTargets -Components $Components -ExcludeComponents $ExcludeComponents
& ./tooling/MultiTarget/UseTargetFrameworks.ps1 -MultiTargets $MultiTargets
& ./tooling/MultiTarget/UseUnoWinUI.ps1 $WinUIMajorVersion

# Set up constant values
$generatedSolutionFilePath = 'CommunityToolkit.AllComponents.sln'
Expand All @@ -55,23 +93,49 @@ $projects = [System.Collections.ArrayList]::new()
# Common/Dependencies for shared infrastructure
[void]$projects.Add(".\tooling\CommunityToolkit*\*.*proj")

# App Head and Test Head
if ($IncludeHeads -ne 'winappsdk')
{
[void]$projects.Add(".\tooling\ProjectHeads\AllComponents\**\*.Uwp.csproj")
# Deployable sample gallery heads
# TODO: this handles separate project heads, but won't directly handle the unified Skia head from Uno.
# Once we have that, just do a transform on the csproj filename inside this loop to decide the same csproj for those separate MultiTargets.
foreach ($multitarget in $MultiTargets) {
# capitalize first letter, avoid case sensitivity issues on linux
$csprojFileNamePartForMultiTarget = $multitarget.substring(0,1).ToUpper() + $multitarget.Substring(1).ToLower()

$path = ".\tooling\ProjectHeads\AllComponents\**\*.$csprojFileNamePartForMultiTarget.csproj";

if (Test-Path $path) {
[void]$projects.Add($path)
}
else {
Write-Warning "No project head could be found at $path for MultiTarget $multitarget. Skipping."
}
}

if ($IncludeHeads -ne 'uwp')
{
[void]$projects.Add(".\tooling\ProjectHeads\AllComponents\**\*.WinAppSdk.csproj")
# Individual projects
if ($Components -eq @('all')) {
$Components = @('**')
}

[void]$projects.Add(".\tooling\ProjectHeads\AllComponents\**\*.Wasm.csproj")

# Individual projects
[void]$projects.Add(".\components\**\src\*.csproj")
[void]$projects.Add(".\components\**\samples\*.Samples.csproj")
[void]$projects.Add(".\components\**\tests\*.Tests\*.shproj")
foreach ($componentName in $Components) {
if ($ExcludeComponents -contains $componentName) {
continue;
}

foreach ($componentPath in Get-Item "$PSScriptRoot/../components/$componentName/") {
$multiTargetPrefs = & $PSScriptRoot\MultiTarget\Get-MultiTargets.ps1 -component $($componentPath.BaseName)

$shouldReferenceInSolution = $multiTargetPrefs.Where({ $MultiTargets.Contains($_) }).Count -gt 0

if ($shouldReferenceInSolution) {
Write-Output "Add component $componentPath to solution";

[void]$projects.Add(".\components\$($componentPath.BaseName)\src\*.csproj")
[void]$projects.Add(".\components\$($componentPath.BaseName)\samples\*.Samples.csproj")
[void]$projects.Add(".\components\$($componentPath.BaseName)\tests\*.Tests\*.shproj")
} else {
Write-Warning "Component $($componentPath.BaseName) doesn't MultiTarget any of $MultiTargets and won't be added to the solution.";
}
}
}

if ($UseDiagnostics.IsPresent)
{
Expand Down
10 changes: 5 additions & 5 deletions MultiTarget/GenerateAllProjectReferences.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Param (
[string]$projectPropsOutputDir = "$PSScriptRoot/Generated",

[Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")]
[string[]]$MultiTarget = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard"),
[Alias("mt")]
[ValidateSet('wasm', 'uwp', 'wasdk', 'wpf', 'linuxgtk', 'macos', 'ios', 'android', 'netstandard')]
[string[]]$MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard"),

[Parameter(HelpMessage = "The names of the components to generate references for. Defaults to all components.")]
[string[]]$Components = @("all"),
Expand All @@ -30,20 +32,18 @@ foreach ($componentName in $Components) {

# Find all components source csproj (when wildcard), or find specific component csproj by name.
foreach ($componentPath in Get-Item "$PSScriptRoot/../../components/$componentName/") {
Write-Output "Generating project references for component $componentName at $componentPath";

# Find source and sample csproj files
$componentSourceCsproj = Get-ChildItem $componentPath/src/*.csproj -ErrorAction SilentlyContinue;
$componentSampleCsproj = Get-ChildItem $componentPath/samples/*.csproj -ErrorAction SilentlyContinue;

# Generate <ProjectReference>s for sample project
# Use source project MultiTarget as first fallback.
if ($null -ne $componentSampleCsproj -and (Test-Path $componentSampleCsproj)) {
& $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $componentSampleCsproj -outputPath "$projectPropsOutputDir/$($componentSampleCsproj.BaseName).props" -MultiTarget $MultiTarget
& $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $componentSampleCsproj -outputPath "$projectPropsOutputDir/$($componentSampleCsproj.BaseName).props" -MultiTargets $MultiTargets
}

# Generate <ProjectReference>s for src project
& $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $componentSourceCsproj -outputPath "$projectPropsOutputDir/$($componentSourceCsproj.BaseName).props" -MultiTarget $MultiTarget
& $PSScriptRoot\GenerateMultiTargetAwareProjectReferenceProps.ps1 -projectPath $componentSourceCsproj -outputPath "$projectPropsOutputDir/$($componentSourceCsproj.BaseName).props" -MultiTargets $MultiTargets
}
}

Expand Down
44 changes: 27 additions & 17 deletions MultiTarget/GenerateMultiTargetAwareProjectReferenceProps.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Param (

[Parameter(HelpMessage = "Only projects that support these targets will have references generated for use by deployable heads.")]
[ValidateSet("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard")]
[string[]] $MultiTarget = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard")
[Alias("mt")]
[string[]] $MultiTargets = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard")
)

$templateContents = Get-Content -Path $templatePath;
Expand All @@ -40,35 +41,44 @@ $templateContents = $templateContents -replace [regex]::escape($projectRootPlace
$componentPath = Get-Item "$projectPath/../../"

# Load multitarget preferences for component
$multiTargets = & $PSScriptRoot\Get-MultiTargets.ps1 -component $($componentPath.BaseName)
$multiTargetPrefs = & $PSScriptRoot\Get-MultiTargets.ps1 -component $($componentPath.BaseName)

if ($null -eq $multiTargets) {
if ($null -eq $multiTargetPrefs) {
Write-Error "Couldn't get MultiTarget property for $componentPath";
exit(-1);
}

# Ensure multiTargets is not empty
if ($multiTargets.Length -eq 0) {
# Ensure multiTargetPrefs is not empty
if ($multiTargetPrefs.Length -eq 0) {
Write-Error "MultiTarget property is empty for $projectPath";
exit(-1);
}

$templateContents = $templateContents -replace [regex]::escape("[IntendedTargets]"), $multiTargets;
$templateContents = $templateContents -replace [regex]::escape("[IntendedTargets]"), $multiTargetPrefs;

function ShouldMultiTarget([string] $target) {
return ($multiTargets.Contains($target) -and $MultiTarget.Contains($target)).ToString().ToLower()
return ($multiTargetPrefs.Contains($target) -and $MultiTargets.Contains($target))
}

Write-Host "Generating project references for $([System.IO.Path]::GetFileNameWithoutExtension($csprojFileName)): $($multiTargets -Join ', ')"
$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasm]"), "'$(ShouldMultiTarget "wasm")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetUwp]"), "'$(ShouldMultiTarget "uwp")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasdk]"), "'$(ShouldMultiTarget "wasdk")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetWpf]"), "'$(ShouldMultiTarget "wpf")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinuxGtk]"), "'$(ShouldMultiTarget "linuxgtk")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetMacOS]"), "'$(ShouldMultiTarget "macos")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetiOS]"), "'$(ShouldMultiTarget "ios")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetDroid]"), "'$(ShouldMultiTarget "droid")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetNetstandard]"), "'$(ShouldMultiTarget "netstandard")'";
function ShouldMultiTargetMsBuildValue([string] $target) {
return $(ShouldMultiTarget $target).ToString().ToLower()
}

$targeted = @("uwp", "wasdk", "wpf", "wasm", "linuxgtk", "macos", "ios", "android", "netstandard").Where({ ShouldMultiTarget $_ })

if ($targeted.Count -gt 0) {
Write-Host "Generating project references for $([System.IO.Path]::GetFileNameWithoutExtension($csprojFileName)): $($targeted -Join ', ')"
}

$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasm]"), "'$(ShouldMultiTargetMsBuildValue "wasm")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetUwp]"), "'$(ShouldMultiTargetMsBuildValue "uwp")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetWasdk]"), "'$(ShouldMultiTargetMsBuildValue "wasdk")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetWpf]"), "'$(ShouldMultiTargetMsBuildValue "wpf")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetLinuxGtk]"), "'$(ShouldMultiTargetMsBuildValue "linuxgtk")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetMacOS]"), "'$(ShouldMultiTargetMsBuildValue "macos")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetiOS]"), "'$(ShouldMultiTargetMsBuildValue "ios")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetDroid]"), "'$(ShouldMultiTargetMsBuildValue "android")'";
$templateContents = $templateContents -replace [regex]::escape("[CanTargetNetstandard]"), "'$(ShouldMultiTargetMsBuildValue "netstandard")'";

# Save to disk
Set-Content -Path $outputPath -Value $templateContents;
Loading
Loading