From 13c5bffeaf18773c82f8d3f7293528e8376be234 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 08:30:56 -0700 Subject: [PATCH 01/36] win arm64 --- .../v2/templates/stages-build-native.yml | 36 +++++++++++++++- .pipelines/v2/templates/stages-cs.yml | 27 ++++++++++++ .pipelines/v2/templates/stages-js.yml | 38 +++++++++++++---- .pipelines/v2/templates/stages-python.yml | 42 +++++++++++++++---- .pipelines/v2/templates/steps-build-js.yml | 2 +- .../v2/templates/steps-build-python.yml | 2 +- .../v2/templates/steps-build-windows.yml | 16 ++++--- .pipelines/v2/templates/steps-test-js.yml | 6 +-- sdk_v2/js/package-lock.json | 30 ------------- 9 files changed, 142 insertions(+), 57 deletions(-) diff --git a/.pipelines/v2/templates/stages-build-native.yml b/.pipelines/v2/templates/stages-build-native.yml index f46777676..2dd9d09dc 100644 --- a/.pipelines/v2/templates/stages-build-native.yml +++ b/.pipelines/v2/templates/stages-build-native.yml @@ -56,7 +56,7 @@ stages: stageHeaders: true # ==================================================================== - # Windows ARM64 — cross-compile only (no tests on x64 host) + # Windows ARM64 — build # ==================================================================== - stage: cpp_build_win_arm64 displayName: 'C++ Native: Windows ARM64' @@ -65,8 +65,9 @@ stages: jobs: - job: build pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-native-arm64-16core os: windows + hostArchitecture: arm64 templateContext: inputs: - input: pipelineArtifact @@ -86,6 +87,37 @@ stages: winmlVersion: ${{ parameters.winmlVersion }} runTests: false stageHeaders: false + pythonArchitecture: arm64 + + # ==================================================================== + # Windows ARM64 (native) — test + # ==================================================================== + - stage: cpp_test_win_arm64 + displayName: 'C++ Native: Test Windows ARM64' + dependsOn: + - compute_version + jobs: + - job: test + pool: + name: onnxruntime-native-arm64-16core + os: windows + hostArchitecture: arm64 + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'version-info' + targetPath: '$(Pipeline.Workspace)/version-info' + steps: + - template: steps-build-windows.yml + parameters: + arch: arm64 + buildConfig: ${{ parameters.buildConfig }} + ortVersion: ${{ parameters.ortVersion }} + genaiVersion: ${{ parameters.genaiVersion }} + winmlVersion: ${{ parameters.winmlVersion }} + runTests: true + stageHeaders: false + pythonArchitecture: arm64 # ==================================================================== # Linux x64 — build + test diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index b83f48b35..84e016573 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -73,6 +73,33 @@ stages: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' +- stage: cs_test_win_arm64 + displayName: 'C# SDK: Test Windows ARM64' + dependsOn: + - cs_build + jobs: + - job: test + pool: + name: onnxruntime-native-arm64-16core + os: windows + hostArchitecture: arm64 + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'version-info' + targetPath: '$(Pipeline.Workspace)/version-info' + - input: pipelineArtifact + artifactName: 'cpp-nuget' + targetPath: '$(Pipeline.Workspace)/cpp-nuget' + steps: + - checkout: self + clean: true + - template: ../../templates/fetch-test-data-from-blob.yml@self + - template: steps-test-cs.yml + parameters: + flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' + testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + # ==================================================================== # Test — Linux x64 / macOS ARM64 # ==================================================================== diff --git a/.pipelines/v2/templates/stages-js.yml b/.pipelines/v2/templates/stages-js.yml index f11ed23bb..2d68a3b74 100644 --- a/.pipelines/v2/templates/stages-js.yml +++ b/.pipelines/v2/templates/stages-js.yml @@ -13,8 +13,7 @@ # * cpp_build_win_x64 (the cpp-native-include artifact, which is # stage-headers-only on the win-x64 build) # -# Tests run on the same platform as the build, except win-arm64 (no -# Windows-ARM64 pool; build-only, matching the C# + Python matrices). +# Tests run on the same platform as the build. stages: @@ -69,8 +68,9 @@ stages: jobs: - job: build pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-native-arm64-16core os: windows + hostArchitecture: arm64 variables: - group: FoundryLocal-ESRP-Signing templateContext: @@ -97,7 +97,6 @@ stages: nativeArtifactDir: '$(Pipeline.Workspace)/cpp-native-win-arm64' includeArtifactDir: '$(Pipeline.Workspace)/cpp-native-include' outputDir: '$(Build.ArtifactStagingDirectory)/js-prebuild' - targetArch: 'arm64' signWindows: true - stage: js_build_linux_x64 @@ -177,9 +176,9 @@ stages: outputDir: '$(Build.ArtifactStagingDirectory)/js-prebuild' signMac: true -# ===================================================================== -# Test stages — same-platform only. win-arm64 is build-only. -# ===================================================================== +# ================================================================ +# Test stages — same-platform only (including native win-arm64). +# ================================================================ - stage: js_test_win_x64 displayName: 'JS SDK: Test Windows x64' @@ -205,6 +204,31 @@ stages: prebuildArtifactDir: '$(Pipeline.Workspace)/js-prebuild-win-x64' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' +- stage: js_test_win_arm64 + displayName: 'JS SDK: Test Windows ARM64' + dependsOn: + - js_build_win_arm64 + jobs: + - job: test + pool: + name: onnxruntime-native-arm64-16core + os: windows + hostArchitecture: arm64 + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'js-prebuild-win-arm64' + targetPath: '$(Pipeline.Workspace)/js-prebuild-win-arm64' + steps: + - checkout: self + clean: true + - template: ../../templates/fetch-test-data-from-blob.yml@self + - template: steps-test-js.yml + parameters: + rid: 'win-arm64' + prebuildArtifactDir: '$(Pipeline.Workspace)/js-prebuild-win-arm64' + testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + - stage: js_test_linux_x64 displayName: 'JS SDK: Test Linux x64' dependsOn: diff --git a/.pipelines/v2/templates/stages-python.yml b/.pipelines/v2/templates/stages-python.yml index c67002f9b..932ce1ca7 100644 --- a/.pipelines/v2/templates/stages-python.yml +++ b/.pipelines/v2/templates/stages-python.yml @@ -1,7 +1,7 @@ # Build + test stages for the sdk_v2 Python SDK (foundry-local-sdk). # -# Builds win-x64 + win-arm64 + linux-x64 + osx-arm64; tests win-x64 + linux-x64 -# + osx-arm64 (win-arm64 is build-only, matching the C# matrix). +# Builds win-x64 + win-arm64 + linux-x64 + osx-arm64; tests win-x64 + +# win-arm64 + linux-x64 + osx-arm64. # # Each build stage depends on the matching native build stage from # stages-build-native.yml and consumes the `cpp-native-` pipeline artifact @@ -55,8 +55,9 @@ stages: jobs: - job: build pool: - name: onnxruntime-Win-CPU-2022 + name: onnxruntime-native-arm64-16core os: windows + hostArchitecture: arm64 templateContext: inputs: - input: pipelineArtifact @@ -76,7 +77,7 @@ stages: parameters: nativeArtifactDir: '$(Pipeline.Workspace)/cpp-native-win-arm64' rid: 'win-arm64' - targetArch: 'arm64' + pythonArchitecture: 'arm64' outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk' - stage: python_build_linux_x64 @@ -144,9 +145,9 @@ stages: pythonArchitecture: 'arm64' outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk' -# ================================================================= -# Tests — win-x64, linux-x64, osx-arm64. win-arm64 is build-only. -# ================================================================= +# ====================================================== +# Tests — win-x64, win-arm64, linux-x64, osx-arm64. +# ====================================================== - stage: python_test_win_x64 displayName: 'Python SDK: Test Windows x64' dependsOn: @@ -172,6 +173,33 @@ stages: wheelDir: '$(Pipeline.Workspace)/python-sdk-win-x64' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' +- stage: python_test_win_arm64 + displayName: 'Python SDK: Test Windows ARM64' + dependsOn: + - python_build_win_arm64 + jobs: + - job: test + pool: + name: onnxruntime-native-arm64-16core + os: windows + hostArchitecture: arm64 + templateContext: + inputs: + - input: pipelineArtifact + artifactName: 'python-sdk-win-arm64' + targetPath: '$(Pipeline.Workspace)/python-sdk-win-arm64' + steps: + - checkout: self + clean: true + - template: ../../templates/checkout-steps.yml@self + parameters: + repoName: test-data-shared + - template: steps-test-python.yml + parameters: + wheelDir: '$(Pipeline.Workspace)/python-sdk-win-arm64' + testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + pythonArchitecture: 'arm64' + - stage: python_test_linux_x64 displayName: 'Python SDK: Test Linux x64' dependsOn: diff --git a/.pipelines/v2/templates/steps-build-js.yml b/.pipelines/v2/templates/steps-build-js.yml index 657704bd9..d8136dbad 100644 --- a/.pipelines/v2/templates/steps-build-js.yml +++ b/.pipelines/v2/templates/steps-build-js.yml @@ -34,7 +34,7 @@ parameters: type: string default: 'native' values: ['native', 'arm64'] - displayName: 'Cross-compile target arch for node-gyp on Windows x64 host. "native" = no cross.' + displayName: 'Optional node-gyp target arch override on Windows. "native" = host architecture.' - name: signWindows type: boolean default: false diff --git a/.pipelines/v2/templates/steps-build-python.yml b/.pipelines/v2/templates/steps-build-python.yml index 50f86c9da..4d471e91c 100644 --- a/.pipelines/v2/templates/steps-build-python.yml +++ b/.pipelines/v2/templates/steps-build-python.yml @@ -25,7 +25,7 @@ parameters: type: string default: 'native' values: ['native', 'arm64'] - displayName: 'Cross-compile target arch on a Windows x64 host. Use "native" for no cross-compile.' + displayName: 'Optional Windows wheel target arch override. Use "native" for host-native builds.' - name: pythonArchitecture type: string default: 'x64' diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 5f1d0f761..1ef091b41 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -5,13 +5,14 @@ # templateContext.outputs. # # Parameters: -# arch – 'x64' or 'arm64' (arm64 is cross-compiled, no tests) +# arch – 'x64' or 'arm64' # buildConfig – CMake config (Debug, Release, RelWithDebInfo, MinSizeRel) # ortVersion – Microsoft.ML.OnnxRuntime.Foundry version # genaiVersion – Microsoft.ML.OnnxRuntimeGenAI.Foundry version # winmlVersion – Microsoft.Windows.AI.MachineLearning version # runTests – Whether to run tests # stageHeaders – Whether to stage public headers as a separate artifact +# pythonArchitecture – Python architecture installed by UsePythonVersion parameters: - name: arch @@ -31,18 +32,21 @@ parameters: - name: stageHeaders type: boolean default: false +- name: pythonArchitecture + type: string + default: 'x64' + values: ['x64', 'arm64'] steps: # Windows hosted agents don't have python on PATH by default — the launcher # stub redirects to the Microsoft Store. UsePythonVersion installs and adds it -# to PATH for the rest of the job. arm64 builds cross-compile on the x64 -# Windows host, so x64 Python is correct for both archs. +# to PATH for the rest of the job. - task: UsePythonVersion@0 displayName: 'Use Python 3.12' inputs: versionSpec: '3.12' - architecture: 'x64' + architecture: '${{ parameters.pythonArchitecture }}' - script: | git clone https://github.com/microsoft/vcpkg.git $(Build.BinariesDirectory)\vcpkg @@ -51,7 +55,7 @@ steps: echo @exit /b 0 > $(Build.BinariesDirectory)\tools\pkg-config.bat displayName: 'Bootstrap vcpkg' -- template: steps-prefetch-nuget.yml + displayName: 'Configure and build (arm64)' parameters: ortVersion: ${{ parameters.ortVersion }} genaiVersion: ${{ parameters.genaiVersion }} @@ -106,7 +110,7 @@ steps: VCPKG_ROOT: $(Build.BinariesDirectory)\vcpkg PKG_CONFIG: $(Build.BinariesDirectory)\tools\pkg-config.bat -- ${{ if and(eq(parameters.runTests, true), eq(parameters.arch, 'x64')) }}: +- ${{ if eq(parameters.runTests, true) }}: - script: python build.py --test --config ${{ parameters.buildConfig }} displayName: 'Run tests' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp diff --git a/.pipelines/v2/templates/steps-test-js.yml b/.pipelines/v2/templates/steps-test-js.yml index bf7e7b74c..8393b1d03 100644 --- a/.pipelines/v2/templates/steps-test-js.yml +++ b/.pipelines/v2/templates/steps-test-js.yml @@ -7,7 +7,7 @@ parameters: - name: rid type: string - values: ['win-x64', 'linux-x64', 'osx-arm64'] + values: ['win-x64', 'win-arm64', 'linux-x64', 'osx-arm64'] displayName: 'ADO RID for the platform being tested (no cross-arch testing)' - name: prebuildArtifactDir type: string @@ -23,7 +23,7 @@ steps: inputs: versionSpec: '20.x' -- ${{ if eq(parameters.rid, 'win-x64') }}: +- ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - pwsh: | $src = "${{ parameters.prebuildArtifactDir }}/prebuilds" $dst = "$(Build.SourcesDirectory)/sdk_v2/js/prebuilds" @@ -46,7 +46,7 @@ steps: find "$dst" -maxdepth 3 -print displayName: 'Drop prebuild into sdk_v2/js/prebuilds' -- ${{ if eq(parameters.rid, 'win-x64') }}: +- ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - task: Npm@1 displayName: 'npm ci (runs install-native postinstall)' inputs: diff --git a/sdk_v2/js/package-lock.json b/sdk_v2/js/package-lock.json index c9d8a4fbd..4bf6916ce 100644 --- a/sdk_v2/js/package-lock.json +++ b/sdk_v2/js/package-lock.json @@ -445,9 +445,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -465,9 +462,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -485,9 +479,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -505,9 +496,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -525,9 +513,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -545,9 +530,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1209,9 +1191,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1233,9 +1212,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1257,9 +1233,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1281,9 +1254,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ From 08b26051c95eaf705fc5b1572ca2165d657a1663 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 08:32:57 -0700 Subject: [PATCH 02/36] typo --- .pipelines/v2/templates/steps-build-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 1ef091b41..9b1012068 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -55,7 +55,7 @@ steps: echo @exit /b 0 > $(Build.BinariesDirectory)\tools\pkg-config.bat displayName: 'Bootstrap vcpkg' - displayName: 'Configure and build (arm64)' +- template: steps-prefetch-nuget.yml parameters: ortVersion: ${{ parameters.ortVersion }} genaiVersion: ${{ parameters.genaiVersion }} @@ -104,7 +104,7 @@ steps: --cmake_generator "Visual Studio 17 2022" --winml_sdk_version ${{ parameters.winmlVersion }} --cmake_extra_defines $(cmakeFetchDefines) - displayName: 'Configure and build (arm64 cross-compile)' + displayName: 'Configure and build (arm64)' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp env: VCPKG_ROOT: $(Build.BinariesDirectory)\vcpkg From d4389ad6ac5b224ab7f08a4612a2793925f8e11c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 08:39:25 -0700 Subject: [PATCH 03/36] copilot --- .../v2/templates/stages-build-native.yml | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/.pipelines/v2/templates/stages-build-native.yml b/.pipelines/v2/templates/stages-build-native.yml index 2dd9d09dc..b43d85709 100644 --- a/.pipelines/v2/templates/stages-build-native.yml +++ b/.pipelines/v2/templates/stages-build-native.yml @@ -56,7 +56,7 @@ stages: stageHeaders: true # ==================================================================== - # Windows ARM64 — build + # Windows ARM64 — build + test # ==================================================================== - stage: cpp_build_win_arm64 displayName: 'C++ Native: Windows ARM64' @@ -78,36 +78,6 @@ stages: artifactName: 'cpp-native-win-arm64' targetPath: '$(Build.ArtifactStagingDirectory)/native' steps: - - template: steps-build-windows.yml - parameters: - arch: arm64 - buildConfig: ${{ parameters.buildConfig }} - ortVersion: ${{ parameters.ortVersion }} - genaiVersion: ${{ parameters.genaiVersion }} - winmlVersion: ${{ parameters.winmlVersion }} - runTests: false - stageHeaders: false - pythonArchitecture: arm64 - - # ==================================================================== - # Windows ARM64 (native) — test - # ==================================================================== - - stage: cpp_test_win_arm64 - displayName: 'C++ Native: Test Windows ARM64' - dependsOn: - - compute_version - jobs: - - job: test - pool: - name: onnxruntime-native-arm64-16core - os: windows - hostArchitecture: arm64 - templateContext: - inputs: - - input: pipelineArtifact - artifactName: 'version-info' - targetPath: '$(Pipeline.Workspace)/version-info' - steps: - template: steps-build-windows.yml parameters: arch: arm64 From 36158ce859054c140dd40c0cd8368ff0d07cde76 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 09:59:54 -0700 Subject: [PATCH 04/36] pwsh --- .pipelines/v2/templates/stages-build-native.yml | 1 + .pipelines/v2/templates/steps-build-windows.yml | 8 ++++++-- .pipelines/v2/templates/steps-prefetch-nuget.yml | 8 ++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.pipelines/v2/templates/stages-build-native.yml b/.pipelines/v2/templates/stages-build-native.yml index b43d85709..c9f313997 100644 --- a/.pipelines/v2/templates/stages-build-native.yml +++ b/.pipelines/v2/templates/stages-build-native.yml @@ -88,6 +88,7 @@ stages: runTests: true stageHeaders: false pythonArchitecture: arm64 + usePwsh: false # ==================================================================== # Linux x64 — build + test diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 9b1012068..51aa4dab6 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -13,6 +13,7 @@ # runTests – Whether to run tests # stageHeaders – Whether to stage public headers as a separate artifact # pythonArchitecture – Python architecture installed by UsePythonVersion +# usePwsh – Whether PowerShell tasks should use PowerShell Core parameters: - name: arch @@ -36,6 +37,9 @@ parameters: type: string default: 'x64' values: ['x64', 'arm64'] +- name: usePwsh + type: boolean + default: true steps: @@ -69,7 +73,7 @@ steps: displayName: 'Append version define' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $version = (Get-Content "$(Pipeline.Workspace)/version-info/sdkVersion.txt" -Raw).Trim() $defines = '$(cmakeFetchDefines)' + " `"FOUNDRY_LOCAL_VERSION_STRING=$version`"" @@ -131,7 +135,7 @@ steps: displayName: 'Stage native artifacts' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $binDir = '$(Build.SourcesDirectory)/sdk_v2/cpp/build/Windows/${{ parameters.buildConfig }}/bin/${{ parameters.buildConfig }}' $linkDir = '$(Build.SourcesDirectory)/sdk_v2/cpp/build/Windows/${{ parameters.buildConfig }}/${{ parameters.buildConfig }}' diff --git a/.pipelines/v2/templates/steps-prefetch-nuget.yml b/.pipelines/v2/templates/steps-prefetch-nuget.yml index 661075294..2c6b9f715 100644 --- a/.pipelines/v2/templates/steps-prefetch-nuget.yml +++ b/.pipelines/v2/templates/steps-prefetch-nuget.yml @@ -11,6 +11,7 @@ # includeWinml – Download WinML and emit WINML_EP_CATALOG_FETCH_URL # includeOrtGpuLinux – Also download Microsoft.ML.OnnxRuntime.Gpu.Linux (Linux only) # shell – 'pwsh' (Windows/macOS) or 'bash' (Linux) +# usePwsh – Whether PowerShell tasks should use PowerShell Core parameters: - name: ortVersion @@ -29,6 +30,9 @@ parameters: - name: shell type: string values: ['pwsh', 'bash'] +- name: usePwsh + type: boolean + default: true steps: @@ -38,7 +42,7 @@ steps: displayName: 'Validate pinned versions match deps_versions.json' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $ErrorActionPreference = 'Stop' $depsFile = Join-Path "$(Build.SourcesDirectory)" "sdk_v2/deps_versions.json" @@ -70,7 +74,7 @@ steps: displayName: 'Pre-download NuGet packages' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $ErrorActionPreference = 'Stop' $cacheDir = "$(Build.BinariesDirectory)/nuget_packages" From 5bb9f699328f19e93bab453c79ce95eeaa8c2890 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 11:41:07 -0700 Subject: [PATCH 05/36] pwsh pwsh --- .pipelines/v2/templates/steps-build-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 51aa4dab6..69fe13079 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -66,6 +66,7 @@ steps: winmlVersion: ${{ parameters.winmlVersion }} includeWinml: true shell: pwsh + usePwsh: ${{ parameters.usePwsh }} # Bake the pipeline-computed version into the binary so FoundryLocalGetVersionString() # matches the .nupkg version (e.g. 0.1.0-dev.202605111234) instead of the cmake default. From e88f761596cb2b3150c1d76efc22d24caca467dc Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 13:45:01 -0700 Subject: [PATCH 06/36] install azcli --- .../templates/fetch-test-data-from-blob.yml | 41 ++++++++++++++++++- .pipelines/v2/templates/stages-cs.yml | 6 +++ .pipelines/v2/templates/stages-js.yml | 3 ++ .../v2/templates/steps-build-windows.yml | 2 + 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index 2ca3682b0..f5f139d40 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -5,13 +5,52 @@ parameters: - name: destinationPath type: string default: '$(Build.SourcesDirectory)/test-data-shared' +- name: scriptType + type: string + default: pscore + values: ['pscore', 'ps'] +- name: installAzCli + type: boolean + default: false steps: +- ${{ if eq(parameters.installAzCli, true) }}: + - task: PowerShell@2 + displayName: 'Ensure Azure CLI is installed (Windows)' + condition: eq(variables['Agent.OS'], 'Windows_NT') + inputs: + targetType: inline + pwsh: false + script: | + $ErrorActionPreference = 'Stop' + + if (Get-Command az -ErrorAction SilentlyContinue) { + az --version | Select-Object -First 1 | Write-Host + Write-Host 'Azure CLI already installed.' + exit 0 + } + + if (Get-Command choco -ErrorAction SilentlyContinue) { + Write-Host 'Azure CLI not found. Installing via Chocolatey...' + choco install azure-cli -y --no-progress + } elseif (Get-Command winget -ErrorAction SilentlyContinue) { + Write-Host 'Azure CLI not found. Installing via winget...' + winget install --id Microsoft.AzureCLI -e --accept-source-agreements --accept-package-agreements --silent + } else { + throw 'Azure CLI is not installed and neither choco nor winget is available to install it.' + } + + $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') + if (-not (Get-Command az -ErrorAction SilentlyContinue)) { + throw 'Azure CLI install completed but az is still not on PATH.' + } + az --version | Select-Object -First 1 | Write-Host + - task: AzureCLI@2 displayName: 'Fetch test data from blob' inputs: azureSubscription: 'ortcibuild_readonly_mi2-ONNX Runtime-AIFoundryLocal' - scriptType: pscore + scriptType: ${{ parameters.scriptType }} scriptLocation: inlineScript inlineScript: | $ErrorActionPreference = 'Stop' diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index 84e016573..255eebbb7 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -68,6 +68,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' @@ -95,6 +98,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' diff --git a/.pipelines/v2/templates/stages-js.yml b/.pipelines/v2/templates/stages-js.yml index 2d68a3b74..049e93647 100644 --- a/.pipelines/v2/templates/stages-js.yml +++ b/.pipelines/v2/templates/stages-js.yml @@ -223,6 +223,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-js.yml parameters: rid: 'win-arm64' diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 69fe13079..6b400ee01 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -86,6 +86,8 @@ steps: - template: ../../templates/fetch-test-data-from-blob.yml@self parameters: destinationPath: '$(Agent.BuildDirectory)/test-data-shared' + scriptType: ps + installAzCli: true - ${{ if eq(parameters.arch, 'x64') }}: - script: >- From 77b794b347068a8322aa8cb214cd9d68a6c1e6fc Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 16 Jul 2026 15:52:03 -0700 Subject: [PATCH 07/36] winget --- .../templates/fetch-test-data-from-blob.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index f5f139d40..c4fa369a4 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -30,19 +30,21 @@ steps: exit 0 } - if (Get-Command choco -ErrorAction SilentlyContinue) { - Write-Host 'Azure CLI not found. Installing via Chocolatey...' - choco install azure-cli -y --no-progress - } elseif (Get-Command winget -ErrorAction SilentlyContinue) { + if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { + throw 'Azure CLI is not installed and winget is not available on this Windows agent.' + } + + try { Write-Host 'Azure CLI not found. Installing via winget...' winget install --id Microsoft.AzureCLI -e --accept-source-agreements --accept-package-agreements --silent - } else { - throw 'Azure CLI is not installed and neither choco nor winget is available to install it.' + } + catch { + throw "winget install failed: $($_.Exception.Message)" } $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') if (-not (Get-Command az -ErrorAction SilentlyContinue)) { - throw 'Azure CLI install completed but az is still not on PATH.' + throw 'Azure CLI install attempted but az is still not on PATH.' } az --version | Select-Object -First 1 | Write-Host From fda0d31af8390c4695474755bb9b6f837853e6c7 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 17 Jul 2026 16:03:43 -0700 Subject: [PATCH 08/36] installer --- .../templates/fetch-test-data-from-blob.yml | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index c4fa369a4..ef4a36785 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -30,21 +30,26 @@ steps: exit 0 } - if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { - throw 'Azure CLI is not installed and winget is not available on this Windows agent.' - } - try { - Write-Host 'Azure CLI not found. Installing via winget...' - winget install --id Microsoft.AzureCLI -e --accept-source-agreements --accept-package-agreements --silent + $installerPath = Join-Path $env:TEMP 'azure-cli-installer.msi' + $installerUrl = 'https://aka.ms/installazurecliwindows' + + Write-Host "Downloading Azure CLI installer from $installerUrl" + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing + + Write-Host 'Installing Azure CLI via MSI...' + $process = Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `"$installerPath`" /qn /norestart" -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Azure CLI MSI install failed with exit code $($process.ExitCode)." + } } catch { - throw "winget install failed: $($_.Exception.Message)" + throw "Azure CLI install failed: $($_.Exception.Message)" } $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') if (-not (Get-Command az -ErrorAction SilentlyContinue)) { - throw 'Azure CLI install attempted but az is still not on PATH.' + throw 'Azure CLI install was attempted but az is still not on PATH.' } az --version | Select-Object -First 1 | Write-Host From 183576b3bc6d242ea8ea44c89d0f3d4ba8109a21 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 08:59:11 -0700 Subject: [PATCH 09/36] nit --- .pipelines/templates/fetch-test-data-from-blob.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index ef4a36785..3e5898aba 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -51,7 +51,7 @@ steps: if (-not (Get-Command az -ErrorAction SilentlyContinue)) { throw 'Azure CLI install was attempted but az is still not on PATH.' } - az --version | Select-Object -First 1 | Write-Host + az version | Write-Host - task: AzureCLI@2 displayName: 'Fetch test data from blob' From ad8ac3651fe8c3cf5edfac0a18be00fb3e278c70 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 12:08:48 -0700 Subject: [PATCH 10/36] azpath --- .pipelines/templates/fetch-test-data-from-blob.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index 3e5898aba..34dbf107b 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -25,6 +25,8 @@ steps: $ErrorActionPreference = 'Stop' if (Get-Command az -ErrorAction SilentlyContinue) { + $azDir = Split-Path -Path (Get-Command az).Source -Parent + Write-Host "##vso[task.prependpath]$azDir" az --version | Select-Object -First 1 | Write-Host Write-Host 'Azure CLI already installed.' exit 0 @@ -48,9 +50,11 @@ steps: } $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') - if (-not (Get-Command az -ErrorAction SilentlyContinue)) { + $azCommand = Get-Command az -ErrorAction SilentlyContinue + if (-not $azCommand) { throw 'Azure CLI install was attempted but az is still not on PATH.' } + Write-Host "##vso[task.prependpath]$(Split-Path -Path $azCommand.Source -Parent)" az version | Write-Host - task: AzureCLI@2 From 88dde3982e00c1caf1055af5fe2fdcceac959c42 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 12:41:15 -0700 Subject: [PATCH 11/36] azcopy --- .../templates/fetch-test-data-from-blob.yml | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index 34dbf107b..a841e7c8b 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -71,7 +71,17 @@ steps: $container = 'models' $prefix = 'foundrylocal/models' - if (-not (Get-Command azcopy -ErrorAction SilentlyContinue)) { + $azcopyAvailable = $false + try { + azcopy --version | Write-Host + if ($LASTEXITCODE -eq 0) { + $azcopyAvailable = $true + } + } + catch { + } + + if (-not $azcopyAvailable) { if ($IsMacOS) { Write-Host 'azcopy not found on macOS agent. Installing via Homebrew...' if (-not (Get-Command brew -ErrorAction SilentlyContinue)) { @@ -80,6 +90,20 @@ steps: brew update --quiet brew install --quiet azcopy + } elseif ($env:AGENT_OS -eq 'Windows_NT') { + Write-Host 'azcopy not found on Windows agent. Installing from official zip...' + $zipPath = Join-Path $env:TEMP 'azcopy_windows.zip' + $extractRoot = Join-Path $env:TEMP 'azcopy' + Invoke-WebRequest -Uri 'https://aka.ms/downloadazcopy-v10-windows' -OutFile $zipPath -UseBasicParsing + if (Test-Path $extractRoot) { + Remove-Item -Path $extractRoot -Recurse -Force + } + Expand-Archive -Path $zipPath -DestinationPath $extractRoot -Force + $azcopyExe = Get-ChildItem -Path $extractRoot -Filter 'azcopy.exe' -Recurse | Select-Object -First 1 + if (-not $azcopyExe) { + throw 'azcopy install completed but azcopy.exe was not found.' + } + $env:PATH = "$($azcopyExe.Directory.FullName);$env:PATH" } else { throw 'azcopy is not installed on this agent.' } From 06aa1327138c2e36acd4bd3c780775239044c8d4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 14:29:38 -0700 Subject: [PATCH 12/36] cmake --- .../templates/fetch-test-data-from-blob.yml | 2 +- .../v2/templates/steps-build-windows.yml | 57 +++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index a841e7c8b..2e45017b9 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -90,7 +90,7 @@ steps: brew update --quiet brew install --quiet azcopy - } elseif ($env:AGENT_OS -eq 'Windows_NT') { + } elseif ($env:AGENT_OS -eq 'Windows_NT' -and $env:AGENT_OSARCHITECTURE -eq 'ARM64') { Write-Host 'azcopy not found on Windows agent. Installing from official zip...' $zipPath = Join-Path $env:TEMP 'azcopy_windows.zip' $extractRoot = Join-Path $env:TEMP 'azcopy' diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 6b400ee01..b14877f02 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -68,6 +68,35 @@ steps: shell: pwsh usePwsh: ${{ parameters.usePwsh }} +- ${{ if eq(parameters.arch, 'arm64') }}: + - task: PowerShell@2 + displayName: 'Locate CMake for ARM64 builds' + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found at $vswhere" } + + $vsInstall = & $vswhere -latest -property installationPath + if (-not $vsInstall) { throw 'Could not locate a Visual Studio installation.' } + + $cmakeDir = Join-Path $vsInstall 'Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin' + $cmakePath = Join-Path $cmakeDir 'cmake.exe' + $ctestPath = Join-Path $cmakeDir 'ctest.exe' + + if (-not (Test-Path $cmakePath)) { + throw "cmake.exe not found at $cmakePath" + } + if (-not (Test-Path $ctestPath)) { + throw "ctest.exe not found at $ctestPath" + } + + Write-Host "cmake.exe: $cmakePath" + Write-Host "ctest.exe: $ctestPath" + Write-Host "##vso[task.setvariable variable=cmakePath]$cmakePath" + Write-Host "##vso[task.setvariable variable=ctestPath]$ctestPath" + # Bake the pipeline-computed version into the binary so FoundryLocalGetVersionString() # matches the .nupkg version (e.g. 0.1.0-dev.202605111234) instead of the cmake default. - task: PowerShell@2 @@ -110,6 +139,8 @@ steps: --config ${{ parameters.buildConfig }} --cmake_generator "Visual Studio 17 2022" --winml_sdk_version ${{ parameters.winmlVersion }} + --cmake_path "$(cmakePath)" + --ctest_path "$(ctestPath)" --cmake_extra_defines $(cmakeFetchDefines) displayName: 'Configure and build (arm64)' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp @@ -118,12 +149,26 @@ steps: PKG_CONFIG: $(Build.BinariesDirectory)\tools\pkg-config.bat - ${{ if eq(parameters.runTests, true) }}: - - script: python build.py --test --config ${{ parameters.buildConfig }} - displayName: 'Run tests' - workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp - env: - VCPKG_ROOT: $(Build.BinariesDirectory)\vcpkg - FOUNDRY_TEST_DATA_DIR: $(Agent.BuildDirectory)\test-data-shared + - ${{ if eq(parameters.arch, 'x64') }}: + - script: python build.py --test --config ${{ parameters.buildConfig }} + displayName: 'Run tests' + workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp + env: + VCPKG_ROOT: $(Build.BinariesDirectory)\vcpkg + FOUNDRY_TEST_DATA_DIR: $(Agent.BuildDirectory)\test-data-shared + + - ${{ if eq(parameters.arch, 'arm64') }}: + - script: >- + python build.py + --test + --config ${{ parameters.buildConfig }} + --cmake_path "$(cmakePath)" + --ctest_path "$(ctestPath)" + displayName: 'Run tests' + workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp + env: + VCPKG_ROOT: $(Build.BinariesDirectory)\vcpkg + FOUNDRY_TEST_DATA_DIR: $(Agent.BuildDirectory)\test-data-shared # Stage the redistributable native artifacts. vcpkg statically links # ORT/GenAI/azure-*/spdlog/fmt/libcurl/libssl/zlib/brotli* into foundry_local.dll From c1e6d73b12bee36eb7a71656e6591c7dd46112b6 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 15:22:56 -0700 Subject: [PATCH 13/36] cmake --- .../v2/templates/steps-build-windows.yml | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index b14877f02..5e7e66fdf 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -75,21 +75,51 @@ steps: targetType: inline pwsh: ${{ parameters.usePwsh }} script: | - $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" - if (-not (Test-Path $vswhere)) { throw "vswhere.exe not found at $vswhere" } + $cmakePath = $null + $ctestPath = $null - $vsInstall = & $vswhere -latest -property installationPath - if (-not $vsInstall) { throw 'Could not locate a Visual Studio installation.' } + # Prefer already-resolved commands if the agent has CMake on PATH. + $cmakeCmd = Get-Command cmake -ErrorAction SilentlyContinue + $ctestCmd = Get-Command ctest -ErrorAction SilentlyContinue + if ($cmakeCmd -and $ctestCmd) { + $cmakePath = $cmakeCmd.Source + $ctestPath = $ctestCmd.Source + } + + # Fall back to common standalone CMake locations. + if (-not $cmakePath -or -not $ctestPath) { + $programFilesX86 = ${env:ProgramFiles(x86)} + $candidates = @( + @{ CMake = (Join-Path $env:ProgramFiles 'CMake\\bin\\cmake.exe'); CTest = (Join-Path $env:ProgramFiles 'CMake\\bin\\ctest.exe') }, + @{ CMake = (Join-Path $programFilesX86 'CMake\\bin\\cmake.exe'); CTest = (Join-Path $programFilesX86 'CMake\\bin\\ctest.exe') } + ) - $cmakeDir = Join-Path $vsInstall 'Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin' - $cmakePath = Join-Path $cmakeDir 'cmake.exe' - $ctestPath = Join-Path $cmakeDir 'ctest.exe' + foreach ($candidate in $candidates) { + if ((-not $cmakePath) -and (Test-Path $candidate.CMake)) { $cmakePath = $candidate.CMake } + if ((-not $ctestPath) -and (Test-Path $candidate.CTest)) { $ctestPath = $candidate.CTest } + } + } + + # Fall back to VS-bundled CMake if vswhere is available. + if (-not $cmakePath -or -not $ctestPath) { + $vswhere = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" + if (Test-Path $vswhere) { + $vsInstall = & $vswhere -latest -property installationPath + if ($vsInstall) { + $cmakeDir = Join-Path $vsInstall 'Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\CMake\\bin' + $vsCmake = Join-Path $cmakeDir 'cmake.exe' + $vsCtest = Join-Path $cmakeDir 'ctest.exe' + if ((-not $cmakePath) -and (Test-Path $vsCmake)) { $cmakePath = $vsCmake } + if ((-not $ctestPath) -and (Test-Path $vsCtest)) { $ctestPath = $vsCtest } + } + } + } - if (-not (Test-Path $cmakePath)) { - throw "cmake.exe not found at $cmakePath" + if (-not $cmakePath) { + throw 'Unable to locate cmake.exe. Ensure CMake is installed or available on PATH.' } - if (-not (Test-Path $ctestPath)) { - throw "ctest.exe not found at $ctestPath" + if (-not $ctestPath) { + throw 'Unable to locate ctest.exe. Ensure CMake is installed or available on PATH.' } Write-Host "cmake.exe: $cmakePath" From 7cc2a7349b2ea8ad4c8cdcf42a87d1917c48661b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 15:44:25 -0700 Subject: [PATCH 14/36] cmake --- .../v2/templates/steps-build-windows.yml | 57 ++++++------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 5e7e66fdf..02598797a 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -70,56 +70,35 @@ steps: - ${{ if eq(parameters.arch, 'arm64') }}: - task: PowerShell@2 - displayName: 'Locate CMake for ARM64 builds' + displayName: 'Install and locate CMake for ARM64 builds' inputs: targetType: inline pwsh: ${{ parameters.usePwsh }} script: | - $cmakePath = $null - $ctestPath = $null + # Main strategy for ARM64 agents: provision CMake from PyPI in the + # same Python environment used by the build step. + python -m pip install --upgrade pip + if ($LASTEXITCODE -ne 0) { throw 'pip upgrade failed while provisioning CMake.' } + + python -m pip install "cmake>=3.29,<4" + if ($LASTEXITCODE -ne 0) { throw 'pip install cmake failed.' } + + $scriptsDir = (& python -c "import sysconfig; print(sysconfig.get_path('scripts'))").Trim() + if ($scriptsDir) { + Write-Host "##vso[task.prependpath]$scriptsDir" + $env:PATH = "$scriptsDir;$env:PATH" + } - # Prefer already-resolved commands if the agent has CMake on PATH. $cmakeCmd = Get-Command cmake -ErrorAction SilentlyContinue $ctestCmd = Get-Command ctest -ErrorAction SilentlyContinue - if ($cmakeCmd -and $ctestCmd) { - $cmakePath = $cmakeCmd.Source - $ctestPath = $ctestCmd.Source - } - - # Fall back to common standalone CMake locations. - if (-not $cmakePath -or -not $ctestPath) { - $programFilesX86 = ${env:ProgramFiles(x86)} - $candidates = @( - @{ CMake = (Join-Path $env:ProgramFiles 'CMake\\bin\\cmake.exe'); CTest = (Join-Path $env:ProgramFiles 'CMake\\bin\\ctest.exe') }, - @{ CMake = (Join-Path $programFilesX86 'CMake\\bin\\cmake.exe'); CTest = (Join-Path $programFilesX86 'CMake\\bin\\ctest.exe') } - ) - - foreach ($candidate in $candidates) { - if ((-not $cmakePath) -and (Test-Path $candidate.CMake)) { $cmakePath = $candidate.CMake } - if ((-not $ctestPath) -and (Test-Path $candidate.CTest)) { $ctestPath = $candidate.CTest } - } - } - - # Fall back to VS-bundled CMake if vswhere is available. - if (-not $cmakePath -or -not $ctestPath) { - $vswhere = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" - if (Test-Path $vswhere) { - $vsInstall = & $vswhere -latest -property installationPath - if ($vsInstall) { - $cmakeDir = Join-Path $vsInstall 'Common7\\IDE\\CommonExtensions\\Microsoft\\CMake\\CMake\\bin' - $vsCmake = Join-Path $cmakeDir 'cmake.exe' - $vsCtest = Join-Path $cmakeDir 'ctest.exe' - if ((-not $cmakePath) -and (Test-Path $vsCmake)) { $cmakePath = $vsCmake } - if ((-not $ctestPath) -and (Test-Path $vsCtest)) { $ctestPath = $vsCtest } - } - } - } + $cmakePath = if ($cmakeCmd) { $cmakeCmd.Source } else { $null } + $ctestPath = if ($ctestCmd) { $ctestCmd.Source } else { $null } if (-not $cmakePath) { - throw 'Unable to locate cmake.exe. Ensure CMake is installed or available on PATH.' + throw 'Unable to locate cmake.exe after pip install.' } if (-not $ctestPath) { - throw 'Unable to locate ctest.exe. Ensure CMake is installed or available on PATH.' + throw 'Unable to locate ctest.exe after pip install.' } Write-Host "cmake.exe: $cmakePath" From 1f97a382e5f6e83f57db13114f3b4b1b34206043 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Tue, 21 Jul 2026 19:06:39 -0700 Subject: [PATCH 15/36] ninja --- .pipelines/v2/templates/steps-build-windows.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 02598797a..c6f1785d5 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -80,6 +80,9 @@ steps: python -m pip install --upgrade pip if ($LASTEXITCODE -ne 0) { throw 'pip upgrade failed while provisioning CMake.' } + python -m pip install "ninja>=1.11" + if ($LASTEXITCODE -ne 0) { throw 'pip install ninja failed.' } + python -m pip install "cmake>=3.29,<4" if ($LASTEXITCODE -ne 0) { throw 'pip install cmake failed.' } @@ -106,6 +109,7 @@ steps: Write-Host "##vso[task.setvariable variable=cmakePath]$cmakePath" Write-Host "##vso[task.setvariable variable=ctestPath]$ctestPath" + # Bake the pipeline-computed version into the binary so FoundryLocalGetVersionString() # matches the .nupkg version (e.g. 0.1.0-dev.202605111234) instead of the cmake default. - task: PowerShell@2 @@ -146,7 +150,7 @@ steps: python build.py --configure --build --arm64 --config ${{ parameters.buildConfig }} - --cmake_generator "Visual Studio 17 2022" + --cmake_generator "Ninja" --winml_sdk_version ${{ parameters.winmlVersion }} --cmake_path "$(cmakePath)" --ctest_path "$(ctestPath)" From 9fa1cf474259925d7691861ed49b6e1fd33de076 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 12:19:50 -0700 Subject: [PATCH 16/36] ninja cmd --- .../v2/templates/steps-build-windows.yml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index c6f1785d5..19270a0dd 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -94,8 +94,10 @@ steps: $cmakeCmd = Get-Command cmake -ErrorAction SilentlyContinue $ctestCmd = Get-Command ctest -ErrorAction SilentlyContinue + $ninjaCmd = Get-Command ninja -ErrorAction SilentlyContinue $cmakePath = if ($cmakeCmd) { $cmakeCmd.Source } else { $null } $ctestPath = if ($ctestCmd) { $ctestCmd.Source } else { $null } + $ninjaPath = if ($ninjaCmd) { $ninjaCmd.Source } else { $null } if (-not $cmakePath) { throw 'Unable to locate cmake.exe after pip install.' @@ -103,11 +105,47 @@ steps: if (-not $ctestPath) { throw 'Unable to locate ctest.exe after pip install.' } + if (-not $ninjaPath) { + throw 'Unable to locate ninja.exe after pip install.' + } Write-Host "cmake.exe: $cmakePath" Write-Host "ctest.exe: $ctestPath" + Write-Host "ninja.exe: $ninjaPath" Write-Host "##vso[task.setvariable variable=cmakePath]$cmakePath" Write-Host "##vso[task.setvariable variable=ctestPath]$ctestPath" + Write-Host "##vso[task.setvariable variable=ninjaPath]$ninjaPath" + + - task: PowerShell@2 + displayName: 'Locate vcvarsall for ARM64 build toolchain' + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $programFilesX86 = ${env:ProgramFiles(x86)} + $roots = @($env:ProgramFiles, $programFilesX86) | Where-Object { $_ -and (Test-Path $_) } + + $vcvars = $null + foreach ($root in $roots) { + $base = Join-Path $root 'Microsoft Visual Studio' + if (-not (Test-Path $base)) { continue } + + $found = Get-ChildItem -Path $base -Filter vcvarsall.bat -Recurse -ErrorAction SilentlyContinue | + Where-Object { $_.FullName -like '*\\VC\\Auxiliary\\Build\\vcvarsall.bat' } | + Select-Object -First 1 + + if ($found) { + $vcvars = $found.FullName + break + } + } + + if (-not $vcvars) { + throw 'Unable to locate vcvarsall.bat. Install Visual Studio Build Tools with C++ workloads on this ARM64 agent.' + } + + Write-Host "vcvarsall.bat: $vcvars" + Write-Host "##vso[task.setvariable variable=vcvarsAllPath]$vcvars" # Bake the pipeline-computed version into the binary so FoundryLocalGetVersionString() @@ -147,6 +185,7 @@ steps: - ${{ if eq(parameters.arch, 'arm64') }}: - script: >- + call "$(vcvarsAllPath)" arm64 && python build.py --configure --build --arm64 --config ${{ parameters.buildConfig }} @@ -154,6 +193,7 @@ steps: --winml_sdk_version ${{ parameters.winmlVersion }} --cmake_path "$(cmakePath)" --ctest_path "$(ctestPath)" + --cmake_extra_defines "CMAKE_MAKE_PROGRAM=$(ninjaPath)" --cmake_extra_defines $(cmakeFetchDefines) displayName: 'Configure and build (arm64)' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp From 7ff72fa2c04d7656db66caa4f602f11a998b7e01 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 12:39:53 -0700 Subject: [PATCH 17/36] type --- .pipelines/v2/templates/steps-build-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 19270a0dd..18b4b67a6 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -185,7 +185,7 @@ steps: - ${{ if eq(parameters.arch, 'arm64') }}: - script: >- - call "$(vcvarsAllPath)" arm64 && + call "$(vcvarsAllPath)" arm64 && python build.py --configure --build --arm64 --config ${{ parameters.buildConfig }} @@ -193,7 +193,7 @@ steps: --winml_sdk_version ${{ parameters.winmlVersion }} --cmake_path "$(cmakePath)" --ctest_path "$(ctestPath)" - --cmake_extra_defines "CMAKE_MAKE_PROGRAM=$(ninjaPath)" + --cmake_extra_defines "CMAKE_MAKE_PROGRAM=$(ninjaPath)" --cmake_extra_defines $(cmakeFetchDefines) displayName: 'Configure and build (arm64)' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp From b8611982513edf386a7a6a2985f81a2eb9c13fd1 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 13:01:18 -0700 Subject: [PATCH 18/36] pls --- .../v2/templates/steps-build-windows.yml | 98 +++++++------------ 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 18b4b67a6..9154bf177 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -70,82 +70,59 @@ steps: - ${{ if eq(parameters.arch, 'arm64') }}: - task: PowerShell@2 - displayName: 'Install and locate CMake for ARM64 builds' + displayName: 'Ensure Visual Studio Build Tools and CMake for ARM64' inputs: targetType: inline pwsh: ${{ parameters.usePwsh }} script: | - # Main strategy for ARM64 agents: provision CMake from PyPI in the - # same Python environment used by the build step. - python -m pip install --upgrade pip - if ($LASTEXITCODE -ne 0) { throw 'pip upgrade failed while provisioning CMake.' } + $installRoot = 'C:\BuildTools' + $vcvars = Join-Path $installRoot 'VC\Auxiliary\Build\vcvarsall.bat' + $cmakeDir = Join-Path $installRoot 'Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin' + $cmakePath = Join-Path $cmakeDir 'cmake.exe' + $ctestPath = Join-Path $cmakeDir 'ctest.exe' - python -m pip install "ninja>=1.11" - if ($LASTEXITCODE -ne 0) { throw 'pip install ninja failed.' } + if (-not (Test-Path $vcvars) -or -not (Test-Path $cmakePath) -or -not (Test-Path $ctestPath)) { + Write-Host 'Visual Studio Build Tools not fully present. Installing...' + $bootstrapper = Join-Path $env:TEMP 'vs_BuildTools.exe' + Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile $bootstrapper -UseBasicParsing - python -m pip install "cmake>=3.29,<4" - if ($LASTEXITCODE -ne 0) { throw 'pip install cmake failed.' } + $arguments = @( + '--quiet', + '--wait', + '--norestart', + '--nocache', + '--installPath', $installRoot, + '--add', 'Microsoft.VisualStudio.Workload.VCTools', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.ARM64', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + '--add', 'Microsoft.VisualStudio.Component.VC.CMake.Project', + '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22621', + '--includeRecommended' + ) - $scriptsDir = (& python -c "import sysconfig; print(sysconfig.get_path('scripts'))").Trim() - if ($scriptsDir) { - Write-Host "##vso[task.prependpath]$scriptsDir" - $env:PATH = "$scriptsDir;$env:PATH" + $process = Start-Process -FilePath $bootstrapper -ArgumentList $arguments -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Visual Studio Build Tools install failed with exit code $($process.ExitCode)." + } } - $cmakeCmd = Get-Command cmake -ErrorAction SilentlyContinue - $ctestCmd = Get-Command ctest -ErrorAction SilentlyContinue - $ninjaCmd = Get-Command ninja -ErrorAction SilentlyContinue - $cmakePath = if ($cmakeCmd) { $cmakeCmd.Source } else { $null } - $ctestPath = if ($ctestCmd) { $ctestCmd.Source } else { $null } - $ninjaPath = if ($ninjaCmd) { $ninjaCmd.Source } else { $null } - - if (-not $cmakePath) { - throw 'Unable to locate cmake.exe after pip install.' + if (-not (Test-Path $vcvars)) { + throw "vcvarsall.bat was not found at $vcvars after Build Tools install." } - if (-not $ctestPath) { - throw 'Unable to locate ctest.exe after pip install.' + if (-not (Test-Path $cmakePath)) { + throw "cmake.exe was not found at $cmakePath after Build Tools install." } - if (-not $ninjaPath) { - throw 'Unable to locate ninja.exe after pip install.' + if (-not (Test-Path $ctestPath)) { + throw "ctest.exe was not found at $ctestPath after Build Tools install." } + Write-Host "##vso[task.prependpath]$cmakeDir" + Write-Host "vcvarsall.bat: $vcvars" Write-Host "cmake.exe: $cmakePath" Write-Host "ctest.exe: $ctestPath" - Write-Host "ninja.exe: $ninjaPath" + Write-Host "##vso[task.setvariable variable=vcvarsAllPath]$vcvars" Write-Host "##vso[task.setvariable variable=cmakePath]$cmakePath" Write-Host "##vso[task.setvariable variable=ctestPath]$ctestPath" - Write-Host "##vso[task.setvariable variable=ninjaPath]$ninjaPath" - - - task: PowerShell@2 - displayName: 'Locate vcvarsall for ARM64 build toolchain' - inputs: - targetType: inline - pwsh: ${{ parameters.usePwsh }} - script: | - $programFilesX86 = ${env:ProgramFiles(x86)} - $roots = @($env:ProgramFiles, $programFilesX86) | Where-Object { $_ -and (Test-Path $_) } - - $vcvars = $null - foreach ($root in $roots) { - $base = Join-Path $root 'Microsoft Visual Studio' - if (-not (Test-Path $base)) { continue } - - $found = Get-ChildItem -Path $base -Filter vcvarsall.bat -Recurse -ErrorAction SilentlyContinue | - Where-Object { $_.FullName -like '*\\VC\\Auxiliary\\Build\\vcvarsall.bat' } | - Select-Object -First 1 - - if ($found) { - $vcvars = $found.FullName - break - } - } - - if (-not $vcvars) { - throw 'Unable to locate vcvarsall.bat. Install Visual Studio Build Tools with C++ workloads on this ARM64 agent.' - } - - Write-Host "vcvarsall.bat: $vcvars" - Write-Host "##vso[task.setvariable variable=vcvarsAllPath]$vcvars" # Bake the pipeline-computed version into the binary so FoundryLocalGetVersionString() @@ -189,11 +166,10 @@ steps: python build.py --configure --build --arm64 --config ${{ parameters.buildConfig }} - --cmake_generator "Ninja" + --cmake_generator "Visual Studio 17 2022" --winml_sdk_version ${{ parameters.winmlVersion }} --cmake_path "$(cmakePath)" --ctest_path "$(ctestPath)" - --cmake_extra_defines "CMAKE_MAKE_PROGRAM=$(ninjaPath)" --cmake_extra_defines $(cmakeFetchDefines) displayName: 'Configure and build (arm64)' workingDirectory: $(Build.SourcesDirectory)/sdk_v2/cpp From de9874a45d9ac9a749c440861a3fe66bea55cb1f Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 13:49:51 -0700 Subject: [PATCH 19/36] restore --- sdk_v2/js/package-lock.json | 46 ++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/sdk_v2/js/package-lock.json b/sdk_v2/js/package-lock.json index 4bf6916ce..0579c9114 100644 --- a/sdk_v2/js/package-lock.json +++ b/sdk_v2/js/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.0-dev.0", "hasInstallScript": true, "dependencies": { - "adm-zip": "^0.5.16", + "adm-zip": "^0.6.0", "node-addon-api": "^8.2.2" }, "devDependencies": { @@ -445,6 +445,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -462,6 +465,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -479,6 +485,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -496,6 +505,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -513,6 +525,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -530,6 +545,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -824,12 +842,12 @@ } }, "node_modules/adm-zip": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", - "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", + "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", "license": "MIT", "engines": { - "node": ">=12.0" + "node": ">=14.0" } }, "node_modules/assertion-error": { @@ -1191,6 +1209,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1212,6 +1233,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1233,6 +1257,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1254,6 +1281,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1608,9 +1638,9 @@ } }, "node_modules/tar": { - "version": "7.5.16", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", - "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", + "version": "7.5.20", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.20.tgz", + "integrity": "sha512-9FcyK4PA6+WbzlTM9WhQm6vB5W7cP7dUiPsv1g7YDwEQnQ1CGpK3MGlKk/ITVWMk05kHZuBhmVhiv8LZoy/PFQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { From ddb74d21af9a1056fac99ab9f18a7f8a85e14511 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 15:00:51 -0700 Subject: [PATCH 20/36] pwsh --- .pipelines/v2/templates/steps-build-js.yml | 8 +++---- .../v2/templates/steps-build-python.yml | 22 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.pipelines/v2/templates/steps-build-js.yml b/.pipelines/v2/templates/steps-build-js.yml index d8136dbad..909f9e062 100644 --- a/.pipelines/v2/templates/steps-build-js.yml +++ b/.pipelines/v2/templates/steps-build-js.yml @@ -55,13 +55,13 @@ steps: # (prebuilds/-/) so downstream consumers find the addon under # the directory matching `${process.platform}-${process.arch}` at runtime. - ${{ if eq(parameters.rid, 'win-x64') }}: - - pwsh: | + - powershell: | Write-Host "##vso[task.setvariable variable=prebuildDir]win32-x64" Write-Host "##vso[task.setvariable variable=nativeLib]foundry_local.dll" displayName: 'Set prebuild directory (win32-x64)' - ${{ if eq(parameters.rid, 'win-arm64') }}: - - pwsh: | + - powershell: | Write-Host "##vso[task.setvariable variable=prebuildDir]win32-arm64" Write-Host "##vso[task.setvariable variable=nativeLib]foundry_local.dll" displayName: 'Set prebuild directory (win32-arm64)' @@ -94,7 +94,7 @@ steps: # we point INCLUDE_DIR at that artifact root, and the public include path # is added separately in binding.gyp via `../cpp/include`. - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - - pwsh: | + - powershell: | $arch = '${{ parameters.targetArch }}' $args = if ($arch -eq 'native') { 'rebuild' } else { "rebuild --arch=$arch" } Write-Host "node-gyp $args" @@ -128,7 +128,7 @@ steps: # into sdk_v2/js/prebuilds/-/; we copy from there into the artifact # dir alongside the shared library. - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - - pwsh: | + - powershell: | $dst = "${{ parameters.outputDir }}/prebuilds/$(prebuildDir)" if (Test-Path $dst) { Remove-Item -Recurse -Force $dst } New-Item -ItemType Directory -Force -Path $dst | Out-Null diff --git a/.pipelines/v2/templates/steps-build-python.yml b/.pipelines/v2/templates/steps-build-python.yml index 4d471e91c..623b751dc 100644 --- a/.pipelines/v2/templates/steps-build-python.yml +++ b/.pipelines/v2/templates/steps-build-python.yml @@ -45,7 +45,7 @@ steps: displayName: 'Set package version from pyVersion.txt' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | $versionFile = "$(Pipeline.Workspace)/version-info/pyVersion.txt" if (-not (Test-Path $versionFile)) { throw "Missing $versionFile" } @@ -57,7 +57,7 @@ steps: displayName: 'Stamp version into pyproject.toml' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | $pyproject = "$(Build.SourcesDirectory)/sdk_v2/python/pyproject.toml" $content = Get-Content $pyproject -Raw @@ -78,7 +78,7 @@ steps: displayName: 'List downloaded native artifact' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | Write-Host "Contents of ${{ parameters.nativeArtifactDir }}:" Get-ChildItem "${{ parameters.nativeArtifactDir }}" -Recurse -File | @@ -88,7 +88,7 @@ steps: displayName: 'Stage native lib into _native/${{ parameters.rid }}/' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | $dest = "$(Build.SourcesDirectory)/sdk_v2/python/src/foundry_local_sdk/_native/${{ parameters.rid }}" if (Test-Path $dest) { Remove-Item -Recurse -Force $dest } @@ -127,7 +127,7 @@ steps: displayName: 'Clean stale build artifacts' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | $py = "$(Build.SourcesDirectory)/sdk_v2/python" # Remove stale, untagged cffi extension from prior dev compiles. @@ -153,7 +153,7 @@ steps: displayName: 'Install build tooling' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | python -m pip install --upgrade pip python -m pip install --upgrade build setuptools wheel "cffi>=1.16" @@ -164,7 +164,7 @@ steps: displayName: 'Locate MSVC arm64 cross-tools (vswhere)' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | # Resolve vcvarsall.bat once and stash the path in a pipeline variable. The actual # invocation happens inside the build step's child cmd.exe so its env is inherited @@ -196,7 +196,7 @@ steps: condition: and(succeeded(), ne(variables.PYTHON_ARM64_CACHE_HIT, 'true')) inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | # We need arm64 Python's headers + python3.lib to link the cffi extension # for win-arm64 from an x64 host. We do NOT need to *run* the arm64 @@ -240,7 +240,7 @@ steps: displayName: 'Capture arm64 Python paths for cross-link' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | # Path is the same whether we just installed via NuGet above or restored # the directory from cache — both produce $stageRoot/pythonarm64/tools/. @@ -263,7 +263,7 @@ steps: displayName: 'Build wheel' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | $outDir = "${{ parameters.outputDir }}" New-Item -ItemType Directory -Force -Path $outDir | Out-Null @@ -326,7 +326,7 @@ steps: displayName: 'List produced wheel' inputs: targetType: inline - pwsh: true + pwsh: ${{ ne(parameters.rid, 'win-arm64') }} script: | Get-ChildItem "${{ parameters.outputDir }}" -Filter '*.whl' | ForEach-Object { Write-Host ("{0,12} {1}" -f $_.Length, $_.Name) } From 5842c6307b639107cb095ef31707dd18898900db Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Wed, 22 Jul 2026 15:05:09 -0700 Subject: [PATCH 21/36] simpl ify --- .../templates/fetch-test-data-from-blob.yml | 82 +++++++++---------- .pipelines/v2/templates/stages-cs.yml | 6 -- .pipelines/v2/templates/stages-js.yml | 3 - .../v2/templates/steps-build-windows.yml | 2 - 4 files changed, 37 insertions(+), 56 deletions(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index 2e45017b9..bd5741d75 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -5,63 +5,55 @@ parameters: - name: destinationPath type: string default: '$(Build.SourcesDirectory)/test-data-shared' -- name: scriptType - type: string - default: pscore - values: ['pscore', 'ps'] -- name: installAzCli - type: boolean - default: false steps: -- ${{ if eq(parameters.installAzCli, true) }}: - - task: PowerShell@2 - displayName: 'Ensure Azure CLI is installed (Windows)' - condition: eq(variables['Agent.OS'], 'Windows_NT') - inputs: - targetType: inline - pwsh: false - script: | - $ErrorActionPreference = 'Stop' - - if (Get-Command az -ErrorAction SilentlyContinue) { - $azDir = Split-Path -Path (Get-Command az).Source -Parent - Write-Host "##vso[task.prependpath]$azDir" - az --version | Select-Object -First 1 | Write-Host - Write-Host 'Azure CLI already installed.' - exit 0 - } +- task: PowerShell@2 + displayName: 'Ensure Azure CLI is installed (Windows)' + condition: eq(variables['Agent.OS'], 'Windows_NT') + inputs: + targetType: inline + pwsh: false + script: | + $ErrorActionPreference = 'Stop' - try { - $installerPath = Join-Path $env:TEMP 'azure-cli-installer.msi' - $installerUrl = 'https://aka.ms/installazurecliwindows' + if (Get-Command az -ErrorAction SilentlyContinue) { + $azDir = Split-Path -Path (Get-Command az).Source -Parent + Write-Host "##vso[task.prependpath]$azDir" + az --version | Select-Object -First 1 | Write-Host + Write-Host 'Azure CLI already installed.' + exit 0 + } - Write-Host "Downloading Azure CLI installer from $installerUrl" - Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing + try { + $installerPath = Join-Path $env:TEMP 'azure-cli-installer.msi' + $installerUrl = 'https://aka.ms/installazurecliwindows' - Write-Host 'Installing Azure CLI via MSI...' - $process = Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `"$installerPath`" /qn /norestart" -Wait -PassThru - if ($process.ExitCode -ne 0) { - throw "Azure CLI MSI install failed with exit code $($process.ExitCode)." - } - } - catch { - throw "Azure CLI install failed: $($_.Exception.Message)" - } + Write-Host "Downloading Azure CLI installer from $installerUrl" + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing - $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') - $azCommand = Get-Command az -ErrorAction SilentlyContinue - if (-not $azCommand) { - throw 'Azure CLI install was attempted but az is still not on PATH.' + Write-Host 'Installing Azure CLI via MSI...' + $process = Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `"$installerPath`" /qn /norestart" -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Azure CLI MSI install failed with exit code $($process.ExitCode)." } - Write-Host "##vso[task.prependpath]$(Split-Path -Path $azCommand.Source -Parent)" - az version | Write-Host + } + catch { + throw "Azure CLI install failed: $($_.Exception.Message)" + } + + $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') + $azCommand = Get-Command az -ErrorAction SilentlyContinue + if (-not $azCommand) { + throw 'Azure CLI install was attempted but az is still not on PATH.' + } + Write-Host "##vso[task.prependpath]$(Split-Path -Path $azCommand.Source -Parent)" + az version | Write-Host - task: AzureCLI@2 displayName: 'Fetch test data from blob' inputs: azureSubscription: 'ortcibuild_readonly_mi2-ONNX Runtime-AIFoundryLocal' - scriptType: ${{ parameters.scriptType }} + scriptType: $[eq(variables['Agent.OS'], 'Windows_NT') ? 'ps' : 'pscore'] scriptLocation: inlineScript inlineScript: | $ErrorActionPreference = 'Stop' diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index 255eebbb7..84e016573 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -68,9 +68,6 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self - parameters: - scriptType: ps - installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' @@ -98,9 +95,6 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self - parameters: - scriptType: ps - installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' diff --git a/.pipelines/v2/templates/stages-js.yml b/.pipelines/v2/templates/stages-js.yml index 049e93647..2d68a3b74 100644 --- a/.pipelines/v2/templates/stages-js.yml +++ b/.pipelines/v2/templates/stages-js.yml @@ -223,9 +223,6 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self - parameters: - scriptType: ps - installAzCli: true - template: steps-test-js.yml parameters: rid: 'win-arm64' diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 9154bf177..14d09b16f 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -143,8 +143,6 @@ steps: - template: ../../templates/fetch-test-data-from-blob.yml@self parameters: destinationPath: '$(Agent.BuildDirectory)/test-data-shared' - scriptType: ps - installAzCli: true - ${{ if eq(parameters.arch, 'x64') }}: - script: >- From 86cb7b66815d0f7ed459f40f140f879274c63267 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 08:09:24 -0700 Subject: [PATCH 22/36] typo --- .pipelines/templates/fetch-test-data-from-blob.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index bd5741d75..e37ae38b1 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -53,7 +53,7 @@ steps: displayName: 'Fetch test data from blob' inputs: azureSubscription: 'ortcibuild_readonly_mi2-ONNX Runtime-AIFoundryLocal' - scriptType: $[eq(variables['Agent.OS'], 'Windows_NT') ? 'ps' : 'pscore'] + scriptType: "$[eq(variables['Agent.OS'], 'Windows_NT') ? 'ps' : 'pscore']" scriptLocation: inlineScript inlineScript: | $ErrorActionPreference = 'Stop' From 8a523683e708b8e0434066b36e75839576424777 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 09:09:56 -0700 Subject: [PATCH 23/36] Revert "simpl" This reverts commit 5842c6307b639107cb095ef31707dd18898900db. --- .../templates/fetch-test-data-from-blob.yml | 82 ++++++++++--------- .pipelines/v2/templates/stages-cs.yml | 6 ++ .pipelines/v2/templates/stages-js.yml | 3 + .../v2/templates/steps-build-windows.yml | 2 + 4 files changed, 56 insertions(+), 37 deletions(-) diff --git a/.pipelines/templates/fetch-test-data-from-blob.yml b/.pipelines/templates/fetch-test-data-from-blob.yml index e37ae38b1..2e45017b9 100644 --- a/.pipelines/templates/fetch-test-data-from-blob.yml +++ b/.pipelines/templates/fetch-test-data-from-blob.yml @@ -5,55 +5,63 @@ parameters: - name: destinationPath type: string default: '$(Build.SourcesDirectory)/test-data-shared' +- name: scriptType + type: string + default: pscore + values: ['pscore', 'ps'] +- name: installAzCli + type: boolean + default: false steps: -- task: PowerShell@2 - displayName: 'Ensure Azure CLI is installed (Windows)' - condition: eq(variables['Agent.OS'], 'Windows_NT') - inputs: - targetType: inline - pwsh: false - script: | - $ErrorActionPreference = 'Stop' - - if (Get-Command az -ErrorAction SilentlyContinue) { - $azDir = Split-Path -Path (Get-Command az).Source -Parent - Write-Host "##vso[task.prependpath]$azDir" - az --version | Select-Object -First 1 | Write-Host - Write-Host 'Azure CLI already installed.' - exit 0 - } +- ${{ if eq(parameters.installAzCli, true) }}: + - task: PowerShell@2 + displayName: 'Ensure Azure CLI is installed (Windows)' + condition: eq(variables['Agent.OS'], 'Windows_NT') + inputs: + targetType: inline + pwsh: false + script: | + $ErrorActionPreference = 'Stop' + + if (Get-Command az -ErrorAction SilentlyContinue) { + $azDir = Split-Path -Path (Get-Command az).Source -Parent + Write-Host "##vso[task.prependpath]$azDir" + az --version | Select-Object -First 1 | Write-Host + Write-Host 'Azure CLI already installed.' + exit 0 + } - try { - $installerPath = Join-Path $env:TEMP 'azure-cli-installer.msi' - $installerUrl = 'https://aka.ms/installazurecliwindows' + try { + $installerPath = Join-Path $env:TEMP 'azure-cli-installer.msi' + $installerUrl = 'https://aka.ms/installazurecliwindows' - Write-Host "Downloading Azure CLI installer from $installerUrl" - Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing + Write-Host "Downloading Azure CLI installer from $installerUrl" + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -UseBasicParsing - Write-Host 'Installing Azure CLI via MSI...' - $process = Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `"$installerPath`" /qn /norestart" -Wait -PassThru - if ($process.ExitCode -ne 0) { - throw "Azure CLI MSI install failed with exit code $($process.ExitCode)." + Write-Host 'Installing Azure CLI via MSI...' + $process = Start-Process -FilePath 'msiexec.exe' -ArgumentList "/i `"$installerPath`" /qn /norestart" -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Azure CLI MSI install failed with exit code $($process.ExitCode)." + } + } + catch { + throw "Azure CLI install failed: $($_.Exception.Message)" } - } - catch { - throw "Azure CLI install failed: $($_.Exception.Message)" - } - $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') - $azCommand = Get-Command az -ErrorAction SilentlyContinue - if (-not $azCommand) { - throw 'Azure CLI install was attempted but az is still not on PATH.' - } - Write-Host "##vso[task.prependpath]$(Split-Path -Path $azCommand.Source -Parent)" - az version | Write-Host + $env:PATH = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') + $azCommand = Get-Command az -ErrorAction SilentlyContinue + if (-not $azCommand) { + throw 'Azure CLI install was attempted but az is still not on PATH.' + } + Write-Host "##vso[task.prependpath]$(Split-Path -Path $azCommand.Source -Parent)" + az version | Write-Host - task: AzureCLI@2 displayName: 'Fetch test data from blob' inputs: azureSubscription: 'ortcibuild_readonly_mi2-ONNX Runtime-AIFoundryLocal' - scriptType: "$[eq(variables['Agent.OS'], 'Windows_NT') ? 'ps' : 'pscore']" + scriptType: ${{ parameters.scriptType }} scriptLocation: inlineScript inlineScript: | $ErrorActionPreference = 'Stop' diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index 84e016573..255eebbb7 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -68,6 +68,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' @@ -95,6 +98,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-cs.yml parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' diff --git a/.pipelines/v2/templates/stages-js.yml b/.pipelines/v2/templates/stages-js.yml index 2d68a3b74..049e93647 100644 --- a/.pipelines/v2/templates/stages-js.yml +++ b/.pipelines/v2/templates/stages-js.yml @@ -223,6 +223,9 @@ stages: - checkout: self clean: true - template: ../../templates/fetch-test-data-from-blob.yml@self + parameters: + scriptType: ps + installAzCli: true - template: steps-test-js.yml parameters: rid: 'win-arm64' diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 14d09b16f..9154bf177 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -143,6 +143,8 @@ steps: - template: ../../templates/fetch-test-data-from-blob.yml@self parameters: destinationPath: '$(Agent.BuildDirectory)/test-data-shared' + scriptType: ps + installAzCli: true - ${{ if eq(parameters.arch, 'x64') }}: - script: >- From a1c0d3e6332d015ac0f36f70ba95151fa3e47b96 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 09:59:27 -0700 Subject: [PATCH 24/36] Revert "restore" This reverts commit de9874a45d9ac9a749c440861a3fe66bea55cb1f. --- sdk_v2/js/package-lock.json | 46 +++++++------------------------------ 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/sdk_v2/js/package-lock.json b/sdk_v2/js/package-lock.json index 0579c9114..4bf6916ce 100644 --- a/sdk_v2/js/package-lock.json +++ b/sdk_v2/js/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.0-dev.0", "hasInstallScript": true, "dependencies": { - "adm-zip": "^0.6.0", + "adm-zip": "^0.5.16", "node-addon-api": "^8.2.2" }, "devDependencies": { @@ -445,9 +445,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -465,9 +462,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -485,9 +479,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -505,9 +496,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -525,9 +513,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -545,9 +530,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -842,12 +824,12 @@ } }, "node_modules/adm-zip": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.6.0.tgz", - "integrity": "sha512-XleryMhbuksdKtofnWZ9Sk+4CUTbms4Mb/EU32SZwToAyZ5RgVos/ki8n+yr0LWHOGKuakbXTuuYNHLQjhddgg==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", + "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", "license": "MIT", "engines": { - "node": ">=14.0" + "node": ">=12.0" } }, "node_modules/assertion-error": { @@ -1209,9 +1191,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1233,9 +1212,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1257,9 +1233,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1281,9 +1254,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -1638,9 +1608,9 @@ } }, "node_modules/tar": { - "version": "7.5.20", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.20.tgz", - "integrity": "sha512-9FcyK4PA6+WbzlTM9WhQm6vB5W7cP7dUiPsv1g7YDwEQnQ1CGpK3MGlKk/ITVWMk05kHZuBhmVhiv8LZoy/PFQ==", + "version": "7.5.16", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", + "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { From 3a2d82ed8abc0cc8f1af3b070de3e5d73dc88ffc Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 10:33:50 -0700 Subject: [PATCH 25/36] python --- .../v2/templates/steps-build-python.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.pipelines/v2/templates/steps-build-python.yml b/.pipelines/v2/templates/steps-build-python.yml index 623b751dc..ab2a5a7ee 100644 --- a/.pipelines/v2/templates/steps-build-python.yml +++ b/.pipelines/v2/templates/steps-build-python.yml @@ -159,6 +159,47 @@ steps: python -m pip install --upgrade build setuptools wheel "cffi>=1.16" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +- ${{ if eq(parameters.rid, 'win-arm64') }}: + - task: PowerShell@2 + displayName: 'Ensure Visual Studio Build Tools for Windows ARM64 Python build' + inputs: + targetType: inline + pwsh: false + script: | + $installRoot = 'C:\BuildTools' + $vcvars = Join-Path $installRoot 'VC\Auxiliary\Build\vcvarsall.bat' + + if (-not (Test-Path $vcvars)) { + Write-Host 'Visual Studio Build Tools not fully present. Installing...' + $bootstrapper = Join-Path $env:TEMP 'vs_BuildTools.exe' + Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile $bootstrapper -UseBasicParsing + + $arguments = @( + '--quiet', + '--wait', + '--norestart', + '--nocache', + '--installPath', $installRoot, + '--add', 'Microsoft.VisualStudio.Workload.VCTools', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.ARM64', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22621', + '--includeRecommended' + ) + + $process = Start-Process -FilePath $bootstrapper -ArgumentList $arguments -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Visual Studio Build Tools install failed with exit code $($process.ExitCode)." + } + } + + if (-not (Test-Path $vcvars)) { + throw "vcvarsall.bat was not found at $vcvars after Build Tools install." + } + + Write-Host "vcvarsall.bat: $vcvars" + Write-Host "##vso[task.setvariable variable=vcvarsAllPath]$vcvars" + - ${{ if eq(parameters.targetArch, 'arm64') }}: - task: PowerShell@2 displayName: 'Locate MSVC arm64 cross-tools (vswhere)' @@ -314,6 +355,15 @@ steps: Write-Host "cmd /v:on /c $cmdLine" cmd /v:on /c $cmdLine if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + } elseif ('${{ parameters.rid }}' -eq 'win-arm64') { + $vcvars = "$(vcvarsAllPath)" + if (-not $vcvars) { throw "vcvarsAllPath pipeline variable is empty" } + $buildArgs = @('-m', 'build', '--wheel', '--outdir', $outDir) + $extraArgs + $quoted = ($buildArgs | ForEach-Object { '"' + $_ + '"' }) -join ' ' + $cmdLine = "`\"$vcvars`\" arm64 && set DISTUTILS_USE_SDK=1 && set MSSdk=1 && python $quoted" + Write-Host "cmd /c $cmdLine" + cmd /c $cmdLine + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } else { python -m build --wheel --outdir $outDir @extraArgs if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } From 43ac8753fd843d4f709ffca938a30f2f25a3312d Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 11:09:07 -0700 Subject: [PATCH 26/36] typo --- .pipelines/v2/templates/steps-build-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/v2/templates/steps-build-python.yml b/.pipelines/v2/templates/steps-build-python.yml index ab2a5a7ee..37370e211 100644 --- a/.pipelines/v2/templates/steps-build-python.yml +++ b/.pipelines/v2/templates/steps-build-python.yml @@ -360,7 +360,7 @@ steps: if (-not $vcvars) { throw "vcvarsAllPath pipeline variable is empty" } $buildArgs = @('-m', 'build', '--wheel', '--outdir', $outDir) + $extraArgs $quoted = ($buildArgs | ForEach-Object { '"' + $_ + '"' }) -join ' ' - $cmdLine = "`\"$vcvars`\" arm64 && set DISTUTILS_USE_SDK=1 && set MSSdk=1 && python $quoted" + $cmdLine = ('"{0}" arm64 && set DISTUTILS_USE_SDK=1 && set MSSdk=1 && python {1}' -f $vcvars, $quoted) Write-Host "cmd /c $cmdLine" cmd /c $cmdLine if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } From 7b43ad3cc1a50b6e482b3ac1a072c3ebe8924f3c Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 12:48:55 -0700 Subject: [PATCH 27/36] nits --- .pipelines/v2/templates/stages-cs.yml | 1 + .pipelines/v2/templates/stages-python.yml | 5 +++-- .pipelines/v2/templates/steps-build-js.yml | 17 +++++++++++++++++ .pipelines/v2/templates/steps-test-cs.yml | 16 ++++++++++------ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index 255eebbb7..8f6948535 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -75,6 +75,7 @@ stages: parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + usePwsh: false - stage: cs_test_win_arm64 displayName: 'C# SDK: Test Windows ARM64' diff --git a/.pipelines/v2/templates/stages-python.yml b/.pipelines/v2/templates/stages-python.yml index 932ce1ca7..414d0f18b 100644 --- a/.pipelines/v2/templates/stages-python.yml +++ b/.pipelines/v2/templates/stages-python.yml @@ -191,9 +191,10 @@ stages: steps: - checkout: self clean: true - - template: ../../templates/checkout-steps.yml@self + - template: ../../templates/fetch-test-data-from-blob.yml@self parameters: - repoName: test-data-shared + scriptType: ps + installAzCli: true - template: steps-test-python.yml parameters: wheelDir: '$(Pipeline.Workspace)/python-sdk-win-arm64' diff --git a/.pipelines/v2/templates/steps-build-js.yml b/.pipelines/v2/templates/steps-build-js.yml index 909f9e062..ce7ae98c0 100644 --- a/.pipelines/v2/templates/steps-build-js.yml +++ b/.pipelines/v2/templates/steps-build-js.yml @@ -51,6 +51,20 @@ steps: inputs: versionSpec: '20.x' +- ${{ if eq(parameters.rid, 'win-x64') }}: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.12 (x64)' + inputs: + versionSpec: '3.12' + architecture: 'x64' + +- ${{ if eq(parameters.rid, 'win-arm64') }}: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.12 (arm64)' + inputs: + versionSpec: '3.12' + architecture: 'arm64' + # Map ADO RID -> Node-style platform-arch key used inside the npm tarball # (prebuilds/-/) so downstream consumers find the addon under # the directory matching `${process.platform}-${process.arch}` at runtime. @@ -95,6 +109,7 @@ steps: # is added separately in binding.gyp via `../cpp/include`. - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - powershell: | + python --version $arch = '${{ parameters.targetArch }}' $args = if ($arch -eq 'native') { 'rebuild' } else { "rebuild --arch=$arch" } Write-Host "node-gyp $args" @@ -103,6 +118,8 @@ steps: if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } displayName: 'Build Node-API addon' env: + PYTHON: '$(pythonLocation)\python.exe' + npm_config_python: '$(pythonLocation)\python.exe' FOUNDRY_LOCAL_LIB_DIR: '${{ parameters.nativeArtifactDir }}' FOUNDRY_LOCAL_INCLUDE_DIR: '${{ parameters.includeArtifactDir }}' # Force the copy_addon_to_prebuilds destination to the target-arch dir. diff --git a/.pipelines/v2/templates/steps-test-cs.yml b/.pipelines/v2/templates/steps-test-cs.yml index adbb10644..b861b00e3 100644 --- a/.pipelines/v2/templates/steps-test-cs.yml +++ b/.pipelines/v2/templates/steps-test-cs.yml @@ -15,6 +15,10 @@ parameters: type: string default: '' displayName: 'Optional extra dotnet test arguments' +- name: usePwsh + type: boolean + default: true + displayName: 'Use PowerShell Core (pwsh) for PowerShell tasks' steps: @@ -40,7 +44,7 @@ steps: displayName: 'Set package version' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $v = (Get-Content "$(Pipeline.Workspace)/version-info/sdkVersion.txt" -Raw).Trim() Write-Host "Package version: $v" @@ -50,7 +54,7 @@ steps: displayName: 'Create NuGet.config with local Foundry Local Runtime feed' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $pkgPattern = 'Microsoft.AI.Foundry.Local.Runtime*.nupkg' $nupkg = Get-ChildItem "${{ parameters.flNugetDir }}" -Recurse -Filter $pkgPattern | @@ -84,7 +88,7 @@ steps: displayName: 'Set isolated NuGet packages path' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $buildDir = "$(Build.BinariesDirectory)/nuget-isolated-$(System.JobId)" if (Test-Path $buildDir) { @@ -105,7 +109,7 @@ steps: displayName: 'Restore & build tests' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $proj = "$(Build.SourcesDirectory)/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" $rid = dotnet msbuild $proj -getProperty:NETCoreSdkRuntimeIdentifier @@ -130,7 +134,7 @@ steps: displayName: 'Purge stale native redirect files' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | # Defense in depth: in CI we resolve foundry_local exclusively via the # Microsoft.AI.Foundry.Local.Runtime NuGet package (runtimes//native/). @@ -150,7 +154,7 @@ steps: displayName: 'Run SDK tests' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $proj = "$(Build.SourcesDirectory)/sdk_v2/cs/test/FoundryLocal.Tests/Microsoft.AI.Foundry.Local.Tests.csproj" From 500e2798753fd3bee9948187b9c7960fda8727d4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 12:58:25 -0700 Subject: [PATCH 28/36] typo --- .pipelines/v2/templates/steps-build-js.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/v2/templates/steps-build-js.yml b/.pipelines/v2/templates/steps-build-js.yml index ce7ae98c0..3b253add4 100644 --- a/.pipelines/v2/templates/steps-build-js.yml +++ b/.pipelines/v2/templates/steps-build-js.yml @@ -109,7 +109,7 @@ steps: # is added separately in binding.gyp via `../cpp/include`. - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - powershell: | - python --version + python --version $arch = '${{ parameters.targetArch }}' $args = if ($arch -eq 'native') { 'rebuild' } else { "rebuild --arch=$arch" } Write-Host "node-gyp $args" From 2dd2e38ee425f52371be177b95df0d486297439b Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 14:31:24 -0700 Subject: [PATCH 29/36] visual studio --- .pipelines/v2/templates/steps-build-js.yml | 51 +++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/.pipelines/v2/templates/steps-build-js.yml b/.pipelines/v2/templates/steps-build-js.yml index 3b253add4..88a71bc20 100644 --- a/.pipelines/v2/templates/steps-build-js.yml +++ b/.pipelines/v2/templates/steps-build-js.yml @@ -65,6 +65,47 @@ steps: versionSpec: '3.12' architecture: 'arm64' +- ${{ if eq(parameters.rid, 'win-arm64') }}: + - task: PowerShell@2 + displayName: 'Ensure Visual Studio Build Tools for node-gyp (win-arm64)' + inputs: + targetType: inline + pwsh: false + script: | + $installRoot = 'C:\BuildTools' + $vcvars = Join-Path $installRoot 'VC\Auxiliary\Build\vcvarsall.bat' + + if (-not (Test-Path $vcvars)) { + Write-Host 'Visual Studio Build Tools not fully present. Installing...' + $bootstrapper = Join-Path $env:TEMP 'vs_BuildTools.exe' + Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile $bootstrapper -UseBasicParsing + + $arguments = @( + '--quiet', + '--wait', + '--norestart', + '--nocache', + '--installPath', $installRoot, + '--add', 'Microsoft.VisualStudio.Workload.VCTools', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.ARM64', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', + '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22621', + '--includeRecommended' + ) + + $process = Start-Process -FilePath $bootstrapper -ArgumentList $arguments -Wait -PassThru + if ($process.ExitCode -ne 0) { + throw "Visual Studio Build Tools install failed with exit code $($process.ExitCode)." + } + } + + if (-not (Test-Path $vcvars)) { + throw "vcvarsall.bat was not found at $vcvars after Build Tools install." + } + + Write-Host "vcvarsall.bat: $vcvars" + Write-Host "##vso[task.setvariable variable=vcvarsAllPath]$vcvars" + # Map ADO RID -> Node-style platform-arch key used inside the npm tarball # (prebuilds/-/) so downstream consumers find the addon under # the directory matching `${process.platform}-${process.arch}` at runtime. @@ -114,7 +155,15 @@ steps: $args = if ($arch -eq 'native') { 'rebuild' } else { "rebuild --arch=$arch" } Write-Host "node-gyp $args" Set-Location "$(Build.SourcesDirectory)/sdk_v2/js" - npx --no-install node-gyp $args.Split(' ') + if ('${{ parameters.rid }}' -eq 'win-arm64') { + $vcvars = "$(vcvarsAllPath)" + if (-not $vcvars) { throw "vcvarsAllPath pipeline variable is empty" } + $cmdLine = ('"{0}" arm64 && npx --no-install node-gyp {1}' -f $vcvars, $args) + Write-Host "cmd /c $cmdLine" + cmd /c $cmdLine + } else { + npx --no-install node-gyp $args.Split(' ') + } if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } displayName: 'Build Node-API addon' env: From 6cf8667568a5d8c1fc6288cce23bd27700f112e0 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 14:47:47 -0700 Subject: [PATCH 30/36] python --- .pipelines/v2/templates/stages-python.yml | 1 + .pipelines/v2/templates/steps-test-python.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.pipelines/v2/templates/stages-python.yml b/.pipelines/v2/templates/stages-python.yml index 414d0f18b..40a553b05 100644 --- a/.pipelines/v2/templates/stages-python.yml +++ b/.pipelines/v2/templates/stages-python.yml @@ -200,6 +200,7 @@ stages: wheelDir: '$(Pipeline.Workspace)/python-sdk-win-arm64' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' pythonArchitecture: 'arm64' + usePwsh: false - stage: python_test_linux_x64 displayName: 'Python SDK: Test Linux x64' diff --git a/.pipelines/v2/templates/steps-test-python.yml b/.pipelines/v2/templates/steps-test-python.yml index 223ef527f..624094b35 100644 --- a/.pipelines/v2/templates/steps-test-python.yml +++ b/.pipelines/v2/templates/steps-test-python.yml @@ -17,6 +17,10 @@ parameters: default: 'x64' values: ['x64', 'arm64'] displayName: 'Architecture of the host Python interpreter (matches the agent OS arch).' +- name: usePwsh + type: boolean + default: true + displayName: 'Use PowerShell Core (pwsh). Set false to use Windows PowerShell.' steps: @@ -32,7 +36,7 @@ steps: displayName: 'Create test venv' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | $venvDir = "$(Agent.TempDirectory)/fl-py-venv-$(System.JobId)" if (Test-Path $venvDir) { Remove-Item -Recurse -Force $venvDir } @@ -51,7 +55,7 @@ steps: displayName: 'Install built wheel + test deps' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | # Locate the wheel. Each job's wheel lands in its own artifact, so a # single match is expected. @@ -75,7 +79,7 @@ steps: displayName: 'Run SDK tests' inputs: targetType: inline - pwsh: true + pwsh: ${{ parameters.usePwsh }} script: | Push-Location "$(Build.SourcesDirectory)/sdk_v2/python" try { From b2868605f7cfdca2e4382ba86dbf1116644977f2 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Thu, 23 Jul 2026 18:49:15 -0700 Subject: [PATCH 31/36] fixes --- .pipelines/v2/templates/stages-cs.yml | 1 + .pipelines/v2/templates/stages-js.yml | 1 + .pipelines/v2/templates/steps-test-js.yml | 54 ++++++++++++------- .../foundry_local_sdk/_native/lib_loader.py | 3 ++ 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/.pipelines/v2/templates/stages-cs.yml b/.pipelines/v2/templates/stages-cs.yml index 8f6948535..654f39994 100644 --- a/.pipelines/v2/templates/stages-cs.yml +++ b/.pipelines/v2/templates/stages-cs.yml @@ -106,6 +106,7 @@ stages: parameters: flNugetDir: '$(Pipeline.Workspace)/cpp-nuget' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + usePwsh: false # ==================================================================== # Test — Linux x64 / macOS ARM64 diff --git a/.pipelines/v2/templates/stages-js.yml b/.pipelines/v2/templates/stages-js.yml index 049e93647..5103ea37f 100644 --- a/.pipelines/v2/templates/stages-js.yml +++ b/.pipelines/v2/templates/stages-js.yml @@ -231,6 +231,7 @@ stages: rid: 'win-arm64' prebuildArtifactDir: '$(Pipeline.Workspace)/js-prebuild-win-arm64' testDataSharedDir: '$(Build.SourcesDirectory)/test-data-shared' + usePwsh: false - stage: js_test_linux_x64 displayName: 'JS SDK: Test Linux x64' diff --git a/.pipelines/v2/templates/steps-test-js.yml b/.pipelines/v2/templates/steps-test-js.yml index 8393b1d03..09430586e 100644 --- a/.pipelines/v2/templates/steps-test-js.yml +++ b/.pipelines/v2/templates/steps-test-js.yml @@ -15,6 +15,10 @@ parameters: - name: testDataSharedDir type: string displayName: 'Path to the model cache directory used by tests' +- name: usePwsh + type: boolean + default: true + displayName: 'Use PowerShell Core (pwsh) for Windows PowerShell tasks' steps: @@ -24,15 +28,19 @@ steps: versionSpec: '20.x' - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: - - pwsh: | - $src = "${{ parameters.prebuildArtifactDir }}/prebuilds" - $dst = "$(Build.SourcesDirectory)/sdk_v2/js/prebuilds" - if (-not (Test-Path $src)) { throw "Prebuild artifact missing: $src" } - if (Test-Path $dst) { Remove-Item -Recurse -Force $dst } - New-Item -ItemType Directory -Force -Path $dst | Out-Null - Copy-Item "$src/*" -Destination $dst -Recurse -Force - Get-ChildItem -Recurse $dst | ForEach-Object { Write-Host " $($_.FullName)" } + - task: PowerShell@2 displayName: 'Drop prebuild into sdk_v2/js/prebuilds' + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $src = "${{ parameters.prebuildArtifactDir }}/prebuilds" + $dst = "$(Build.SourcesDirectory)/sdk_v2/js/prebuilds" + if (-not (Test-Path $src)) { throw "Prebuild artifact missing: $src" } + if (Test-Path $dst) { Remove-Item -Recurse -Force $dst } + New-Item -ItemType Directory -Force -Path $dst | Out-Null + Copy-Item "$src/*" -Destination $dst -Recurse -Force + Get-ChildItem -Recurse $dst | ForEach-Object { Write-Host " $($_.FullName)" } - ${{ if or(eq(parameters.rid, 'linux-x64'), eq(parameters.rid, 'osx-arm64')) }}: - bash: | @@ -54,20 +62,28 @@ steps: workingDir: '$(Build.SourcesDirectory)/sdk_v2/js' customCommand: 'ci --no-audit --no-fund' - - pwsh: | - Set-Location "$(Build.SourcesDirectory)/sdk_v2/js" - npm run build:ts - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + - task: PowerShell@2 displayName: 'Build TypeScript' + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + Set-Location "$(Build.SourcesDirectory)/sdk_v2/js" + npm run build:ts + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - - pwsh: | - Set-Location "$(Build.SourcesDirectory)/sdk_v2/js" - Write-Host "FOUNDRY_TEST_DATA_DIR=$env:FOUNDRY_TEST_DATA_DIR" - if (-not (Test-Path $env:FOUNDRY_TEST_DATA_DIR)) { throw "FOUNDRY_TEST_DATA_DIR does not exist: $env:FOUNDRY_TEST_DATA_DIR" } - Get-ChildItem -Path $env:FOUNDRY_TEST_DATA_DIR -Force | ForEach-Object { Write-Host " $($_.FullName)" } - npx --no-install vitest run --reporter=verbose - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + - task: PowerShell@2 displayName: 'Run vitest' + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + Set-Location "$(Build.SourcesDirectory)/sdk_v2/js" + Write-Host "FOUNDRY_TEST_DATA_DIR=$env:FOUNDRY_TEST_DATA_DIR" + if (-not (Test-Path $env:FOUNDRY_TEST_DATA_DIR)) { throw "FOUNDRY_TEST_DATA_DIR does not exist: $env:FOUNDRY_TEST_DATA_DIR" } + Get-ChildItem -Path $env:FOUNDRY_TEST_DATA_DIR -Force | ForEach-Object { Write-Host " $($_.FullName)" } + npx --no-install vitest run --reporter=verbose + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } env: FOUNDRY_TEST_DATA_DIR: '${{ parameters.testDataSharedDir }}' diff --git a/sdk_v2/python/src/foundry_local_sdk/_native/lib_loader.py b/sdk_v2/python/src/foundry_local_sdk/_native/lib_loader.py index 1369759c8..a1a7bddb6 100644 --- a/sdk_v2/python/src/foundry_local_sdk/_native/lib_loader.py +++ b/sdk_v2/python/src/foundry_local_sdk/_native/lib_loader.py @@ -29,6 +29,9 @@ def _lib_name() -> str: def _platform_subdir() -> str: if sys.platform == "win32": + machine = platform.machine().lower() + if machine in {"arm64", "aarch64"}: + return "win-arm64" return "win-x64" if sys.platform == "darwin": return "osx-arm64" if platform.machine() == "arm64" else "osx-x64" From d46ededfbf07b1643a3e50e085111efc5c4aba66 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 24 Jul 2026 09:08:46 -0700 Subject: [PATCH 32/36] diagnose --- .../v2/templates/steps-build-windows.yml | 1 + .pipelines/v2/templates/steps-test-cs.yml | 73 ++++++++++++++++++ .pipelines/v2/templates/steps-test-js.yml | 69 +++++++++++++++++ .pipelines/v2/templates/steps-test-python.yml | 76 +++++++++++++++++++ 4 files changed, 219 insertions(+) diff --git a/.pipelines/v2/templates/steps-build-windows.yml b/.pipelines/v2/templates/steps-build-windows.yml index 9154bf177..4735a1af0 100644 --- a/.pipelines/v2/templates/steps-build-windows.yml +++ b/.pipelines/v2/templates/steps-build-windows.yml @@ -235,6 +235,7 @@ steps: Write-Host " staged $(Split-Path -Leaf $s)" } + - ${{ if eq(parameters.stageHeaders, true) }}: - task: CopyFiles@2 displayName: 'Stage public headers' diff --git a/.pipelines/v2/templates/steps-test-cs.yml b/.pipelines/v2/templates/steps-test-cs.yml index b861b00e3..c296faaee 100644 --- a/.pipelines/v2/templates/steps-test-cs.yml +++ b/.pipelines/v2/templates/steps-test-cs.yml @@ -150,6 +150,79 @@ steps: Write-Host "No stale foundry_local.native.cfg files found." } +- task: PowerShell@2 + displayName: 'ARM64 native loader diagnostics (C#)' + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['Agent.OSArchitecture'], 'ARM64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Continue' + Write-Host "Agent.OS=$env:AGENT_OS" + Write-Host "Agent.OSArchitecture=$env:AGENT_OSARCHITECTURE" + Write-Host "PROCESSOR_ARCHITECTURE=$env:PROCESSOR_ARCHITECTURE" + + $dumpbin = (Get-Command dumpbin.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + $linkExe = (Get-Command link.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + + function Show-DllDiagnostics([string]$dllPath) { + if (-not (Test-Path $dllPath)) { + Write-Warning "Missing target DLL: $dllPath" + return + } + + Write-Host "" + Write-Host "=== Diagnostics for $dllPath ===" + $output = @() + if ($dumpbin) { + $output = & $dumpbin /dependents $dllPath 2>&1 + } elseif ($linkExe) { + $output = & $linkExe /dump /dependents $dllPath 2>&1 + } else { + Write-Warning 'Neither dumpbin.exe nor link.exe found on PATH.' + } + + if ($output.Count -gt 0) { + $output | ForEach-Object { Write-Host $_ } + $deps = @($output | + ForEach-Object { + $line = $_.ToString().Trim() + if ($line -match '^[A-Za-z0-9._-]+\\.dll$') { $line.ToLowerInvariant() } + } | + Where-Object { $_ } | + Select-Object -Unique) + + $probeDirs = @( + (Split-Path -Parent $dllPath), + "$env:WINDIR\\System32", + "$env:WINDIR\\SysWOW64" + ) + foreach ($dep in $deps) { + $resolved = $null + foreach ($d in $probeDirs) { + $p = Join-Path $d $dep + if (Test-Path $p) { $resolved = $p; break } + } + if ($resolved) { + Write-Host " resolved: $dep -> $resolved" + } else { + Write-Warning " unresolved: $dep" + } + } + } + } + + $nativeCandidates = Get-ChildItem -Path "$(Build.SourcesDirectory)/sdk_v2/cs" -Recurse -Filter 'foundry_local.dll' -ErrorAction SilentlyContinue | + Where-Object { $_.FullName -match 'runtimes\\win-arm64\\native' } + + if (-not $nativeCandidates) { + Write-Warning 'No runtimes/win-arm64/native/foundry_local.dll found under sdk_v2/cs output.' + } + + foreach ($dll in $nativeCandidates) { + Show-DllDiagnostics $dll.FullName + } + - task: PowerShell@2 displayName: 'Run SDK tests' inputs: diff --git a/.pipelines/v2/templates/steps-test-js.yml b/.pipelines/v2/templates/steps-test-js.yml index 09430586e..e4f2c427c 100644 --- a/.pipelines/v2/templates/steps-test-js.yml +++ b/.pipelines/v2/templates/steps-test-js.yml @@ -72,6 +72,75 @@ steps: npm run build:ts if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + - task: PowerShell@2 + displayName: 'ARM64 native loader diagnostics (JS)' + condition: and(succeeded(), eq('${{ parameters.rid }}', 'win-arm64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Continue' + $prebuildDir = "$(Build.SourcesDirectory)/sdk_v2/js/prebuilds/win32-arm64" + Write-Host "Diagnostic prebuild dir: $prebuildDir" + Write-Host "Agent.OS=$env:AGENT_OS" + Write-Host "Agent.OSArchitecture=$env:AGENT_OSARCHITECTURE" + Write-Host "PROCESSOR_ARCHITECTURE=$env:PROCESSOR_ARCHITECTURE" + Get-ChildItem -Path $prebuildDir -Force | ForEach-Object { Write-Host " $($_.Name)" } + + $dumpbin = (Get-Command dumpbin.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + $linkExe = (Get-Command link.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + + function Show-DllDiagnostics([string]$dllPath) { + if (-not (Test-Path $dllPath)) { + Write-Warning "Missing target DLL: $dllPath" + return + } + + Write-Host "" + Write-Host "=== Diagnostics for $dllPath ===" + $output = @() + if ($dumpbin) { + $output = & $dumpbin /dependents $dllPath 2>&1 + } elseif ($linkExe) { + $output = & $linkExe /dump /dependents $dllPath 2>&1 + } else { + Write-Warning 'Neither dumpbin.exe nor link.exe found on PATH.' + } + + if ($output.Count -gt 0) { + $output | ForEach-Object { Write-Host $_ } + $deps = @($output | + ForEach-Object { + $line = $_.ToString().Trim() + if ($line -match '^[A-Za-z0-9._-]+\\.dll$') { $line.ToLowerInvariant() } + } | + Where-Object { $_ } | + Select-Object -Unique) + + $probeDirs = @( + (Split-Path -Parent $dllPath), + "$env:WINDIR\\System32", + "$env:WINDIR\\SysWOW64" + ) + foreach ($dep in $deps) { + $resolved = $null + foreach ($d in $probeDirs) { + $p = Join-Path $d $dep + if (Test-Path $p) { $resolved = $p; break } + } + if ($resolved) { + Write-Host " resolved: $dep -> $resolved" + } else { + Write-Warning " unresolved: $dep" + } + } + } + } + + Show-DllDiagnostics (Join-Path $prebuildDir 'foundry_local.dll') + Show-DllDiagnostics (Join-Path $prebuildDir 'onnxruntime.dll') + Show-DllDiagnostics (Join-Path $prebuildDir 'onnxruntime-genai.dll') + - task: PowerShell@2 displayName: 'Run vitest' inputs: diff --git a/.pipelines/v2/templates/steps-test-python.yml b/.pipelines/v2/templates/steps-test-python.yml index 624094b35..2a85f61ed 100644 --- a/.pipelines/v2/templates/steps-test-python.yml +++ b/.pipelines/v2/templates/steps-test-python.yml @@ -75,6 +75,82 @@ steps: & "$(venvPy)" -m pip install pytest pytest-cov if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +- task: PowerShell@2 + displayName: 'ARM64 native loader diagnostics (Python)' + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['Agent.OSArchitecture'], 'ARM64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Continue' + Write-Host "Agent.OS=$env:AGENT_OS" + Write-Host "Agent.OSArchitecture=$env:AGENT_OSARCHITECTURE" + Write-Host "PROCESSOR_ARCHITECTURE=$env:PROCESSOR_ARCHITECTURE" + + $dumpbin = (Get-Command dumpbin.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + $linkExe = (Get-Command link.exe -ErrorAction SilentlyContinue | Select-Object -First 1).Source + + function Show-DllDiagnostics([string]$dllPath) { + if (-not (Test-Path $dllPath)) { + Write-Warning "Missing target DLL: $dllPath" + return + } + + Write-Host "" + Write-Host "=== Diagnostics for $dllPath ===" + $output = @() + if ($dumpbin) { + $output = & $dumpbin /dependents $dllPath 2>&1 + } elseif ($linkExe) { + $output = & $linkExe /dump /dependents $dllPath 2>&1 + } else { + Write-Warning 'Neither dumpbin.exe nor link.exe found on PATH.' + } + + if ($output.Count -gt 0) { + $output | ForEach-Object { Write-Host $_ } + $deps = @($output | + ForEach-Object { + $line = $_.ToString().Trim() + if ($line -match '^[A-Za-z0-9._-]+\\.dll$') { $line.ToLowerInvariant() } + } | + Where-Object { $_ } | + Select-Object -Unique) + + $probeDirs = @( + (Split-Path -Parent $dllPath), + "$env:WINDIR\\System32", + "$env:WINDIR\\SysWOW64" + ) + foreach ($dep in $deps) { + $resolved = $null + foreach ($d in $probeDirs) { + $p = Join-Path $d $dep + if (Test-Path $p) { $resolved = $p; break } + } + if ($resolved) { + Write-Host " resolved: $dep -> $resolved" + } else { + Write-Warning " unresolved: $dep" + } + } + } + } + + $wheelNativeDir = & "$(venvPy)" -c "import pathlib,foundry_local_sdk._native.lib_loader as l; print((pathlib.Path(l.__file__).resolve().parent / 'win-arm64'))" + $wheelNativeDir = $wheelNativeDir.Trim() + Write-Host "Wheel native dir: $wheelNativeDir" + if (Test-Path $wheelNativeDir) { + Get-ChildItem -Path $wheelNativeDir -Force | ForEach-Object { Write-Host " $($_.Name)" } + } + + $ortDll = & "$(venvPy)" -c "import importlib.util,pathlib; s=importlib.util.find_spec('onnxruntime_core'); print((pathlib.Path(s.origin).resolve().parent / 'bin' / 'onnxruntime.dll') if s else '')" + $genaiDll = & "$(venvPy)" -c "import importlib.util,pathlib; s=importlib.util.find_spec('onnxruntime_genai_core'); print((pathlib.Path(s.origin).resolve().parent / 'bin' / 'onnxruntime-genai.dll') if s else '')" + + Show-DllDiagnostics (Join-Path $wheelNativeDir 'foundry_local.dll') + if ($ortDll) { Show-DllDiagnostics $ortDll.Trim() } + if ($genaiDll) { Show-DllDiagnostics $genaiDll.Trim() } + - task: PowerShell@2 displayName: 'Run SDK tests' inputs: From c6878f5489ac6e702809035fac34f01448786b77 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 24 Jul 2026 11:21:56 -0700 Subject: [PATCH 33/36] vc --- .pipelines/v2/templates/steps-test-cs.yml | 39 +++++++++++++++++++ .pipelines/v2/templates/steps-test-js.yml | 39 +++++++++++++++++++ .pipelines/v2/templates/steps-test-python.yml | 39 +++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/.pipelines/v2/templates/steps-test-cs.yml b/.pipelines/v2/templates/steps-test-cs.yml index c296faaee..f510d754e 100644 --- a/.pipelines/v2/templates/steps-test-cs.yml +++ b/.pipelines/v2/templates/steps-test-cs.yml @@ -40,6 +40,45 @@ steps: packageType: runtime version: '8.0.x' +- task: PowerShell@2 + displayName: 'Bootstrap VC++ ARM64 runtime' + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['Agent.OSArchitecture'], 'ARM64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Stop' + $url = 'https://aka.ms/vs/17/release/vc_redist.arm64.exe' + $installer = Join-Path $env:TEMP 'vc_redist.arm64.exe' + $logPath = Join-Path $env:TEMP 'vc_redist_arm64_install.log' + + Write-Host "Downloading ARM64 VC++ runtime from: $url" + Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing + + $arguments = @('/install', '/quiet', '/norestart', '/log', $logPath) + $proc = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru + if ($proc.ExitCode -notin @(0, 3010, 1638)) { + throw "VC++ ARM64 runtime installer failed with exit code $($proc.ExitCode). Log: $logPath" + } + + if ($proc.ExitCode -eq 3010) { + Write-Host 'VC++ ARM64 runtime installed; reboot is required by installer but deferred in CI.' + } elseif ($proc.ExitCode -eq 1638) { + Write-Host 'A newer/same VC++ ARM64 runtime is already installed.' + } else { + Write-Host 'VC++ ARM64 runtime installation completed successfully.' + } + + $runtimeDlls = @('vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') + foreach ($dll in $runtimeDlls) { + $path = Join-Path "$env:WINDIR\System32" $dll + if (-not (Test-Path $path)) { + throw "Expected ARM64 VC runtime DLL not found: $path" + } + $ver = (Get-Item $path).VersionInfo.FileVersion + Write-Host " $dll => $path (version: $ver)" + } + - task: PowerShell@2 displayName: 'Set package version' inputs: diff --git a/.pipelines/v2/templates/steps-test-js.yml b/.pipelines/v2/templates/steps-test-js.yml index e4f2c427c..3d4f5b545 100644 --- a/.pipelines/v2/templates/steps-test-js.yml +++ b/.pipelines/v2/templates/steps-test-js.yml @@ -55,6 +55,45 @@ steps: displayName: 'Drop prebuild into sdk_v2/js/prebuilds' - ${{ if or(eq(parameters.rid, 'win-x64'), eq(parameters.rid, 'win-arm64')) }}: + - task: PowerShell@2 + displayName: 'Bootstrap VC++ ARM64 runtime' + condition: and(succeeded(), eq('${{ parameters.rid }}', 'win-arm64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Stop' + $url = 'https://aka.ms/vs/17/release/vc_redist.arm64.exe' + $installer = Join-Path $env:TEMP 'vc_redist.arm64.exe' + $logPath = Join-Path $env:TEMP 'vc_redist_arm64_install.log' + + Write-Host "Downloading ARM64 VC++ runtime from: $url" + Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing + + $arguments = @('/install', '/quiet', '/norestart', '/log', $logPath) + $proc = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru + if ($proc.ExitCode -notin @(0, 3010, 1638)) { + throw "VC++ ARM64 runtime installer failed with exit code $($proc.ExitCode). Log: $logPath" + } + + if ($proc.ExitCode -eq 3010) { + Write-Host 'VC++ ARM64 runtime installed; reboot is required by installer but deferred in CI.' + } elseif ($proc.ExitCode -eq 1638) { + Write-Host 'A newer/same VC++ ARM64 runtime is already installed.' + } else { + Write-Host 'VC++ ARM64 runtime installation completed successfully.' + } + + $runtimeDlls = @('vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') + foreach ($dll in $runtimeDlls) { + $path = Join-Path "$env:WINDIR\System32" $dll + if (-not (Test-Path $path)) { + throw "Expected ARM64 VC runtime DLL not found: $path" + } + $ver = (Get-Item $path).VersionInfo.FileVersion + Write-Host " $dll => $path (version: $ver)" + } + - task: Npm@1 displayName: 'npm ci (runs install-native postinstall)' inputs: diff --git a/.pipelines/v2/templates/steps-test-python.yml b/.pipelines/v2/templates/steps-test-python.yml index 2a85f61ed..35f8261c6 100644 --- a/.pipelines/v2/templates/steps-test-python.yml +++ b/.pipelines/v2/templates/steps-test-python.yml @@ -31,6 +31,45 @@ steps: addToPath: true architecture: '${{ parameters.pythonArchitecture }}' +- task: PowerShell@2 + displayName: 'Bootstrap VC++ ARM64 runtime' + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['Agent.OSArchitecture'], 'ARM64')) + inputs: + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Stop' + $url = 'https://aka.ms/vs/17/release/vc_redist.arm64.exe' + $installer = Join-Path $env:TEMP 'vc_redist.arm64.exe' + $logPath = Join-Path $env:TEMP 'vc_redist_arm64_install.log' + + Write-Host "Downloading ARM64 VC++ runtime from: $url" + Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing + + $arguments = @('/install', '/quiet', '/norestart', '/log', $logPath) + $proc = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru + if ($proc.ExitCode -notin @(0, 3010, 1638)) { + throw "VC++ ARM64 runtime installer failed with exit code $($proc.ExitCode). Log: $logPath" + } + + if ($proc.ExitCode -eq 3010) { + Write-Host 'VC++ ARM64 runtime installed; reboot is required by installer but deferred in CI.' + } elseif ($proc.ExitCode -eq 1638) { + Write-Host 'A newer/same VC++ ARM64 runtime is already installed.' + } else { + Write-Host 'VC++ ARM64 runtime installation completed successfully.' + } + + $runtimeDlls = @('vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') + foreach ($dll in $runtimeDlls) { + $path = Join-Path "$env:WINDIR\System32" $dll + if (-not (Test-Path $path)) { + throw "Expected ARM64 VC runtime DLL not found: $path" + } + $ver = (Get-Item $path).VersionInfo.FileVersion + Write-Host " $dll => $path (version: $ver)" + } + # Job-local venv so installs never pollute the agent's site-packages. - task: PowerShell@2 displayName: 'Create test venv' From 23a1700b054e1a1594555a48fc6b18fde4fb4789 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 24 Jul 2026 12:38:49 -0700 Subject: [PATCH 34/36] formaT --- .pipelines/v2/templates/steps-test-python.yml | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.pipelines/v2/templates/steps-test-python.yml b/.pipelines/v2/templates/steps-test-python.yml index 35f8261c6..a3ade3a06 100644 --- a/.pipelines/v2/templates/steps-test-python.yml +++ b/.pipelines/v2/templates/steps-test-python.yml @@ -35,40 +35,40 @@ steps: displayName: 'Bootstrap VC++ ARM64 runtime' condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['Agent.OSArchitecture'], 'ARM64')) inputs: - targetType: inline - pwsh: ${{ parameters.usePwsh }} - script: | - $ErrorActionPreference = 'Stop' - $url = 'https://aka.ms/vs/17/release/vc_redist.arm64.exe' - $installer = Join-Path $env:TEMP 'vc_redist.arm64.exe' - $logPath = Join-Path $env:TEMP 'vc_redist_arm64_install.log' - - Write-Host "Downloading ARM64 VC++ runtime from: $url" - Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing - - $arguments = @('/install', '/quiet', '/norestart', '/log', $logPath) - $proc = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru - if ($proc.ExitCode -notin @(0, 3010, 1638)) { - throw "VC++ ARM64 runtime installer failed with exit code $($proc.ExitCode). Log: $logPath" - } - - if ($proc.ExitCode -eq 3010) { - Write-Host 'VC++ ARM64 runtime installed; reboot is required by installer but deferred in CI.' - } elseif ($proc.ExitCode -eq 1638) { - Write-Host 'A newer/same VC++ ARM64 runtime is already installed.' - } else { - Write-Host 'VC++ ARM64 runtime installation completed successfully.' - } - - $runtimeDlls = @('vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') - foreach ($dll in $runtimeDlls) { - $path = Join-Path "$env:WINDIR\System32" $dll - if (-not (Test-Path $path)) { - throw "Expected ARM64 VC runtime DLL not found: $path" + targetType: inline + pwsh: ${{ parameters.usePwsh }} + script: | + $ErrorActionPreference = 'Stop' + $url = 'https://aka.ms/vs/17/release/vc_redist.arm64.exe' + $installer = Join-Path $env:TEMP 'vc_redist.arm64.exe' + $logPath = Join-Path $env:TEMP 'vc_redist_arm64_install.log' + + Write-Host "Downloading ARM64 VC++ runtime from: $url" + Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing + + $arguments = @('/install', '/quiet', '/norestart', '/log', $logPath) + $proc = Start-Process -FilePath $installer -ArgumentList $arguments -Wait -PassThru + if ($proc.ExitCode -notin @(0, 3010, 1638)) { + throw "VC++ ARM64 runtime installer failed with exit code $($proc.ExitCode). Log: $logPath" + } + + if ($proc.ExitCode -eq 3010) { + Write-Host 'VC++ ARM64 runtime installed; reboot is required by installer but deferred in CI.' + } elseif ($proc.ExitCode -eq 1638) { + Write-Host 'A newer/same VC++ ARM64 runtime is already installed.' + } else { + Write-Host 'VC++ ARM64 runtime installation completed successfully.' + } + + $runtimeDlls = @('vcruntime140.dll', 'vcruntime140_1.dll', 'msvcp140.dll') + foreach ($dll in $runtimeDlls) { + $path = Join-Path "$env:WINDIR\System32" $dll + if (-not (Test-Path $path)) { + throw "Expected ARM64 VC runtime DLL not found: $path" + } + $ver = (Get-Item $path).VersionInfo.FileVersion + Write-Host " $dll => $path (version: $ver)" } - $ver = (Get-Item $path).VersionInfo.FileVersion - Write-Host " $dll => $path (version: $ver)" - } # Job-local venv so installs never pollute the agent's site-packages. - task: PowerShell@2 From a8631d484f76fb11481d5b555f2eacfa24754bb4 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 24 Jul 2026 19:12:01 -0700 Subject: [PATCH 35/36] c# tests fix --- .../cs/test/FoundryLocal.Tests/AudioClientTests.cs | 13 +++++++++---- .../cs/test/FoundryLocal.Tests/AudioSessionTests.cs | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs index e74f15715..6d6afa0ed 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs @@ -17,6 +17,11 @@ internal sealed class OpenAIAudioClientTests { private static IModel? model; + // ARM64 runs can produce punctuation-only transcript variance (for example an + // extra comma) while the spoken content is semantically identical. Strip commas + // before comparison to avoid platform-specific false negatives. + private static string WithoutCommas(string text) => text.Replace(",", string.Empty); + [Before(Class)] public static async Task Setup() { @@ -68,7 +73,7 @@ public async Task AudioTranscription_NoStreaming_Succeeds() await Assert.That(response).IsNotNull(); await Assert.That(response.Text).IsNotNull().And.IsNotEmpty(); var content = response.Text; - await Assert.That(content).IsEqualTo(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links."); + await Assert.That(WithoutCommas(content)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); Console.WriteLine($"Response: {content}"); } @@ -93,7 +98,7 @@ public async Task AudioTranscription_NoStreaming_Succeeds_WithTemperature() await Assert.That(response).IsNotNull(); await Assert.That(response.Text).IsNotNull().And.IsNotEmpty(); var content = response.Text; - await Assert.That(content).IsEqualTo(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links."); + await Assert.That(WithoutCommas(content)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); Console.WriteLine($"Response: {content}"); } @@ -157,7 +162,7 @@ public async Task AudioTranscription_Streaming_Succeeds() var fullResponse = responseMessage.ToString(); Console.WriteLine(fullResponse); - await Assert.That(fullResponse).IsEqualTo(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links."); + await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); } @@ -191,7 +196,7 @@ public async Task AudioTranscription_Streaming_Succeeds_WithTemperature() var fullResponse = responseMessage.ToString(); Console.WriteLine(fullResponse); - await Assert.That(fullResponse).IsEqualTo(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links."); + await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); } diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs index 103ad8256..90f8d9265 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs @@ -17,6 +17,11 @@ internal sealed class AudioSessionTests { private static IModel? model; + // ARM64 runs can produce punctuation-only transcript variance (for example an + // extra comma) while the spoken content is semantically identical. Strip commas + // before comparison to avoid platform-specific false negatives. + private static string WithoutCommas(string text) => text.Replace(",", string.Empty); + private const string ExpectedTranscription = " And lots of times you need to give people more than one link at a time." + " You a band could give their fans a couple new videos from the live concert" + @@ -103,7 +108,7 @@ public async Task Transcribe_NoStreaming_Succeeds() } await Assert.That(text).IsNotNull().And.IsNotEmpty(); - await Assert.That(text!).IsEqualTo(ExpectedTranscription); + await Assert.That(WithoutCommas(text!)).IsEqualTo(WithoutCommas(ExpectedTranscription)); await Assert.That(segmentCount).IsGreaterThan(0); Console.WriteLine($"Response: {text} ({segmentCount} segments)"); } @@ -146,7 +151,7 @@ public async Task Transcribe_Streaming_Succeeds() var fullResponse = sb.ToString(); Console.WriteLine($"Streaming response ({callbackCount} callbacks): {fullResponse}"); await Assert.That(callbackCount).IsGreaterThan(0); - await Assert.That(fullResponse).IsEqualTo(ExpectedTranscription); + await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(ExpectedTranscription)); } [Test] @@ -187,7 +192,7 @@ public async Task Transcribe_Streaming_FinalResponse_AggregatesTranscript() } await Assert.That(streamedCount).IsGreaterThan(0); - await Assert.That(sb.ToString()).IsEqualTo(ExpectedTranscription); + await Assert.That(WithoutCommas(sb.ToString())).IsEqualTo(WithoutCommas(ExpectedTranscription)); using var final = await stream.FinalResponse; @@ -206,7 +211,7 @@ public async Task Transcribe_Streaming_FinalResponse_AggregatesTranscript() } await Assert.That(aggregated).IsNotNull(); - await Assert.That(aggregated!).IsEqualTo(ExpectedTranscription); + await Assert.That(WithoutCommas(aggregated!)).IsEqualTo(WithoutCommas(ExpectedTranscription)); } [Test] From 84943b1b59b3b6d1f6a3a1ddff18f99317d36ed1 Mon Sep 17 00:00:00 2001 From: Prathik Rao Date: Fri, 24 Jul 2026 23:19:57 -0700 Subject: [PATCH 36/36] arm64 expected transcription --- .../FoundryLocal.Tests/AudioClientTests.cs | 19 ++++++++------ .../FoundryLocal.Tests/AudioSessionTests.cs | 25 +++++++++++-------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs index 6d6afa0ed..a74ac6133 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/AudioClientTests.cs @@ -17,10 +17,13 @@ internal sealed class OpenAIAudioClientTests { private static IModel? model; - // ARM64 runs can produce punctuation-only transcript variance (for example an - // extra comma) while the spoken content is semantically identical. Strip commas - // before comparison to avoid platform-specific false negatives. - private static string WithoutCommas(string text) => text.Replace(",", string.Empty); + private const string ExpectedTranscriptionX64 = " And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links."; + private const string ExpectedTranscriptionArm64 = " And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from a live concert behind the scenes photo gallery and album to purchase like these next few links."; + + private static string ExpectedTranscription => + System.Runtime.InteropServices.RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64 + ? ExpectedTranscriptionArm64 + : ExpectedTranscriptionX64; [Before(Class)] public static async Task Setup() @@ -73,7 +76,7 @@ public async Task AudioTranscription_NoStreaming_Succeeds() await Assert.That(response).IsNotNull(); await Assert.That(response.Text).IsNotNull().And.IsNotEmpty(); var content = response.Text; - await Assert.That(WithoutCommas(content)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); + await Assert.That(content).IsEqualTo(ExpectedTranscription); Console.WriteLine($"Response: {content}"); } @@ -98,7 +101,7 @@ public async Task AudioTranscription_NoStreaming_Succeeds_WithTemperature() await Assert.That(response).IsNotNull(); await Assert.That(response.Text).IsNotNull().And.IsNotEmpty(); var content = response.Text; - await Assert.That(WithoutCommas(content)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); + await Assert.That(content).IsEqualTo(ExpectedTranscription); Console.WriteLine($"Response: {content}"); } @@ -162,7 +165,7 @@ public async Task AudioTranscription_Streaming_Succeeds() var fullResponse = responseMessage.ToString(); Console.WriteLine(fullResponse); - await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); + await Assert.That(fullResponse).IsEqualTo(ExpectedTranscription); } @@ -196,7 +199,7 @@ public async Task AudioTranscription_Streaming_Succeeds_WithTemperature() var fullResponse = responseMessage.ToString(); Console.WriteLine(fullResponse); - await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(" And lots of times you need to give people more than one link at a time. You a band could give their fans a couple new videos from the live concert behind the scenes photo gallery and album to purchase like these next few links.")); + await Assert.That(fullResponse).IsEqualTo(ExpectedTranscription); } diff --git a/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs b/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs index 90f8d9265..9fb6e9d7a 100644 --- a/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs +++ b/sdk_v2/cs/test/FoundryLocal.Tests/AudioSessionTests.cs @@ -17,16 +17,21 @@ internal sealed class AudioSessionTests { private static IModel? model; - // ARM64 runs can produce punctuation-only transcript variance (for example an - // extra comma) while the spoken content is semantically identical. Strip commas - // before comparison to avoid platform-specific false negatives. - private static string WithoutCommas(string text) => text.Replace(",", string.Empty); - - private const string ExpectedTranscription = + private const string ExpectedTranscriptionX64 = " And lots of times you need to give people more than one link at a time." + " You a band could give their fans a couple new videos from the live concert" + " behind the scenes photo gallery and album to purchase like these next few links."; + private const string ExpectedTranscriptionArm64 = + " And lots of times you need to give people more than one link at a time." + + " You a band could give their fans a couple new videos from a live concert" + + " behind the scenes photo gallery and album to purchase like these next few links."; + + private static string ExpectedTranscription => + System.Runtime.InteropServices.RuntimeInformation.OSArchitecture == System.Runtime.InteropServices.Architecture.Arm64 + ? ExpectedTranscriptionArm64 + : ExpectedTranscriptionX64; + [Before(Class)] public static async Task Setup() { @@ -108,7 +113,7 @@ public async Task Transcribe_NoStreaming_Succeeds() } await Assert.That(text).IsNotNull().And.IsNotEmpty(); - await Assert.That(WithoutCommas(text!)).IsEqualTo(WithoutCommas(ExpectedTranscription)); + await Assert.That(text!).IsEqualTo(ExpectedTranscription); await Assert.That(segmentCount).IsGreaterThan(0); Console.WriteLine($"Response: {text} ({segmentCount} segments)"); } @@ -151,7 +156,7 @@ public async Task Transcribe_Streaming_Succeeds() var fullResponse = sb.ToString(); Console.WriteLine($"Streaming response ({callbackCount} callbacks): {fullResponse}"); await Assert.That(callbackCount).IsGreaterThan(0); - await Assert.That(WithoutCommas(fullResponse)).IsEqualTo(WithoutCommas(ExpectedTranscription)); + await Assert.That(fullResponse).IsEqualTo(ExpectedTranscription); } [Test] @@ -192,7 +197,7 @@ public async Task Transcribe_Streaming_FinalResponse_AggregatesTranscript() } await Assert.That(streamedCount).IsGreaterThan(0); - await Assert.That(WithoutCommas(sb.ToString())).IsEqualTo(WithoutCommas(ExpectedTranscription)); + await Assert.That(sb.ToString()).IsEqualTo(ExpectedTranscription); using var final = await stream.FinalResponse; @@ -211,7 +216,7 @@ public async Task Transcribe_Streaming_FinalResponse_AggregatesTranscript() } await Assert.That(aggregated).IsNotNull(); - await Assert.That(WithoutCommas(aggregated!)).IsEqualTo(WithoutCommas(ExpectedTranscription)); + await Assert.That(aggregated!).IsEqualTo(ExpectedTranscription); } [Test]