Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 122 additions & 1 deletion .pipelines/foundry-local-packaging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# Produces artifacts: flc-nuget, flc-nuget-winml, flc-wheels, flc-wheels-winml,
# cs-sdk, cs-sdk-winml, js-sdk, js-sdk-winml, python-sdk, python-sdk-winml,
# rust-sdk, rust-sdk-winml
# rust-sdk, rust-sdk-winml, cpp-sdk, cpp-sdk-winml

pr:
- main
Expand Down Expand Up @@ -643,6 +643,36 @@ extends:
# depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml'
# outputDir: '$(Build.ArtifactStagingDirectory)/rust-sdk-winml'

# ── Build C++ SDK ──
- stage: build_cpp
displayName: 'Build C++ SDK'
dependsOn:
- build_core
jobs:
- job: cpp_sdk
displayName: 'Build'
pool:
name: onnxruntime-Win-CPU-2022
os: windows
templateContext:
inputs:
- input: pipelineArtifact
artifactName: 'version-info'
targetPath: '$(Pipeline.Workspace)/version-info'
- input: pipelineArtifact
artifactName: 'deps-versions-standard'
targetPath: '$(Pipeline.Workspace)/deps-versions-standard'
outputs:
- output: pipelineArtifact
artifactName: 'cpp-sdk'
targetPath: '$(Build.ArtifactStagingDirectory)/cpp-sdk'
steps:
- checkout: self
- template: .pipelines/templates/build-cpp-steps.yml@self
parameters:
isWinML: false
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard'

# ── Test C# SDK ──
- stage: test_cs
displayName: 'Test C#'
Expand Down Expand Up @@ -1003,6 +1033,36 @@ extends:
flcNugetDir: '$(Pipeline.Workspace)/flc-nuget'
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard'

# ── Test C++ SDK ──
- stage: test_cpp
displayName: 'Test C++'
dependsOn: build_cpp
jobs:
- job: test_cpp_win_x64
displayName: 'win-x64'
pool:
name: onnxruntime-Win-CPU-2022
os: windows
templateContext:
inputs:
- input: pipelineArtifact
artifactName: 'flc-nuget'
targetPath: '$(Pipeline.Workspace)/flc-nuget'
- input: pipelineArtifact
artifactName: 'deps-versions-standard'
targetPath: '$(Pipeline.Workspace)/deps-versions-standard'
steps:
- checkout: self
clean: true
- template: .pipelines/templates/checkout-steps.yml@self
parameters:
repoName: test-data-shared
- template: .pipelines/templates/test-cpp-steps.yml@self
parameters:
isWinML: false
flcNugetDir: '$(Pipeline.Workspace)/flc-nuget'
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-standard'

# ── Build FLC (WinML) ──
- stage: build_core_winml
displayName: 'Build Core (WinML)'
Expand Down Expand Up @@ -1283,6 +1343,37 @@ extends:
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml'
outputDir: '$(Build.ArtifactStagingDirectory)/python-sdk-winml'

# ── Build C++ SDK (WinML) ──
- stage: build_cpp_winml
displayName: 'Build C++ SDK (WinML)'
dependsOn:
- build_core_winml
jobs:
- job: cpp_sdk_winml
displayName: 'Build'
pool:
name: onnxruntime-Win-CPU-2022
os: windows
templateContext:
inputs:
- input: pipelineArtifact
artifactName: 'version-info'
targetPath: '$(Pipeline.Workspace)/version-info'
- input: pipelineArtifact
artifactName: 'deps-versions-winml'
targetPath: '$(Pipeline.Workspace)/deps-versions-winml'
outputs:
- output: pipelineArtifact
artifactName: 'cpp-sdk-winml'
targetPath: '$(Build.ArtifactStagingDirectory)/cpp-sdk-winml'
steps:
- checkout: self
- template: .pipelines/templates/build-cpp-steps.yml@self
parameters:
isWinML: true
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml'
outputDir: '$(Build.ArtifactStagingDirectory)/cpp-sdk-winml'

# ── Test C# SDK (WinML) ──
- stage: test_cs_winml
displayName: 'Test C# (WinML)'
Expand Down Expand Up @@ -1377,3 +1468,33 @@ extends:
flcWheelsDir: '$(Pipeline.Workspace)/flc-wheels-winml'
sdkWheelsDir: '$(Pipeline.Workspace)/python-sdk-winml'
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml'

# ── Test C++ SDK (WinML) ──
- stage: test_cpp_winml
displayName: 'Test C++ (WinML)'
dependsOn: build_cpp_winml
jobs:
- job: test_cpp_winml_win_x64
displayName: 'win-x64'
pool:
name: onnxruntime-Win-CPU-2022
os: windows
templateContext:
inputs:
- input: pipelineArtifact
artifactName: 'flc-nuget-winml'
targetPath: '$(Pipeline.Workspace)/flc-nuget-winml'
- input: pipelineArtifact
artifactName: 'deps-versions-winml'
targetPath: '$(Pipeline.Workspace)/deps-versions-winml'
steps:
- checkout: self
clean: true
- template: .pipelines/templates/checkout-steps.yml@self
parameters:
repoName: test-data-shared
- template: .pipelines/templates/test-cpp-steps.yml@self
parameters:
isWinML: true
flcNugetDir: '$(Pipeline.Workspace)/flc-nuget-winml'
depsVersionsDir: '$(Pipeline.Workspace)/deps-versions-winml'
73 changes: 73 additions & 0 deletions .pipelines/templates/build-cpp-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Steps to package the C++ SDK source into a release archive.
# The archive contains headers, source, CMake config, and deps_versions.json
# so consumers can build from source with their own toolchain.
parameters:
- name: isWinML
type: boolean
default: false
- name: outputDir
type: string
default: '$(Build.ArtifactStagingDirectory)/cpp-sdk'
displayName: 'Path to directory for the packaged SDK'
- name: depsVersionsDir
type: string
default: ''
displayName: 'Path to deps-versions artifact directory'
steps:
# Set paths for multi-repo checkout
- task: PowerShell@2
displayName: 'Set source paths'
inputs:
targetType: inline
script: |
$multiCheckout = "$(Build.SourcesDirectory)/Foundry-Local"
if (Test-Path $multiCheckout) {
$repoRoot = $multiCheckout
} else {
$repoRoot = "$(Build.SourcesDirectory)"
}
Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot"

# Read version from the version-info artifact produced by compute_version stage.
- task: PowerShell@2
displayName: 'Set SDK version'
inputs:
targetType: inline
script: |
$v = (Get-Content "$(Pipeline.Workspace)/version-info/sdkVersion.txt" -Raw).Trim()
Write-Host "C++ SDK version: $v"

# Patch vcpkg.json version-string
$vcpkgPath = "$(repoRoot)/sdk/cpp/vcpkg.json"
$content = Get-Content $vcpkgPath -Raw
$content = $content -replace '"version-string"\s*:\s*"[^"]+"', "`"version-string`": `"$v`""
Set-Content -Path $vcpkgPath -Value $content

# Patch CMakeLists.txt project version (CMake only accepts MAJOR.MINOR.PATCH[.TWEAK])
$cmakeVer = ($v -split '-')[0]
$cmakePath = "$(repoRoot)/sdk/cpp/CMakeLists.txt"
$content = Get-Content $cmakePath -Raw
$content = $content -replace 'project\(CppSdk\s+VERSION\s+[^\s]+', "project(CppSdk VERSION $cmakeVer"
Set-Content -Path $cmakePath -Value $content

Write-Host "##vso[task.setvariable variable=cppSdkVersion]$v"

# Load dependency versions from deps_versions.json so the archive has correct versions
- template: update-deps-versions-steps.yml
parameters:
repoRoot: $(repoRoot)
artifactDir: ${{ parameters.depsVersionsDir }}
isWinML: ${{ parameters.isWinML }}

# Archive the SDK source tree for GitHub Releases
- task: PowerShell@2
displayName: 'Package SDK source'
inputs:
targetType: inline
script: |
$destDir = "${{ parameters.outputDir }}"
New-Item -ItemType Directory -Path $destDir -Force | Out-Null

$zipPath = "$destDir/foundry-local-cpp-sdk-$(cppSdkVersion).zip"
Compress-Archive -Path "$(repoRoot)/sdk/cpp/*" -DestinationPath $zipPath -Force
Write-Host "Packaged SDK source: $zipPath"
151 changes: 151 additions & 0 deletions .pipelines/templates/test-cpp-steps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Steps to test the C++ SDK.
# Runs unit tests (mocked, no Core DLL needed) and E2E tests (requires Core DLL).
parameters:
- name: isWinML
type: boolean
default: false
- name: flcNugetDir
type: string
displayName: 'Path to directory containing the FLC .nupkg'
- name: depsVersionsDir
type: string
default: ''
displayName: 'Path to deps-versions artifact directory'

steps:
- task: PowerShell@2
displayName: 'Set source paths'
inputs:
targetType: inline
script: |
$multiCheckout = "$(Build.SourcesDirectory)/Foundry-Local"
if (Test-Path $multiCheckout) {
$repoRoot = $multiCheckout
} else {
$repoRoot = "$(Build.SourcesDirectory)"
}
$testDataDir = "$(Build.SourcesDirectory)/test-data-shared"
Write-Host "##vso[task.setvariable variable=repoRoot]$repoRoot"
Write-Host "##vso[task.setvariable variable=testDataDir]$testDataDir"

# Load dependency versions from deps_versions.json
- template: update-deps-versions-steps.yml
parameters:
repoRoot: $(repoRoot)
artifactDir: ${{ parameters.depsVersionsDir }}
isWinML: ${{ parameters.isWinML }}

# Extract FLC native binaries from the pipeline-built .nupkg
- task: PowerShell@2
displayName: 'Extract FLC native binaries'
inputs:
targetType: inline
script: |
$nupkg = Get-ChildItem "${{ parameters.flcNugetDir }}" -Recurse -Filter "Microsoft.AI.Foundry.Local.Core*.nupkg" -Exclude "*.snupkg" | Select-Object -First 1
if (-not $nupkg) { throw "No FLC .nupkg found in ${{ parameters.flcNugetDir }}" }

$extractDir = "$(Build.ArtifactStagingDirectory)/flc-extract-cpp"
$zip = [System.IO.Path]::ChangeExtension($nupkg.FullName, ".zip")
Copy-Item $nupkg.FullName $zip -Force
Expand-Archive -Path $zip -DestinationPath $extractDir -Force

$arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq 'Arm64') { 'arm64' } else { 'x64' }
$rid = "win-$arch"

$nativeDir = "$extractDir/runtimes/$rid/native"
if (-not (Test-Path $nativeDir)) { throw "No native binaries found at $nativeDir for RID $rid" }

$flcNativeDir = "$(Build.ArtifactStagingDirectory)/flc-native-cpp"
New-Item -ItemType Directory -Path $flcNativeDir -Force | Out-Null
Get-ChildItem $nativeDir -File | Copy-Item -Destination $flcNativeDir -Force
Write-Host "##vso[task.setvariable variable=FOUNDRY_NATIVE_OVERRIDE_DIR]$flcNativeDir"
Write-Host "Extracted FLC native binaries to $flcNativeDir"

# Ensure vcpkg is available
- task: PowerShell@2
displayName: 'Bootstrap vcpkg'
inputs:
targetType: inline
script: |
if ($env:VCPKG_ROOT -and (Test-Path "$env:VCPKG_ROOT/vcpkg.exe")) {
Write-Host "vcpkg already available at $env:VCPKG_ROOT"
} else {
$vcpkgDir = "$(Build.ArtifactStagingDirectory)/vcpkg"
git clone https://github.com/microsoft/vcpkg.git $vcpkgDir
& "$vcpkgDir/bootstrap-vcpkg.bat" -disableMetrics
Write-Host "##vso[task.setvariable variable=VCPKG_ROOT]$vcpkgDir"
Write-Host "##vso[task.prependpath]$vcpkgDir"
Write-Host "Bootstrapped vcpkg at $vcpkgDir"
}

# Configure and build with tests enabled
- task: PowerShell@2
displayName: 'CMake configure'
inputs:
targetType: inline
script: |
Set-Location "$(repoRoot)/sdk/cpp"

$buildDir = "$(Build.ArtifactStagingDirectory)/cpp-test-build"

cmake -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-DVCPKG_OVERLAY_TRIPLETS="$(repoRoot)/sdk/cpp/triplets" `
-DVCPKG_OVERLAY_PORTS="$(repoRoot)/sdk/cpp/vcpkg-overlay-ports" `
-DVCPKG_TARGET_TRIPLET=x64-windows-static-md `
-DBUILD_TESTING=ON `
-B "$buildDir" `
-S "$(repoRoot)/sdk/cpp"
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
env:
PKG_CONFIG: 'echo'

- task: PowerShell@2
displayName: 'CMake build'
inputs:
targetType: inline
script: |
$buildDir = "$(Build.ArtifactStagingDirectory)/cpp-test-build"
cmake --build $buildDir --config Release
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

# Run unit tests (mocked — no Core DLL needed)
- task: PowerShell@2
displayName: 'Run unit tests'
inputs:
targetType: inline
script: |
$buildDir = "$(Build.ArtifactStagingDirectory)/cpp-test-build"
$testResultsDir = "$(Build.ArtifactStagingDirectory)/test-results"
New-Item -ItemType Directory -Path $testResultsDir -Force | Out-Null
Set-Location $buildDir

# Run only the unit test executable with JUnit XML output
& ./CppSdkTests --gtest_output=xml:$testResultsDir/unit-tests.xml
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

# Run E2E tests (requires Core DLL)
- task: PowerShell@2
displayName: 'Run E2E tests'
inputs:
targetType: inline
script: |
$buildDir = "$(Build.ArtifactStagingDirectory)/cpp-test-build"
$testResultsDir = "$(Build.ArtifactStagingDirectory)/test-results"
Set-Location $buildDir

& ./CppSdkE2ETests --gtest_output=xml:$testResultsDir/e2e-tests.xml
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
env:
TF_BUILD: 'true'
FOUNDRY_TEST_DATA_DIR: $(testDataDir)

# Publish test results
- task: PublishTestResults@2
displayName: 'Publish test results'
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '$(Build.ArtifactStagingDirectory)/test-results/*.xml'
testRunTitle: 'C++ SDK Tests'
failTaskOnFailedTests: true
condition: always()
Loading
Loading