diff --git a/android/android/CMakeLists.txt b/android/android/CMakeLists.txt index 33e60e4..8059c56 100644 --- a/android/android/CMakeLists.txt +++ b/android/android/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.10) +project(PanoPainterAndroidNative LANGUAGES C CXX) + include(../cmake/PanoPainterAndroidLegacyCompat.cmake) link_directories( diff --git a/android/focus/CMakeLists.txt b/android/focus/CMakeLists.txt index c178c09..7368499 100644 --- a/android/focus/CMakeLists.txt +++ b/android/focus/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.10) +project(PanoPainterFocusNative LANGUAGES C CXX) + include(../cmake/PanoPainterAndroidLegacyCompat.cmake) # build native_app_glue as a static lib diff --git a/android/quest/CMakeLists.txt b/android/quest/CMakeLists.txt index f1aad51..9bfe1b8 100644 --- a/android/quest/CMakeLists.txt +++ b/android/quest/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.10) +project(PanoPainterQuestNative LANGUAGES C CXX) + include(../cmake/PanoPainterAndroidLegacyCompat.cmake) # build native_app_glue as a static lib diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index 19845e4..a36f412 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -73,10 +73,8 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 - ctest --preset desktop-fast-vcpkg --build-config Debug cmake --preset android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 -cmake -S android/android -B out/build/android-legacy-standard-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE="$env:ANDROID_NDK_HOME\build\cmake\android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -cmake --build out/build/android-legacy-standard-arm64 --target native-lib -cmake -S android/quest -B out/build/android-legacy-quest-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE="$env:ANDROID_NDK_HOME\build\cmake\android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 -cmake -S android/focus -B out/build/android-legacy-focus-arm64 -G Ninja -DCMAKE_TOOLCHAIN_FILE="$env:ANDROID_NDK_HOME\build\cmake\android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-23 +powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard +powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages quest,focus -ConfigureOnly powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly cmake --fresh --preset windows-clangcl-asan @@ -98,7 +96,12 @@ Known local toolchain state: - Bundled vcpkg: `C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg` (`vcpkg version` reports 2025-11-19) - Android SDK: `C:\Users\omara\AppData\Local\Android\Sdk` -- Android NDK: `C:\Users\omara\AppData\Local\Android\Sdk\ndk\29.0.14206865` +- Android NDK: latest SDK Manager package selected by + `scripts/automation/android-sdk-env.ps1`; currently + `C:\Users\omara\AppData\Local\Android\Sdk\ndk\30.0.14904198` +- Android CMake: latest SDK Manager package selected by + `scripts/automation/android-sdk-env.ps1`; currently + `C:\Users\omara\AppData\Local\Android\Sdk\cmake\4.1.2` - clang-cl: `C:\Program Files\LLVM\bin\clang-cl.exe` reports 18.1.8, but the selected VS 2026-preview STL expects Clang 20 or newer; see DEBT-0014 before treating `windows-clangcl-asan` as a passing sanitizer gate. diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 6cd452e..28dec76 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -256,6 +256,12 @@ agent or engineer to remove them without reconstructing context from chat. The standard arm64 `native-lib` package target builds and links directly; Quest and Focus package CMake paths configure with the current Yoga source list. APK/package migration into root CMake remains open. +- 2026-06-05: DEBT-0009 was narrowed again. Android automation now selects the + newest installed SDK Manager NDK/CMake pair through + `scripts/automation/android-sdk-env.*`, reports that toolchain in structured + wrapper output, and the current host installed/validated NDK `30.0.14904198` + plus CMake `4.1.2`. Root Android `pp_assets`, retained standard + `native-lib`, and retained Quest/Focus configure gates pass with that pair. - 2026-06-04: DEBT-0036 was narrowed again. Canvas stroke commit, thumbnail, and object-draw history paths now query saved blend state through tested `pp_renderer_gl` capability-state dispatch; CanvasLayer equirect @@ -279,9 +285,9 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | `vcpkg` is not currently on PATH, but headless tests need to run now | `ctest --preset desktop-fast --build-config Debug` | Replace `tests/test_harness.h` tests with Catch2 tests once vcpkg toolchain/presets are validated | | DEBT-0007 | Open | Modernization | `vcpkg.json` and `windows-msvc-vcpkg-headless` are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven | Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | `$env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless`; `ctest --preset desktop-fast-vcpkg --build-config Debug` | Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions | | DEBT-0008 | Open | Modernization | `windows-msvc-default` preset is used for local validation because the VS 2026 generator is not installed here | The target VS 2026 preset must remain, but this machine configures with Visual Studio 17 2022 | `cmake --preset windows-msvc-default`; `ctest --preset desktop-fast --build-config Debug` | Validate `windows-vs2026-x64` on a machine with Visual Studio 2026 installed and make it the default Windows validation preset | -| DEBT-0009 | Open | Modernization | Android root CMake validation currently builds headless targets only, while retained standard/Quest/Focus package CMake paths now have a refreshed CMake 3.10/C++23 baseline outside root CMake; standard arm64 `native-lib` builds directly and Quest/Focus package paths configure | Platform app entrypoints still live in legacy Gradle/CMake projects and need Phase 6 alignment | `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64`; `cmake --build --preset android-x64`; `cmake --build --preset android-quest-arm64`; `cmake --build --preset android-focus-arm64`; `cmake --build out/build/android-legacy-standard-arm64 --target native-lib`; Quest/Focus retained package configure checks | Android standard, Quest, and Focus/Wave package targets consume shared component targets and have package smoke commands | +| DEBT-0009 | Open | Modernization | Android root CMake validation currently builds headless targets only, while retained standard/Quest/Focus package CMake paths now have a refreshed CMake 3.10/C++23 baseline outside root CMake; automation selects the newest installed SDK Manager NDK/CMake pair before configure | Platform app entrypoints still live in legacy Gradle/CMake projects and need Phase 6 alignment | `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64`; `cmake --build --preset android-x64`; `cmake --build --preset android-quest-arm64`; `cmake --build --preset android-focus-arm64`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages quest,focus -ConfigureOnly` | Android standard, Quest, and Focus/Wave package targets consume shared component targets and have package smoke commands | | DEBT-0010 | Open | Modernization | `pp_document` is a pure layer/frame/document/undo-history model with alpha-lock metadata, snapshot construction, per-layer frame metadata, renderer-free RGBA8 face payload storage, snapshot-embedded face-payload validation, renderer-free alpha8 selection-mask storage, PPI import/export helpers, and stroke-script-to-face-payload CLI automation, but it is not yet wired to legacy `Canvas`, legacy save, or legacy action commands | Keep extraction incremental while preserving app behavior | `ctest --preset desktop-fast --build-config Debug`; `pano_cli create-document --width 64 --height 32 --layers 2`; `pano_cli load-project --path tests\data\projects\minimal-project.ppi`; `pp_document_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_simulate_document_edits_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Legacy document behavior is represented by `pp_document` tests and the app consumes it through a boundary/facade | -| DEBT-0011 | Open | Modernization | `package-smoke` validates the Windows CMake app artifact and reports a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, and WebGL output; retained Android package native CMake paths are refreshed but APK outputs are still `blocked` because root CMake package targets do not exist yet | Platform package targets are not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug`; `bash -n scripts/automation/package-smoke.sh`; retained Android standard `native-lib` build and Quest/Focus configure checks | Package-smoke builds and validates Windows AppX, Android APK variants, Apple bundles, and WebGL output where local toolchains are present | +| DEBT-0011 | Open | Modernization | `package-smoke` validates the Windows CMake app artifact and reports a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, and WebGL output; retained Android package native CMake paths are refreshed and use latest SDK-managed NDK/CMake selection, but APK outputs are still `blocked` because root CMake package targets do not exist yet | Platform package targets are not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug`; `bash -n scripts/automation/package-smoke.sh`; retained Android standard `native-lib` build and Quest/Focus configure checks | Package-smoke builds and validates Windows AppX, Android APK variants, Apple bundles, and WebGL output where local toolchains are present | | DEBT-0012 | Open | Modernization | `pp_ui_core` uses vcpkg tinyxml2 on `windows-msvc-vcpkg-headless`, but retains `pp_vendor_tinyxml2` for default and unproven platform presets | Mobile/AppX/Apple triplets and app packaging still need validation before removing the vendored fallback | `ctest --preset desktop-fast-vcpkg --build-config Debug`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64` | All supported presets consume vcpkg tinyxml2 or document a permanent vendored exception | | DEBT-0013 | Open | Modernization | `pp_assets`, `pp_document`, `pano_cli inspect-project`, `pano_cli load-project`, and `pano_cli save-project` validate the fixed PPI header, thumbnail/body byte layout, generated multi-layer/multi-frame PPI writing with explicit layer opacity/blend/alpha-lock/visibility metadata, per-layer frame durations, metadata-only and targeted dirty-face-payload save/load round-trips, layer/frame index, dirty-face descriptors, dirty-face PNG payload metadata, asset-level RGBA PNG payload decoding, pure document-to-PPI export, CLI document export automation, file-writing document export automation, stroke-script-generated document payload export, and decoded pixel attachment to `pp_document`, but full legacy PPI round-trip parity is not yet extracted | Full PPI save parity requires staged extraction of legacy `Canvas` serialization and image/layer payload handling | `ctest --preset desktop-fast --build-config Debug`; `pp_assets_image_pixels_tests`; `pp_assets_ppi_header_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_inspect_project_layout_smoke`; `pano_cli_load_project_metadata_smoke`; `pano_cli_save_project_roundtrip_smoke`; `pano_cli_save_project_payload_roundtrip_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Full PPI load/save fixtures cover thumbnails, decoded layer face payloads attached to documents, frames, corrupt payloads, dirty-face payload saving, arbitrary legacy canvas payload/layout combinations, and legacy app round-trip compatibility | | DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix | @@ -325,8 +331,8 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0053 | Open | Modernization | Prepared-file writable target selection and prepared-file export-dialog policy now dispatch through `PlatformServices`; iOS temporary-file and WebGL data-path target planning live in tested `pp_platform_api::platform_policy`, but retained iOS/Web save/download handoff execution still lives in `src/platform_legacy/legacy_platform_services.*` | Preserve mobile/Web export handoff behavior while platform shells are extracted incrementally | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug`; Windows app build; Apple/Web package smoke once root package builds exist | Prepared-file target selection, export-dialog policy, and save/download handoff are owned by injected platform services with no legacy adapter branch | | DEBT-0054 | Open | Modernization | Layout XML file read/reload decisions now consume `pp_platform_api::plan_asset_file_load`; platform-family reload behavior lives in tested `pp_platform_api::platform_policy` and pure probed planning, but the live wrapper still performs direct `stat` probing for Windows/macOS mtime reload checks until platform storage/file-watch services exist | Preserve current layout hot-reload and mobile/Web single-load behavior while removing platform guards from the shared `LayoutManager` parser | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build | Layout reload decisions are owned by injected platform storage/file-watch services or an asset manager boundary with platform-specific file watching removed from compile-time helpers | | DEBT-0055 | Open | Modernization | `src/app.h` now forward-declares retained iOS/macOS/Android/Linux/Web platform handles instead of including platform SDK headers, and full SDK includes are isolated in `src/platform_legacy/legacy_platform_services.cpp`, but the `App` singleton still stores those platform handles directly | Reduce central header platform coupling incrementally without rewriting non-Windows platform entrypoints before Phase 6 | Windows app build; Apple/Android/Linux/Web package smoke once platform root builds are active | Platform handles are owned by injected `pp_platform_*` shell state or services, and `App` has no platform SDK handle fields or platform conditional members | -| DEBT-0056 | Open | Modernization | `src/asset.h` is now Android-SDK-free and uses opaque Android asset handles behind `Asset::set_android_asset_manager`, but retained `Asset` still owns a static Android asset-manager bridge and `src/asset.cpp` still performs Android `AAssetManager` reads directly; the current `android-arm64` root preset is headless and does not expose `pp_legacy_assets_io`, though the retained Android standard package `native-lib` now builds through its refreshed C++23 CMake path | Reduce legacy asset I/O header coupling without rewriting Android asset loading before the asset manager/storage boundary exists | Windows app build; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 -Targets pp_assets`; `cmake --build out/build/android-legacy-standard-arm64 --target native-lib` | Android asset loading is owned by injected asset storage/platform services or `pp_assets` file providers, with no static Android asset manager on `Asset` | -| DEBT-0060 | Open | Modernization | Retained Android package CMake generates a patched `nanort.h` overlay in the build tree for `native-lib` instead of modifying the `libs/nanort` submodule | Current NDK/Clang rejects `TriangleSAHPred::operator=` assigning to a `const size_t` member, but the retained grid/lightmap path still includes `nanort` before that dependency is replaced or updated | `cmake --build out/build/android-legacy-standard-arm64 --target native-lib`; Quest/Focus retained package configure checks; Windows app build | Update/replace `nanort`, move grid/lightmap baking behind a component that owns its dependency, or retire the retained Android package CMake path so no generated vendor overlay is required | +| DEBT-0056 | Open | Modernization | `src/asset.h` is now Android-SDK-free and uses opaque Android asset handles behind `Asset::set_android_asset_manager`, but retained `Asset` still owns a static Android asset-manager bridge and `src/asset.cpp` still performs Android `AAssetManager` reads directly; the current `android-arm64` root preset is headless and does not expose `pp_legacy_assets_io`, though the retained Android standard package `native-lib` now builds through its refreshed C++23 CMake path | Reduce legacy asset I/O header coupling without rewriting Android asset loading before the asset manager/storage boundary exists | Windows app build; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 -Targets pp_assets`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard` | Android asset loading is owned by injected asset storage/platform services or `pp_assets` file providers, with no static Android asset manager on `Asset` | +| DEBT-0060 | Open | Modernization | Retained Android package CMake generates a patched `nanort.h` overlay in the build tree for `native-lib` instead of modifying the `libs/nanort` submodule | Current SDK Manager NDK/Clang rejects `TriangleSAHPred::operator=` assigning to a `const size_t` member, but the retained grid/lightmap path still includes `nanort` before that dependency is replaced or updated | `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard`; Quest/Focus retained package configure checks; Windows app build | Update/replace `nanort`, move grid/lightmap baking behind a component that owns its dependency, or retire the retained Android package CMake path so no generated vendor overlay is required | | DEBT-0057 | Open | Modernization | Default canvas allocation size now dispatches through `PlatformServices::default_canvas_resolution`, removing the `CANVAS_RES` platform macro from `src/canvas.h`; WebGL's retained 512 default now lives in tested `pp_platform_api::platform_policy`, but the Web shell still reaches it through the legacy platform fallback until injected Web services own the policy | Preserve WebGL memory behavior while moving canvas creation policy out of shared canvas headers and into the platform boundary | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build; WebGL package smoke once root Web build exists | Default canvas resolution is owned by injected `pp_platform_*` services for every supported platform, with no WebGL branch in the legacy fallback | | DEBT-0058 | Open | Modernization | App-level progress/message/input dialog metadata, including message-dialog OK/cancel captions, now consumes pure `pp_app_core` through `App::show_progress`, `App::message_box`, `App::input_box`, `pano_cli plan-app-dialog`, and `pp_app_core_app_dialog_tests`; live execution is centralized in `src/legacy_app_dialog_services.*`, but the bridge still creates retained `NodeProgressBar`, `NodeMessageBox`, and `NodeInputBox` instances and inserts them into the legacy layout tree | Preserve current app-shell dialog behavior while moving shared dialog policy toward UI/app services | `pp_app_core_app_dialog_tests`; `pano_cli plan-app-dialog --kind progress --total -4`; `pano_cli plan-app-dialog --kind message --cancel`; `pano_cli plan-app-dialog --kind input --ok-caption Save`; `ctest --preset desktop-fast --build-config Debug`; Windows app build | Progress/message/input dialog creation, callback wiring, layout insertion, lifetime ownership, and headless automation are owned by injected app/UI services with `App` methods acting only as adapters | | DEBT-0059 | Open | Modernization | iOS root CMake headless builds assign generated bundle identifiers and disable code signing for executable test/tool targets | The current Apple gate is compile validation for shared component targets; signed iOS app/package validation is not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device`; `sh scripts/automation/platform-build.sh "ios-device"` on `panopainter-mac` | Root CMake owns the signed Apple app/package targets, package-smoke validates Apple bundles where signing material is available, and headless iOS test/tool targets are either excluded from signed package builds or use explicit test-runner signing policy | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 6d31a4d..1c01b4e 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -1417,7 +1417,11 @@ monolithically, and share a generated `nanort` compatibility overlay from `android/cmake/PanoPainterAndroidLegacyCompat.cmake` instead of dirtying the vendor submodule. The standard package `native-lib` arm64 target now compiles and links with the current NDK; Quest and Focus configure with the aligned Yoga -source list and their SDK imported-library paths. +source list and their SDK imported-library paths. Android automation now +discovers the newest installed SDK-managed NDK and CMake package before +configuring Android presets or retained package paths; on the current Windows +host that selects NDK `30.0.14904198` and CMake `4.1.2` after installing the +latest NDK through `sdkmanager`. Implementation tasks: @@ -2371,6 +2375,9 @@ Results: configures/builds `native-lib` directly for arm64 using C++23 and the shared modern component source set, while Quest and Focus package CMake paths configure with the same compatibility helper and current Yoga source list. + The Android platform-build wrapper and retained package helper now select the + newest installed SDK Manager NDK/CMake pair automatically and report the + selected versions in their structured output. - Desktop VR drawing now routes generic OpenGL scissor/depth/blend state, blend/depth state snapshots and restores, depth clears, active texture units, and fallback 2D texture unbinds through tested renderer GL backend dispatch; diff --git a/scripts/automation/android-legacy-package-build.ps1 b/scripts/automation/android-legacy-package-build.ps1 new file mode 100644 index 0000000..7bf6d46 --- /dev/null +++ b/scripts/automation/android-legacy-package-build.ps1 @@ -0,0 +1,103 @@ +[CmdletBinding()] +param( + [string[]]$Packages = @("standard"), + [switch]$ConfigureOnly +) + +$ErrorActionPreference = "Stop" + +. "$PSScriptRoot\android-sdk-env.ps1" + +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 +} + +$Packages = @(Expand-ArgumentList -Values $Packages) + +$toolchain = Set-AndroidSdkToolchainEnvironment +$packageMap = @{ + standard = "android/android" + quest = "android/quest" + focus = "android/focus" +} + +$started = Get-Date +$results = @() +$overallExitCode = 0 + +foreach ($package in $Packages) { + if (!$packageMap.ContainsKey($package)) { + throw "Unknown Android package '$package'. Expected one of: standard, quest, focus." + } + + $sourceDir = $packageMap[$package] + $buildDir = "out/build/android-legacy-$package-arm64" + $toolchainFile = Join-Path $toolchain.ndkPath "build\cmake\android.toolchain.cmake" + + $configureArgs = @( + "-S", $sourceDir, + "-B", $buildDir, + "-G", "Ninja", + "-DCMAKE_TOOLCHAIN_FILE=$toolchainFile", + "-DANDROID_ABI=arm64-v8a", + "-DANDROID_PLATFORM=android-23" + ) + + & $toolchain.cmakeCommand @configureArgs + $configureExitCode = $LASTEXITCODE + if ($configureExitCode -ne 0) { + if ($overallExitCode -eq 0) { + $overallExitCode = $configureExitCode + } + $results += [ordered]@{ + package = $package + stage = "configure" + exitCode = $configureExitCode + } + continue + } + + if ($ConfigureOnly) { + $results += [ordered]@{ + package = $package + stage = "configure" + exitCode = 0 + } + continue + } + + & $toolchain.cmakeCommand --build $buildDir --target native-lib + $buildExitCode = $LASTEXITCODE + if ($buildExitCode -ne 0 -and $overallExitCode -eq 0) { + $overallExitCode = $buildExitCode + } + + $results += [ordered]@{ + package = $package + stage = "build" + target = "native-lib" + exitCode = $buildExitCode + } +} + +$elapsed = [int]((Get-Date) - $started).TotalMilliseconds +[ordered]@{ + command = "android-legacy-package-build" + exitCode = $overallExitCode + elapsedMs = $elapsed + androidToolchain = $toolchain + results = $results +} | ConvertTo-Json -Compress -Depth 6 + +exit $overallExitCode diff --git a/scripts/automation/android-sdk-env.ps1 b/scripts/automation/android-sdk-env.ps1 new file mode 100644 index 0000000..060e163 --- /dev/null +++ b/scripts/automation/android-sdk-env.ps1 @@ -0,0 +1,66 @@ +[CmdletBinding()] +param() + +$ErrorActionPreference = "Stop" + +function Get-AndroidSdkRoot { + $candidates = @( + $env:ANDROID_SDK_ROOT, + $env:ANDROID_HOME, + (Join-Path $env:LOCALAPPDATA "Android\Sdk") + ) + + foreach ($candidate in $candidates) { + if ($candidate -and (Test-Path -LiteralPath $candidate -PathType Container)) { + return (Resolve-Path -LiteralPath $candidate).Path + } + } + + throw "Android SDK root was not found. Install command-line tools or set ANDROID_SDK_ROOT." +} + +function Get-LatestAndroidSdkPackageDirectory { + param( + [Parameter(Mandatory=$true)][string]$SdkRoot, + [Parameter(Mandatory=$true)][string]$PackageName + ) + + $packageRoot = Join-Path $SdkRoot $PackageName + if (!(Test-Path -LiteralPath $packageRoot -PathType Container)) { + throw "Android SDK package directory not found: $packageRoot" + } + + $packages = @(Get-ChildItem -LiteralPath $packageRoot -Directory | + Where-Object { $_.Name -match '^\d+(\.\d+)*$' } | + Sort-Object { [version]$_.Name } -Descending) + + if ($packages.Count -eq 0) { + throw "No installed Android SDK package versions found under $packageRoot" + } + + return $packages[0] +} + +function Set-AndroidSdkToolchainEnvironment { + $sdkRoot = Get-AndroidSdkRoot + $ndk = Get-LatestAndroidSdkPackageDirectory -SdkRoot $sdkRoot -PackageName "ndk" + $cmake = Get-LatestAndroidSdkPackageDirectory -SdkRoot $sdkRoot -PackageName "cmake" + $cmakeCommand = Join-Path $cmake.FullName "bin\cmake.exe" + + if (!(Test-Path -LiteralPath $cmakeCommand -PathType Leaf)) { + throw "Android SDK CMake executable not found: $cmakeCommand" + } + + $env:ANDROID_HOME = $sdkRoot + $env:ANDROID_SDK_ROOT = $sdkRoot + $env:ANDROID_NDK_HOME = $ndk.FullName + $env:ANDROID_NDK_ROOT = $ndk.FullName + + return [ordered]@{ + sdkRoot = $sdkRoot + ndkVersion = $ndk.Name + ndkPath = $ndk.FullName + cmakeVersion = $cmake.Name + cmakeCommand = $cmakeCommand + } +} diff --git a/scripts/automation/android-sdk-env.sh b/scripts/automation/android-sdk-env.sh new file mode 100644 index 0000000..5e076ce --- /dev/null +++ b/scripts/automation/android-sdk-env.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env sh + +android_sdk_root() { + if [ -n "${ANDROID_SDK_ROOT:-}" ] && [ -d "$ANDROID_SDK_ROOT" ]; then + printf '%s\n' "$ANDROID_SDK_ROOT" + return 0 + fi + + if [ -n "${ANDROID_HOME:-}" ] && [ -d "$ANDROID_HOME" ]; then + printf '%s\n' "$ANDROID_HOME" + return 0 + fi + + if [ -n "${LOCALAPPDATA:-}" ]; then + local_sdk="$LOCALAPPDATA/Android/Sdk" + if command -v cygpath >/dev/null 2>&1; then + local_sdk="$(cygpath -u "$local_sdk")" + fi + if [ -d "$local_sdk" ]; then + printf '%s\n' "$local_sdk" + return 0 + fi + fi + + if [ -d "$HOME/Android/Sdk" ]; then + printf '%s\n' "$HOME/Android/Sdk" + return 0 + fi + + return 1 +} + +latest_android_package_dir() { + root="$1" + package="$2" + package_root="$root/$package" + [ -d "$package_root" ] || return 1 + latest="$( + for dir in "$package_root"/*; do + [ -d "$dir" ] || continue + version="${dir##*/}" + printf '%s\n' "$version" + done | grep -E '^[0-9]+(\.[0-9]+)*$' | sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -n 1 + )" + [ -n "$latest" ] || return 1 + printf '%s/%s\n' "$package_root" "$latest" +} + +set_android_sdk_toolchain_environment() { + sdk_root="$(android_sdk_root)" || { + printf '%s\n' "Android SDK root was not found. Install command-line tools or set ANDROID_SDK_ROOT." >&2 + return 1 + } + + ndk_dir="$(latest_android_package_dir "$sdk_root" ndk)" || { + printf '%s\n' "No installed Android NDK package was found under $sdk_root/ndk." >&2 + return 1 + } + + cmake_dir="$(latest_android_package_dir "$sdk_root" cmake)" || { + printf '%s\n' "No installed Android CMake package was found under $sdk_root/cmake." >&2 + return 1 + } + + cmake_command="$cmake_dir/bin/cmake" + [ -x "$cmake_command" ] || { + printf '%s\n' "Android SDK CMake executable not found: $cmake_command" >&2 + return 1 + } + + export ANDROID_HOME="$sdk_root" + export ANDROID_SDK_ROOT="$sdk_root" + export ANDROID_NDK_HOME="$ndk_dir" + export ANDROID_NDK_ROOT="$ndk_dir" + export ANDROID_CMAKE_COMMAND="$cmake_command" + export ANDROID_NDK_VERSION="${ndk_dir##*/}" + export ANDROID_CMAKE_VERSION="${cmake_dir##*/}" +} diff --git a/scripts/automation/platform-build.ps1 b/scripts/automation/platform-build.ps1 index f841a88..78aa2e6 100644 --- a/scripts/automation/platform-build.ps1 +++ b/scripts/automation/platform-build.ps1 @@ -96,12 +96,25 @@ function Expand-ArgumentList { $Presets = @(Expand-ArgumentList -Values $Presets) $Targets = @(Expand-ArgumentList -Values $Targets) +$cmakeCommand = "cmake" +$androidToolchain = $null +if ($Presets | Where-Object { $_ -like "android-*" }) { + . "$PSScriptRoot\android-sdk-env.ps1" + $androidToolchain = Set-AndroidSdkToolchainEnvironment + $cmakeCommand = $androidToolchain.cmakeCommand +} + $started = Get-Date $results = @() $overallExitCode = 0 foreach ($preset in $Presets) { - & cmake --preset $preset + $presetCmakeCommand = $cmakeCommand + if ($androidToolchain -and $preset -notlike "android-*") { + $presetCmakeCommand = "cmake" + } + + & $presetCmakeCommand --preset $preset $configureExitCode = $LASTEXITCODE if ($configureExitCode -ne 0) { $overallExitCode = $configureExitCode @@ -118,7 +131,7 @@ foreach ($preset in $Presets) { $buildArgs += @("--target", $target) } - & cmake @buildArgs + & $presetCmakeCommand @buildArgs $buildExitCode = $LASTEXITCODE if ($buildExitCode -ne 0 -and $overallExitCode -eq 0) { $overallExitCode = $buildExitCode @@ -137,6 +150,7 @@ $elapsed = [int]((Get-Date) - $started).TotalMilliseconds command = "platform-build" exitCode = $overallExitCode elapsedMs = $elapsed + androidToolchain = $androidToolchain results = $results } | ConvertTo-Json -Compress -Depth 6 diff --git a/scripts/automation/platform-build.sh b/scripts/automation/platform-build.sh index 6274ab7..0e36b19 100644 --- a/scripts/automation/platform-build.sh +++ b/scripts/automation/platform-build.sh @@ -6,6 +6,16 @@ shift || true 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_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_platform_api_tests pp_ui_core_color_tests pp_ui_core_layout_value_tests pp_ui_core_layout_xml_tests pp_app_core_about_menu_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_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}" start="$(date +%s)" +android_cmake_cmd="" +case " $presets " in + *" android-"*) + # shellcheck disable=SC1091 + . "$(dirname "$0")/android-sdk-env.sh" + set_android_sdk_toolchain_environment || exit 1 + android_cmake_cmd="$ANDROID_CMAKE_COMMAND" + ;; +esac + overall_exit=0 results="" first_result=1 @@ -17,14 +27,21 @@ done normalized_presets="$(printf '%s' "$presets" | tr ',' ' ')" for preset in $normalized_presets; do - cmake --preset "$preset" + cmake_cmd="cmake" + case "$preset" in + android-*) + cmake_cmd="$android_cmake_cmd" + ;; + esac + + "$cmake_cmd" --preset "$preset" configure_exit="$?" if [ "$configure_exit" -ne 0 ]; then [ "$overall_exit" -eq 0 ] && overall_exit="$configure_exit" result="$(printf '{"preset":"%s","stage":"configure","exitCode":%s}' "$preset" "$configure_exit")" else # shellcheck disable=SC2086 - cmake --build --preset "$preset" $build_args + "$cmake_cmd" --build --preset "$preset" $build_args build_exit="$?" [ "$build_exit" -ne 0 ] && [ "$overall_exit" -eq 0 ] && overall_exit="$build_exit" result="$(printf '{"preset":"%s","stage":"build","targets":"%s","exitCode":%s}' "$preset" "$targets" "$build_exit")" @@ -40,5 +57,9 @@ done end="$(date +%s)" elapsed_ms="$(( (end - start) * 1000 ))" -printf '{"command":"platform-build","exitCode":%s,"elapsedMs":%s,"results":[%s]}\n' "$overall_exit" "$elapsed_ms" "$results" +if [ -n "${ANDROID_NDK_HOME:-}" ] && [ -n "${ANDROID_CMAKE_COMMAND:-}" ]; then + printf '{"command":"platform-build","exitCode":%s,"elapsedMs":%s,"androidToolchain":{"sdkRoot":"%s","ndkVersion":"%s","ndkPath":"%s","cmakeVersion":"%s","cmakeCommand":"%s"},"results":[%s]}\n' "$overall_exit" "$elapsed_ms" "$ANDROID_SDK_ROOT" "$ANDROID_NDK_VERSION" "$ANDROID_NDK_HOME" "$ANDROID_CMAKE_VERSION" "$ANDROID_CMAKE_COMMAND" "$results" +else + printf '{"command":"platform-build","exitCode":%s,"elapsedMs":%s,"results":[%s]}\n' "$overall_exit" "$elapsed_ms" "$results" +fi exit "$overall_exit"