[CmdletBinding()] param( [string[]]$Presets = @("android-arm64", "android-x64", "android-quest-arm64", "android-focus-arm64"), [string[]]$Targets = @( "pp_foundation", "pp_assets", "pp_paint", "pp_document", "pp_renderer_api", "pp_renderer_gl", "pp_paint_renderer", "pp_ui_core", "pp_platform_api", "pp_app_core", "pano_cli", "pp_foundation_binary_stream_tests", "pp_foundation_event_tests", "pp_foundation_log_tests", "pp_foundation_parse_tests", "pp_foundation_task_queue_tests", "pp_foundation_trace_tests", "pp_foundation_task_queue_stress_tests", "pp_assets_brush_package_tests", "pp_assets_image_format_tests", "pp_assets_image_metadata_tests", "pp_assets_image_pixels_tests", "pp_assets_ppi_header_tests", "pp_assets_settings_document_tests", "pp_paint_brush_tests", "pp_paint_blend_tests", "pp_paint_stroke_tests", "pp_paint_stroke_script_tests", "pp_document_tests", "pp_document_ppi_import_tests", "pp_document_ppi_export_tests", "pp_renderer_api_tests", "pp_renderer_gl_capabilities_tests", "pp_renderer_gl_command_plan_tests", "pp_paint_renderer_compositor_tests", "pp_paint_renderer_stroke_execution_tests", "pp_renderer_gl_gpu_readback_tests", "pp_platform_api_tests", "pp_ui_core_color_tests", "pp_ui_core_layout_value_tests", "pp_ui_core_layout_xml_tests", "pp_ui_core_node_lifetime_tests", "pp_ui_core_overlay_lifetime_tests", "pp_app_core_about_menu_tests", "pp_app_core_app_dialog_tests", "pp_app_core_app_preferences_tests", "pp_app_core_app_frame_tests", "pp_app_core_app_thread_tests", "pp_app_core_app_input_tests", "pp_app_core_app_shutdown_tests", "pp_app_core_app_startup_tests", "pp_app_core_app_status_tests", "pp_app_core_app_thread_stress_tests", "pp_app_core_command_convert_tests", "pp_app_core_brush_package_export_tests", "pp_app_core_brush_package_import_tests", "pp_app_core_brush_ui_tests", "pp_app_core_canvas_hotkey_tests", "pp_app_core_canvas_tool_ui_tests", "pp_app_core_canvas_view_tests", "pp_app_core_document_animation_tests", "pp_app_core_document_canvas_tests", "pp_app_core_document_cloud_tests", "pp_app_core_document_export_tests", "pp_app_core_document_import_tests", "pp_app_core_document_layer_tests", "pp_app_core_document_platform_io_tests", "pp_app_core_document_recording_tests", "pp_app_core_document_resize_tests", "pp_app_core_document_route_tests", "pp_app_core_document_sharing_tests", "pp_app_core_document_session_tests", "pp_app_core_file_menu_tests", "pp_app_core_grid_ui_tests", "pp_app_core_history_ui_tests", "pp_app_core_main_toolbar_tests", "pp_app_core_quick_ui_tests", "pp_app_core_tools_menu_tests" ), [switch]$Quiet, [string]$LogDir = "out/logs/platform-build", [int]$FailureTailLines = 0 ) $ErrorActionPreference = "Stop" function Expand-ArgumentList { param([string[]]$Values) $expanded = @() foreach ($value in $Values) { foreach ($part in ($value -split ",")) { $trimmed = $part.Trim() if ($trimmed.Length -gt 0) { $expanded += $trimmed } } } return $expanded } function Limit-LogSlug { param( [string]$Value, [int]$MaxLength = 96 ) if ($Value.Length -le $MaxLength) { return $Value } return $Value.Substring(0, $MaxLength) } function Invoke-LoggedCommand { param( [string]$Command, [string[]]$Arguments, [string]$LogPath, [int]$FailureTailLines ) $started = Get-Date $exitCode = 0 $restoreNativeCommandPreference = $false if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) { $previousNativeCommandPreference = $PSNativeCommandUseErrorActionPreference $PSNativeCommandUseErrorActionPreference = $false $restoreNativeCommandPreference = $true } try { & $Command @Arguments *> $LogPath $exitCode = $LASTEXITCODE if ($null -eq $exitCode) { $exitCode = 0 } } catch { $_ | Out-File -LiteralPath $LogPath -Append -Encoding utf8 $exitCode = 1 } finally { if ($restoreNativeCommandPreference) { $PSNativeCommandUseErrorActionPreference = $previousNativeCommandPreference } } $result = [ordered]@{ exitCode = $exitCode elapsedMs = [int]((Get-Date) - $started).TotalMilliseconds log = $LogPath } if ($exitCode -ne 0 -and $FailureTailLines -gt 0 -and (Test-Path -LiteralPath $LogPath)) { $result.failureTail = @(Get-Content -LiteralPath $LogPath -Tail $FailureTailLines | ForEach-Object { [string]$_ }) } return $result } function Get-VcpkgRoot { $candidates = @() if ($env:VCPKG_ROOT) { $candidates += $env:VCPKG_ROOT } $programFiles = @($env:ProgramFiles, ${env:ProgramFiles(x86)}) | Where-Object { $_ } $vsYears = @("2026", "2022") $vsEditions = @("Community", "Professional", "Enterprise", "BuildTools", "Preview") foreach ($root in $programFiles) { foreach ($year in $vsYears) { foreach ($edition in $vsEditions) { $candidates += (Join-Path $root "Microsoft Visual Studio\$year\$edition\VC\vcpkg") } } } foreach ($candidate in $candidates) { if ($candidate -and (Test-Path -LiteralPath (Join-Path $candidate "vcpkg.exe") -PathType Leaf)) { return (Resolve-Path -LiteralPath $candidate).Path } } throw "VCPKG_ROOT was not set and no Visual Studio bundled vcpkg root was found." } function Set-VcpkgRootEnvironment { $vcpkgRoot = Get-VcpkgRoot $env:VCPKG_ROOT = $vcpkgRoot return [ordered]@{ vcpkgRoot = $vcpkgRoot vcpkgCommand = Join-Path $vcpkgRoot "vcpkg.exe" } } $Presets = @(Expand-ArgumentList -Values $Presets) $Targets = @(Expand-ArgumentList -Values $Targets) $cmakeCommand = "cmake" $androidToolchain = $null $vcpkgToolchain = $null if ($Presets | Where-Object { $_ -like "*vcpkg*" }) { $vcpkgToolchain = Set-VcpkgRootEnvironment } if ($Presets | Where-Object { $_ -like "android-*" }) { . "$PSScriptRoot\android-sdk-env.ps1" $androidToolchain = Set-AndroidSdkToolchainEnvironment $cmakeCommand = $androidToolchain.cmakeCommand } $started = Get-Date $results = @() $overallExitCode = 0 $runId = Get-Date -Format "yyyyMMdd-HHmmss" if ($Quiet) { New-Item -ItemType Directory -Force -Path $LogDir | Out-Null } foreach ($preset in $Presets) { $presetCmakeCommand = $cmakeCommand if ($androidToolchain -and $preset -notlike "android-*") { $presetCmakeCommand = "cmake" } $configureExitCode = 0 $configureLog = $null if ($Quiet) { $configureLog = Join-Path -Path $LogDir -ChildPath ("{0}-configure-{1}.log" -f $runId, (Limit-LogSlug (($preset -replace "[^A-Za-z0-9_.-]", "_")))) $configureResult = Invoke-LoggedCommand ` -Command $presetCmakeCommand ` -Arguments @("--preset", $preset) ` -LogPath $configureLog ` -FailureTailLines $FailureTailLines $configureExitCode = $configureResult.exitCode } else { & $presetCmakeCommand --preset $preset $configureExitCode = $LASTEXITCODE } if ($configureExitCode -ne 0) { $overallExitCode = $configureExitCode $result = [ordered]@{ preset = $preset stage = "configure" exitCode = $configureExitCode } if ($Quiet) { $result.log = $configureLog if ($configureResult.Contains("failureTail")) { $result.failureTail = $configureResult.failureTail } } $results += $result continue } $buildArgs = @("--build", "--preset", $preset) foreach ($target in $Targets) { $buildArgs += @("--target", $target) } $buildExitCode = 0 $buildLog = $null if ($Quiet) { $safeTargets = Limit-LogSlug (($Targets -join "_") -replace "[^A-Za-z0-9_.-]", "_") $buildLog = Join-Path -Path $LogDir -ChildPath ("{0}-build-{1}-{2}.log" -f $runId, ($preset -replace "[^A-Za-z0-9_.-]", "_"), $safeTargets) $buildResult = Invoke-LoggedCommand ` -Command $presetCmakeCommand ` -Arguments $buildArgs ` -LogPath $buildLog ` -FailureTailLines $FailureTailLines $buildExitCode = $buildResult.exitCode } else { & $presetCmakeCommand @buildArgs $buildExitCode = $LASTEXITCODE } if ($buildExitCode -ne 0 -and $overallExitCode -eq 0) { $overallExitCode = $buildExitCode } $result = [ordered]@{ preset = $preset stage = "build" targets = $Targets exitCode = $buildExitCode } if ($Quiet) { $result.log = $buildLog if ($buildResult.Contains("failureTail")) { $result.failureTail = $buildResult.failureTail } } $results += $result } $elapsed = [int]((Get-Date) - $started).TotalMilliseconds [ordered]@{ command = "platform-build" exitCode = $overallExitCode elapsedMs = $elapsed androidToolchain = $androidToolchain vcpkgToolchain = $vcpkgToolchain results = $results } | ConvertTo-Json -Compress -Depth 6 exit $overallExitCode