diff --git a/.pipelines/nuget-publishing.yml b/.pipelines/nuget-publishing.yml index 22ec44677..1888d1234 100644 --- a/.pipelines/nuget-publishing.yml +++ b/.pipelines/nuget-publishing.yml @@ -38,6 +38,11 @@ parameters: type: boolean default: true +- name: enable_android + displayName: 'Whether Android AAR package is built.' + type: boolean + default: true + - name: enable_apple_framework displayName: 'Whether Apple framework for iOS & MacCatalyst is built.' type: boolean @@ -94,6 +99,7 @@ stages: enable_win_dml: ${{ parameters.enable_win_dml }} enable_win_arm64: ${{ parameters.enable_win_arm64 }} enable_macos_cpu: ${{ parameters.enable_macos_cpu }} + enable_android: ${{ parameters.enable_android }} enable_apple_framework: ${{ parameters.enable_apple_framework }} ort_version: ${{ parameters.ort_version }} ort_cuda_version: ${{ parameters.ort_cuda_version }} @@ -110,6 +116,7 @@ stages: enable_win_dml: ${{ parameters.enable_win_dml }} enable_win_arm64: ${{ parameters.enable_win_arm64 }} enable_macos_cpu: ${{ parameters.enable_macos_cpu }} + enable_android: ${{ parameters.enable_android }} enable_apple_framework: ${{ parameters.enable_apple_framework }} ort_version: ${{ parameters.ort_version }} ort_cuda_version: ${{ parameters.ort_cuda_version }} diff --git a/.pipelines/stages/capi-packaging-stage.yml b/.pipelines/stages/capi-packaging-stage.yml index add22efa9..a4aa477c9 100644 --- a/.pipelines/stages/capi-packaging-stage.yml +++ b/.pipelines/stages/capi-packaging-stage.yml @@ -13,6 +13,8 @@ parameters: type: boolean - name: enable_macos_cpu type: boolean +- name: enable_android + type: boolean - name: enable_apple_framework type: boolean - name: ort_version @@ -114,6 +116,12 @@ stages: os: 'osx' build_config: ${{ parameters.build_config }} + - ${{ if eq(parameters.enable_android, true) }}: + - template: jobs/android-java-api-aar.yml + parameters: + ort_version: ${{ parameters.ort_version }} + build_config: ${{ parameters.build_config }} + - ${{ if eq(parameters.enable_apple_framework, true) }}: - template: jobs/capi-packaging-job.yml parameters: diff --git a/.pipelines/stages/jobs/android-java-api-aar.yml b/.pipelines/stages/jobs/android-java-api-aar.yml index fface352e..f9b145308 100644 --- a/.pipelines/stages/jobs/android-java-api-aar.yml +++ b/.pipelines/stages/jobs/android-java-api-aar.yml @@ -26,15 +26,18 @@ jobs: - template: steps/utils/use-android-ndk.yml - template: steps/utils/set-genai-version.yml + - template: steps/utils/set-cmake-build-type.yml + parameters: + build_config: ${{parameters.build_config}} - task: CmdLine@2 displayName: Build Android AAR Packages inputs: script: | set -e -x - + BUILD_DIR=$(Build.BinariesDirectory) - BUILD_CONFIG=${{parameters.build_config}} + BUILD_CONFIG=$(cmake_build_type) GENAI_VERSION=$(genai_version) PACKAGE_NAME=${{parameters.package_name}} ARTIFACTS_DIR=$(Build.ArtifactStagingDirectory) diff --git a/.pipelines/stages/jobs/nuget-packaging-job.yml b/.pipelines/stages/jobs/nuget-packaging-job.yml index efa71e52b..1be6a9cd2 100644 --- a/.pipelines/stages/jobs/nuget-packaging-job.yml +++ b/.pipelines/stages/jobs/nuget-packaging-job.yml @@ -37,6 +37,11 @@ parameters: type: boolean default: false +- name: enable_android + displayName: 'Whether Android AAR package is built.' + type: boolean + default: false + - name: enable_apple_framework displayName: 'Whether Apple framework for iOS & MacCatalyst is built.' type: boolean @@ -153,6 +158,20 @@ jobs: ArtifactName: onnxruntime-genai-osx-cpu-arm64-capi TargetPath: '$(Build.BinariesDirectory)/artifact-downloads' + - ${{ if eq(parameters.enable_apple_framework, true) }}: + - template: steps/utils/flex-download-pipeline-artifact.yml + parameters: + StepName: 'Download iOS XCFramework Artifacts' + ArtifactName: onnxruntime-genai-ios-xcframework + TargetPath: '$(Build.BinariesDirectory)/artifact-downloads' + + - ${{ if eq(parameters.enable_android, true) }}: + - template: steps/utils/flex-download-pipeline-artifact.yml + parameters: + StepName: 'Download Android AAR Artifacts' + ArtifactName: drop-android + TargetPath: '$(Build.BinariesDirectory)/artifact-downloads' + - checkout: self path: onnxruntime-genai clean: true @@ -162,7 +181,7 @@ jobs: - powershell: | dotnet --info - dotnet build Microsoft.ML.OnnxRuntimeGenAI.csproj -p:Configuration="$(buildConfig)" --verbosity normal + dotnet build Microsoft.ML.OnnxRuntimeGenAI.csproj -p:Configuration="$(buildConfig)" -p:IncludeMobileTargets=true --verbosity normal displayName: 'Build CSharp' workingDirectory: '$(Build.Repository.LocalPath)\src\csharp' @@ -181,10 +200,12 @@ jobs: - powershell: | $artifacts_dir = '$(Build.BinariesDirectory)/artifact-downloads' Write-Host "List downloaded artifacts" - $artifacts = Get-ChildItem -Path $artifacts_dir/* -Include *.zip,*.tar.gz + $artifacts = Get-ChildItem -Path $artifacts_dir/* -Include *.zip,*.tar.gz,*.aar Write-Host $artifacts $outputDir = '$(Build.Repository.LocalPath)/$(buildDir)' + Write-Host "List extracted artifacts" + Get-ChildItem -Path $nativeBuildOutputDir -Recurse mkdir -Force $outputDir foreach ($file in $artifacts) { @@ -195,28 +216,42 @@ jobs: $rid = $Matches.1 } else { - Write-Host "Invalid artifact name" $file - return + $rid_match = $a -match "onnxruntime-genai-(android|ios)-$(genai_version)(.+?)?(\.zip|\.aar)" + if ($rid_match) { + $rid = $Matches.1 + } + else { + Write-Host "Invalid artifact name" $file + return + } } - mkdir -Force $outputDir/$rid - if ($a -like "*.zip") { - Expand-Archive -Path $file -DestinationPath $outputDir/$rid + mkdir -Force $outputDir/$rid + mkdir -Force $outputDir/$rid/$(buildConfig) + if ($rid -like "ios") { + Move-Item $file $outputDir/$rid/$(buildConfig)/onnxruntime-genai.xcframework.zip + } + elseif ($a -like "*.aar") { + Move-Item $file $outputDir/$rid/$(buildConfig)/onnxruntime-genai.aar } - elseif ($a -like "*.tar.gz") { - tar -xf $file -C $outputDir/$rid + else { + if ($a -like "*.zip") { + Expand-Archive -Path $file -DestinationPath $outputDir/$rid + } + elseif ($a -like "*.tar.gz") { + tar -xf $file -C $outputDir/$rid + } } - mkdir -Force $outputDir/$rid/$(buildConfig) $b = $file.Basename $b = $b -split '.tar' $b = $b[0] - Move-Item $outputDir/$rid/$b/lib/* $outputDir/$rid/$(buildConfig) -Force + if (Test-Path $outputDir/$rid/$b/lib/) { + Move-Item $outputDir/$rid/$b/lib/* $outputDir/$rid/$(buildConfig) -Force + } + Get-ChildItem -Path $outputDir/$rid -Recurse } - Write-Host "List extracted artifacts" - Get-ChildItem -Path $nativeBuildOutputDir -Recurse - displayName: 'Extract Artifacts & Prepare Native Libraries' workingDirectory: '$(Build.BinariesDirectory)/artifact-downloads' diff --git a/.pipelines/stages/jobs/steps/capi-appleframework-step.yml b/.pipelines/stages/jobs/steps/capi-appleframework-step.yml index d3bef23c0..1970812ed 100644 --- a/.pipelines/stages/jobs/steps/capi-appleframework-step.yml +++ b/.pipelines/stages/jobs/steps/capi-appleframework-step.yml @@ -22,12 +22,12 @@ steps: tools/ci_build/github/apple/default_full_ios_framework_build_settings.json mkdir $(Build.BinariesDirectory)/artifacts - mkdir -p $(Build.BinariesDirectory)/artifacts_staging/onnxruntime-genai-ios-xcframework-$(genai_version) + mkdir -p $(Build.BinariesDirectory)/artifacts_staging/onnxruntime-genai.xcframework cp -R $(Build.BinariesDirectory)/apple_framework/framework_out/onnxruntime-genai.xcframework \ - $(Build.BinariesDirectory)/artifacts_staging/onnxruntime-genai-ios-xcframework-$(genai_version) + $(Build.BinariesDirectory)/artifacts_staging/ pushd $(Build.BinariesDirectory)/artifacts_staging - zip -vr $(Build.BinariesDirectory)/artifacts/onnxruntime_genai_ios_xcframework.zip \ - onnxruntime-genai-ios-xcframework-$(genai_version) + zip -vr $(Build.BinariesDirectory)/artifacts/onnxruntime-genai-ios-$(genai_version).zip \ + onnxruntime-genai.xcframework popd displayName: 'Build Apple XCFramework' workingDirectory: '$(Build.Repository.LocalPath)' @@ -35,5 +35,5 @@ steps: - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact: ONNXRuntime GenAI XCFramework' inputs: - ArtifactName: capi-onnxruntime-genai-ios-xcframework + ArtifactName: onnxruntime-genai-ios-xcframework PathtoPublish: '$(Build.BinariesDirectory)/artifacts' diff --git a/.pipelines/stages/jobs/steps/utils/set-cmake-build-type.yml b/.pipelines/stages/jobs/steps/utils/set-cmake-build-type.yml new file mode 100644 index 000000000..077fd2337 --- /dev/null +++ b/.pipelines/stages/jobs/steps/utils/set-cmake-build-type.yml @@ -0,0 +1,23 @@ +parameters: +- name: build_config + type: string +steps: +- task: PowerShell@2 + displayName: 'Set CMake Build Type' + inputs: + workingDirectory: $(Build.SourcesDirectory) + targetType: inline + script: | + $chosen_build_config = "${{ parameters.build_config }}" + $cmake_build_type = $chosen_build_config; + if ($chosen_build_config -eq "release") { + $cmake_build_type = "Release" + } + elseif ($chosen_build_config -eq "relwithdebinfo") { + $cmake_build_type = "RelWithDebInfo" + } + elseif ($chosen_build_config -eq "debug") { + $cmake_build_type = "Debug" + } + Write-Host "Current build type: $cmake_build_type" + Write-Host "##vso[task.setvariable variable=cmake_build_type]$cmake_build_type" \ No newline at end of file diff --git a/.pipelines/stages/nuget-packaging-stage.yml b/.pipelines/stages/nuget-packaging-stage.yml index 9122b2459..9d869f382 100644 --- a/.pipelines/stages/nuget-packaging-stage.yml +++ b/.pipelines/stages/nuget-packaging-stage.yml @@ -34,10 +34,15 @@ parameters: type: boolean default: true +- name: enable_android + displayName: 'Whether Android AAR package is built.' + type: boolean + default: true + - name: enable_apple_framework displayName: 'Whether Apple framework for iOS & MacCatalyst is built.' type: boolean - default: false + default: true - name: ort_version type: string @@ -62,6 +67,7 @@ stages: enable_win_cpu: ${{ parameters.enable_win_cpu }} enable_win_arm64: ${{ parameters.enable_win_arm64 }} enable_macos_cpu: ${{ parameters.enable_macos_cpu }} + enable_android: ${{ parameters.enable_android }} enable_apple_framework: ${{ parameters.enable_apple_framework }} - ${{ if or(eq(parameters.enable_linux_cuda, true), eq(parameters.enable_win_cuda, true)) }}: - template: jobs/nuget-packaging-job.yml @@ -74,7 +80,7 @@ stages: - ${{ if eq(parameters.enable_win_dml, true) }}: - template: jobs/nuget-packaging-job.yml parameters: - ep: 'directml' + ep: 'directml' ort_version: ${{ parameters.ort_dml_version }} build_config: ${{ parameters.build_config }} enable_win_dml: ${{ parameters.enable_win_dml }} diff --git a/nuget/Microsoft.ML.OnnxRuntimeGenAI.Managed.nuspec b/nuget/Microsoft.ML.OnnxRuntimeGenAI.Managed.nuspec index f4d06bc0a..1bd50e0fc 100644 --- a/nuget/Microsoft.ML.OnnxRuntimeGenAI.Managed.nuspec +++ b/nuget/Microsoft.ML.OnnxRuntimeGenAI.Managed.nuspec @@ -15,6 +15,9 @@ + + + @@ -27,6 +30,16 @@ + + + + + + + + + + diff --git a/nuget/targets/net8.0-android/Microsoft.ML.OnnxRuntimeGenAI.targets b/nuget/targets/net8.0-android/Microsoft.ML.OnnxRuntimeGenAI.targets new file mode 100644 index 000000000..a5b44939c --- /dev/null +++ b/nuget/targets/net8.0-android/Microsoft.ML.OnnxRuntimeGenAI.targets @@ -0,0 +1,8 @@ + + + + + %(Filename)%(Extension) + + + \ No newline at end of file diff --git a/nuget/targets/net8.0-ios/Microsoft.ML.OnnxRuntimeGenAI.targets b/nuget/targets/net8.0-ios/Microsoft.ML.OnnxRuntimeGenAI.targets new file mode 100644 index 000000000..d90112963 --- /dev/null +++ b/nuget/targets/net8.0-ios/Microsoft.ML.OnnxRuntimeGenAI.targets @@ -0,0 +1,13 @@ + + + + + Static + True + True + True + -lc++ + CoreML + + + \ No newline at end of file diff --git a/nuget/targets/net8.0-maccatalyst/README.md b/nuget/targets/net8.0-maccatalyst/README.md new file mode 100644 index 000000000..ef91f0f7c --- /dev/null +++ b/nuget/targets/net8.0-maccatalyst/README.md @@ -0,0 +1,3 @@ +### Notes for maccatalyst .NET targets: + +We only add a blank file for the target framework folder here and thus will be including blank TFM under build/ and buildTransitive/ in the Nuget package. The reason is for Mac Catalyst platform, it directly will resolve the xcframework from the runtimes/native/ios folder based on this [RuntimeidentifierGraph](https://github.com/dotnet/sdk/blob/main/src/Layout/redist/PortableRuntimeIdentifierGraph.json#L300-L304) diff --git a/nuget/targets/net8.0-maccatalyst/_._ b/nuget/targets/net8.0-maccatalyst/_._ new file mode 100644 index 000000000..e69de29bb diff --git a/nuget/targets/Microsoft.ML.OnnxRuntimeGenAI.props b/nuget/targets/netstandard/Microsoft.ML.OnnxRuntimeGenAI.props similarity index 100% rename from nuget/targets/Microsoft.ML.OnnxRuntimeGenAI.props rename to nuget/targets/netstandard/Microsoft.ML.OnnxRuntimeGenAI.props diff --git a/nuget/targets/Microsoft.ML.OnnxRuntimeGenAI.targets b/nuget/targets/netstandard/Microsoft.ML.OnnxRuntimeGenAI.targets similarity index 100% rename from nuget/targets/Microsoft.ML.OnnxRuntimeGenAI.targets rename to nuget/targets/netstandard/Microsoft.ML.OnnxRuntimeGenAI.targets diff --git a/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.csproj b/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.csproj index a17d999a0..ee53c83fb 100644 --- a/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.csproj +++ b/src/csharp/Microsoft.ML.OnnxRuntimeGenAI.csproj @@ -1,6 +1,16 @@  - net8.0;netstandard2.0 + false + net8.0;netstandard2.0; + + + + + net8.0-android;net8.0-ios;net8.0-maccatalyst + + + + $(BaseTargets);$(MobileTargets) AnyCPU default true @@ -22,6 +32,16 @@ true true true + + + true + true + true @@ -68,6 +88,22 @@ + + $(OrtConstants);__MOBILE__ + + + + $(OrtConstants);__ANDROID__ + + + + $(OrtConstants);__IOS__ + + + + $(DefineConstants);$(OrtConstants) + + diff --git a/src/csharp/NativeMethods.cs b/src/csharp/NativeMethods.cs index 431b8e8cc..20b368c82 100644 --- a/src/csharp/NativeMethods.cs +++ b/src/csharp/NativeMethods.cs @@ -10,7 +10,15 @@ internal static class NativeMethods { internal class NativeLib { +#if __ANDROID__ + // define the library name required for android + internal const string DllName = "libonnxruntime-genai.so"; +#elif __IOS__ + // define the library name required for iOS + internal const string DllName = "__Internal"; +#else internal const string DllName = "onnxruntime-genai"; +#endif } // The returned pointer is owned by the OgaResult object and will be freed when the OgaResult @@ -73,7 +81,7 @@ internal class NativeLib [DllImport(NativeLib.DllName, CallingConvention = CallingConvention.Winapi)] public static extern IntPtr /* OgaResult* */ OgaGeneratorParamsSetModelInput(IntPtr /* OgaGeneratorParams* */ generatorParams, - byte[] /* const char* */ name, + byte[] /* const char* */ name, IntPtr /* const OgaTensor* */ tensor); [DllImport(NativeLib.DllName, CallingConvention = CallingConvention.Winapi)] diff --git a/tools/ci_build/github/android/build_aar_package.py b/tools/ci_build/github/android/build_aar_package.py index 2151acabb..8b3b339ac 100644 --- a/tools/ci_build/github/android/build_aar_package.py +++ b/tools/ci_build/github/android/build_aar_package.py @@ -72,7 +72,7 @@ def _parse_build_settings(args): if build_settings["android_min_sdk_version"] > build_settings["android_target_sdk_version"]: raise ValueError( - f"android_min_sdk_version {build_settings['android_min_sdk_version']} cannot be larger than " + f"android_min_sdk_version {build_settings['android_min_sdk_version']} cannot be larger than " f"android_target_sdk_version {build_settings['android_target_sdk_version']}" ) @@ -95,9 +95,10 @@ def _build_aar(args): build_config = args.config aar_dir = intermediates_dir / "aar" / build_config jnilibs_dir = intermediates_dir / "jnilibs" / build_config - base_build_command = ([sys.executable, str(BUILD_PY), - f"--config={build_config}", f"--ort_home={str(args.ort_home)}"] + - build_settings["build_params"]) + base_build_command = [sys.executable, str(BUILD_PY), f"--config={build_config}"] + if args.ort_home: + base_build_command += [f"--ort_home={str(args.ort_home)}"] + base_build_command += build_settings["build_params"] header_files_path = None @@ -181,7 +182,7 @@ def parse_args(): help="Configuration to build.", ) - parser.add_argument("--ort_home", type=Path, default=REPO_ROOT / "ort", + parser.add_argument("--ort_home", type=Path, default=None, help="Path to an unzipped onnxruntime AAR.") parser.add_argument( diff --git a/tools/nuget/generate_nuspec_for_native_nuget.py b/tools/nuget/generate_nuspec_for_native_nuget.py index ba464add6..00b7dfd08 100644 --- a/tools/nuget/generate_nuspec_for_native_nuget.py +++ b/tools/nuget/generate_nuspec_for_native_nuget.py @@ -97,7 +97,7 @@ def generate_release_notes(line_list): def generate_dependencies(xml_text, package_version, ort_package_name, ort_package_version): xml_text.append("") - target_frameworks = ["NETSTANDARD" , "NETCOREAPP", "NETFRAMEWORK"] + target_frameworks = ["NETSTANDARD" , "NETCOREAPP", "NETFRAMEWORK", "net8.0-android31.0", "net8.0-ios15.4", "net8.0-maccatalyst14.0"] for framework in target_frameworks: xml_text.append(f'') xml_text.append(f'') @@ -122,23 +122,37 @@ def add_native_artifact_if_exists(xml_lines, runtime, artifact): f'' ) - runtimes = ["win-x64", "win-arm64", "linux-x64", "osx-x64", "osx-arm64"] + runtimes = ["win-x64", "win-arm64", "linux-x64", "osx-x64", "osx-arm64", "ios", "android"] for runtime in runtimes: if runtime.startswith("win"): add_native_artifact_if_exists(lines, runtime, "onnxruntime-genai.lib") add_native_artifact_if_exists(lines, runtime, "onnxruntime-genai.dll") add_native_artifact_if_exists(lines, runtime, "d3d12core.dll") - if runtime.startswith("linux"): + elif runtime.startswith("linux"): add_native_artifact_if_exists(lines, runtime, "libonnxruntime-genai.so") - if runtime.startswith("osx"): + elif runtime.startswith("osx"): add_native_artifact_if_exists(lines, runtime, "libonnxruntime-genai.dylib") + elif runtime.startswith("ios"): + add_native_artifact_if_exists(lines, runtime, "onnxruntime-genai.xcframework.zip") + elif runtime.startswith("android"): + add_native_artifact_if_exists(lines, runtime, "onnxruntime-genai.aar") # targets for dotnet in ["netstandard2.0", "net8.0", "native"]: - lines.append(f'') - lines.append(f'') - # include + lines.append(f'') + lines.append(f'') + + # mobile targets + lines.append(f'') + lines.append(f'') + + lines.append(f'') + lines.append(f'') + lines.append(f'') + lines.append(f'') + + # include lines.append(f'') lines.append('')