From c37e7f2b487781fd26927e1181677b0cee56ee49 Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Fri, 27 Feb 2026 14:41:04 +0200 Subject: [PATCH 1/5] Add Windows ARM64 CPU support for TorchSharp Add support for building, packaging, and distributing TorchSharp on Windows ARM64 (CPU-only, no CUDA). This enables .NET developers on Windows ARM64 devices to use TorchSharp with the stable LibTorch 2.10.0 release. Key changes: - MSBuild: Add win-arm64 RID mapping, archive name, and cmake path (ARM64 archive has different layout: lib/ instead of libtorch/lib/) - Native build: Enable ARM64 cross-compilation from x64 via MSVC amd64_arm64 toolchain and CMake -A ARM64 - Runtime: Detect win-arm64 in Torch.cs nativeRid for correct native library loading - NuGet: Add libtorch-cpu-win-arm64 package and update libtorch-cpu meta-package - CI: Add Windows ARM64 PR validation and native build pipeline jobs (cross-compiled on x64 agents) - LibTorch: ARM64 uses armpl_lp64.dll (ARM Performance Libraries) instead of Intel OpenMP (libiomp5md.dll) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Directory.Build.props | 7 +- Directory.Build.targets | 10 ++ azure-pipelines.yml | 118 ++++++++++++++++++ .../libtorch-cpu-win-arm64.nupkgproj | 16 +++ pkg/libtorch-cpu/libtorch-cpu.nupkgproj | 1 + pkg/pack.proj | 2 + src/Native/build.cmd | 30 ++--- src/Native/gen-buildsys-win.bat | 3 +- src/Redist/libtorch-cpu/libtorch-cpu.proj | 11 +- ...rm64-shared-with-deps-2.10.0%2Bcpu.zip.sha | 1 + src/TorchSharp/Torch.cs | 3 +- 11 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 pkg/libtorch-cpu-win-arm64/libtorch-cpu-win-arm64.nupkgproj create mode 100644 src/Redist/libtorch-cpu/libtorch-win-arm64-shared-with-deps-2.10.0%2Bcpu.zip.sha diff --git a/Directory.Build.props b/Directory.Build.props index e8e44ee50..014fd9495 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -55,10 +55,12 @@ $(TargetOS)-$(TargetArchitecture) win-x64 + win-arm64 linux-x64 osx-arm64 win-x64 + win-arm64 linux-x64 osx-$(TargetArchitecture) @@ -141,6 +143,7 @@ cpu cu$(CudaVersionNoDot) libtorch-win-shared-with-deps$(LibTorchDebug) + libtorch-win-arm64-shared-with-deps$(LibTorchDebug) libtorch-shared-with-deps libtorch-macos-x86_64 libtorch-macos-arm64 @@ -148,7 +151,9 @@ $(LibTorchArchiveCoreName)-$(LibTorchVersion)$(LibTorchCudaArchiveNameSuffix) $(LibTorchArchiveCoreName)-$(LibTorchVersion)$(LibTorchCpuLocalNameSuffix) $(LibTorchArchiveCoreName)-$(LibTorchVersion)$(LibTorchCudaLocalNameSuffix) - $(IntermediateOutputRootPath)libtorch-cpu\$(LibTorchCpuLocalBase)\libtorch\share\cmake\Torch + $(IntermediateOutputRootPath)libtorch-cpu\$(LibTorchCpuLocalBase)\libtorch\share\cmake\Torch + + $(IntermediateOutputRootPath)libtorch-cpu\$(LibTorchCpuLocalBase)\share\cmake\Torch diff --git a/Directory.Build.targets b/Directory.Build.targets index 4ab3c814c..cc6bb3d4e 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -18,6 +18,16 @@ + + + + + + + + + + diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3a6a17a96..df20611ac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -89,6 +89,15 @@ jobs: pool: vmImage: 'macos-latest' +- template: /build/ci/job-template.yml + parameters: + prepScript: echo "no prep needed" + name: Windows_arm64 + buildScript: dotnet build /p:SkipCuda=true /p:TargetArchitecture=arm64 /p:SkipNetFxBuild=true -c + testScript: echo "Cannot run ARM64 tests on x64 Azure Pipelines agent" + pool: + vmImage: 'windows-latest' + ################################################################################ # {Build} --> combine --> package to build native bits on multiple OS's ################################################################################ @@ -285,6 +294,64 @@ jobs: - publish: $(Build.SourcesDirectory)/bin/obj/packprep/$(BuildConfig) artifact: MacAssets_arm64 +################################################################################ +- job: Windows_arm64_Native_Build_For_Packages +################################################################################ + condition: and(ne(variables['system.pullrequest.isfork'], true), eq(variables['build.sourcebranchname'], '${{ parameters.SourceBranchName }}')) + variables: + BuildConfig: Release + OfficialBuildId: $(BUILD.BUILDNUMBER) + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_MULTILEVEL_LOOKUP: 0 + pool: + vmImage: 'windows-latest' + steps: + # Initial cleanup + - script: | + rmdir /s /q .git 2>nul + dotnet nuget locals all --clear + dir + displayName: Initial cleanup + continueOnError: true + + - task: UseDotNet@2 + displayName: 'Use .NET Core sdk' + inputs: + packageType: sdk + version: 8.0.x + installationPath: $(Agent.ToolsDirectory)/dotnet + + # Download ARM64 LibTorch and clean immediately + - script: | + dotnet build -c $(BuildConfig) src/Redist/libtorch-cpu/libtorch-cpu.proj /p:UpdateSHA=true /p:SkipTests=true /p:TargetOS=windows /p:TargetArchitecture=arm64 /t:Build /p:IncludeLibTorchCpuPackages=true + del /s /q *.zip 2>nul + del /s /q *.tar.gz 2>nul + displayName: Download ARM64 libtorch native binaries and cleanup + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + + # Cross-compile LibTorchSharp for ARM64 on x64 host + - script: dotnet build -c $(BuildConfig) src/TorchSharp/TorchSharp.csproj /p:SkipCuda=true /p:SkipTests=true /p:TargetArchitecture=arm64 + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + displayName: Build TorchSharp win-arm64 + + - script: dotnet build -c $(BuildConfig) src/TorchVision/TorchVision.csproj /p:SkipCuda=true /p:SkipTests=true /p:TargetArchitecture=arm64 + displayName: Build TorchVision + + - script: dotnet build -c $(BuildConfig) src/TorchAudio/TorchAudio.csproj /p:SkipCuda=true /p:SkipTests=true /p:TargetArchitecture=arm64 + displayName: Build TorchAudio + + # Clean up unnecessary files before publishing + - script: | + del /s /q $(Build.SourcesDirectory)\bin\*.pdb 2>nul + del /s /q $(Build.SourcesDirectory)\bin\*.xml 2>nul + del /s /q $(Build.SourcesDirectory)\bin\obj\packprep\$(BuildConfig)\*.lib 2>nul + displayName: Clean up unnecessary files + continueOnError: true + + - publish: $(Build.SourcesDirectory)/bin/obj/packprep/$(BuildConfig) + artifact: WindowsAssets_arm64 + ################################################################################ - job: Build_TorchSharp_And_libtorch_cpu_Packages ################################################################################ @@ -292,6 +359,7 @@ jobs: dependsOn: - Linux_Native_Build_For_Packages - Windows_Native_Build_For_Packages + - Windows_arm64_Native_Build_For_Packages - MacOS_arm64_Native_Build_For_Packages timeoutInMinutes: 90 variables: @@ -496,6 +564,56 @@ jobs: displayName: Clean WindowsAssets immediately continueOnError: true + # Process Windows ARM64 assets + - task: DownloadPipelineArtifact@2 + displayName: Download Windows ARM64 TorchSharp assets + inputs: + artifact: WindowsAssets_arm64 + patterns: | + TorchSharp/** + path: $(Pipeline.Workspace)/WindowsAssets_arm64 + retryCountOnTaskFailure: 3 + + - task: DownloadPipelineArtifact@2 + displayName: Download Windows ARM64 TorchAudio assets + inputs: + artifact: WindowsAssets_arm64 + patterns: | + TorchAudio/** + path: $(Pipeline.Workspace)/WindowsAssets_arm64 + retryCountOnTaskFailure: 3 + + - task: DownloadPipelineArtifact@2 + displayName: Download Windows ARM64 TorchVision assets + inputs: + artifact: WindowsAssets_arm64 + patterns: | + TorchVision/** + path: $(Pipeline.Workspace)/WindowsAssets_arm64 + retryCountOnTaskFailure: 3 + + - task: DownloadPipelineArtifact@2 + displayName: Download Windows ARM64 libtorch-cpu assets + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + inputs: + artifact: WindowsAssets_arm64 + patterns: | + libtorch-cpu-win-arm64/** + path: $(Pipeline.Workspace)/WindowsAssets_arm64 + retryCountOnTaskFailure: 3 + continueOnError: true + + - task: CopyFiles@2 + displayName: Copy Windows ARM64 native assets (batch) + inputs: + sourceFolder: $(Pipeline.Workspace)/WindowsAssets_arm64 + targetFolder: $(Build.SourcesDirectory)/bin/obj/packprep/$(BuildConfig) + cleanTargetFolder: false + + - script: rmdir /s /q $(Pipeline.Workspace)\WindowsAssets_arm64 + displayName: Clean WindowsAssets_arm64 immediately + continueOnError: true + # Restore and pack - script: dotnet restore pkg/pack.proj /p:Configuration=Release --nologo displayName: Restore package projects diff --git a/pkg/libtorch-cpu-win-arm64/libtorch-cpu-win-arm64.nupkgproj b/pkg/libtorch-cpu-win-arm64/libtorch-cpu-win-arm64.nupkgproj new file mode 100644 index 000000000..d8ce731a6 --- /dev/null +++ b/pkg/libtorch-cpu-win-arm64/libtorch-cpu-win-arm64.nupkgproj @@ -0,0 +1,16 @@ + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/pkg/libtorch-cpu/libtorch-cpu.nupkgproj b/pkg/libtorch-cpu/libtorch-cpu.nupkgproj index 97c3ffe67..c35a3d5fc 100644 --- a/pkg/libtorch-cpu/libtorch-cpu.nupkgproj +++ b/pkg/libtorch-cpu/libtorch-cpu.nupkgproj @@ -7,6 +7,7 @@ + diff --git a/pkg/pack.proj b/pkg/pack.proj index 3c9db2f98..55474fdc6 100644 --- a/pkg/pack.proj +++ b/pkg/pack.proj @@ -24,6 +24,8 @@ Condition="'$(IncludeTorchSharpPackage)' == 'true' AND !Exists('$(PackagePreparationPath)\TorchSharp\runtimes\linux-x64\native\libLibTorchSharp.so')" /> + diff --git a/src/Native/build.cmd b/src/Native/build.cmd index c0c26c600..ef2b1bd84 100644 --- a/src/Native/build.cmd +++ b/src/Native/build.cmd @@ -23,6 +23,7 @@ if /i [%1] == [Debug] ( set CMAKE_BUILD_TYPE=Debug&&shift&goto Arg_Loop) if /i [%1] == [x86] ( set __BuildArch=x86&&set __VCBuildArch=x86&&shift&goto Arg_Loop) if /i [%1] == [x64] ( set __BuildArch=x64&&set __VCBuildArch=x86_amd64&&shift&goto Arg_Loop) if /i [%1] == [amd64] ( set __BuildArch=x64&&set __VCBuildArch=x86_amd64&&shift&goto Arg_Loop) +if /i [%1] == [arm64] ( set __BuildArch=ARM64&&set __VCBuildArch=amd64_arm64&&shift&goto Arg_Loop) if /i [%1] == [--libtorchpath] ( set LIBTORCH_PATH=%2&&shift&goto Arg_Loop) @@ -66,50 +67,39 @@ exit /b 1 :: Setup vars for VS2026 set __PlatformToolset=v145 set __VSVersion=18 2026 -if NOT "%__BuildArch%" == "arm64" ( - :: Set the environment for the native build - call "%VS180COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% -) +:: Set the environment for the native build (including cross-compilation for ARM64) +call "%VS180COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% goto :SetupDirs :VS2022 :: Setup vars for VS2022 set __PlatformToolset=v143 set __VSVersion=17 2022 -if NOT "%__BuildArch%" == "arm64" ( - :: Set the environment for the native build - call "%VS170COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% -) +:: Set the environment for the native build (including cross-compilation for ARM64) +call "%VS170COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% goto :SetupDirs :VS2019 :: Setup vars for VS2019 set __PlatformToolset=v142 set __VSVersion=16 2019 -if NOT "%__BuildArch%" == "arm64" ( - :: Set the environment for the native build - call "%VS160COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% -) +:: Set the environment for the native build (including cross-compilation for ARM64) +call "%VS160COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% goto :SetupDirs :VS2017 :: Setup vars for VS2017 set __PlatformToolset=v141 set __VSVersion=15 2017 -if NOT "%__BuildArch%" == "arm64" ( - :: Set the environment for the native build - call "%VS150COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% -) +:: Set the environment for the native build (including cross-compilation for ARM64) +call "%VS150COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% goto :SetupDirs :VS2015 :: Setup vars for VS2015build set __PlatformToolset=v140 set __VSVersion=14 2015 -if NOT "%__BuildArch%" == "arm64" ( - :: Set the environment for the native build - call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %__VCBuildArch% -) +call "%VS140COMNTOOLS%..\..\VC\vcvarsall.bat" %__VCBuildArch% :SetupDirs :: Setup to cmake the native components diff --git a/src/Native/gen-buildsys-win.bat b/src/Native/gen-buildsys-win.bat index b3870c171..c4a76bd4f 100644 --- a/src/Native/gen-buildsys-win.bat +++ b/src/Native/gen-buildsys-win.bat @@ -30,6 +30,7 @@ popd :: Set the target architecture to a format cmake understands. if /i "%3" == "x64" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A x64) if /i "%3" == "x86" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A Win32) +if /i "%3" == "ARM64" (set __ExtraCmakeParams=%__ExtraCmakeParams% -A ARM64) echo "%CMakePath%" "-DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DLIBTORCH_PATH=%LIBTORCH_PATH%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% -B. -H%1 "%CMakePath%" "-DCMAKE_BUILD_TYPE=%CMAKE_BUILD_TYPE%" "-DCMAKE_INSTALL_PREFIX=%__CMakeBinDir%" "-DLIBTORCH_PATH=%LIBTORCH_PATH%" -G "Visual Studio %__VSString%" %__ExtraCmakeParams% -B. -H%1 @@ -40,7 +41,7 @@ GOTO :DONE echo "Usage..." echo "gen-buildsys-win.bat " echo "Specify the VSVersion to be used - VS2015, VS2017 or VS2019" - echo "Specify the Target Architecture - x86, or x64." + echo "Specify the Target Architecture - x86, x64, or ARM64." EXIT /B 1 :DONE diff --git a/src/Redist/libtorch-cpu/libtorch-cpu.proj b/src/Redist/libtorch-cpu/libtorch-cpu.proj index adc8ba013..c082675ee 100644 --- a/src/Redist/libtorch-cpu/libtorch-cpu.proj +++ b/src/Redist/libtorch-cpu/libtorch-cpu.proj @@ -30,7 +30,7 @@ $(MainPackageFolder)\.copied.SkipTests.$(SkipTests).IncludeLibTorchCpuPackages.$(IncludeLibTorchCpuPackages) - + @@ -39,6 +39,15 @@ + + + + + + + + + diff --git a/src/Redist/libtorch-cpu/libtorch-win-arm64-shared-with-deps-2.10.0%2Bcpu.zip.sha b/src/Redist/libtorch-cpu/libtorch-win-arm64-shared-with-deps-2.10.0%2Bcpu.zip.sha new file mode 100644 index 000000000..f50bc08ff --- /dev/null +++ b/src/Redist/libtorch-cpu/libtorch-win-arm64-shared-with-deps-2.10.0%2Bcpu.zip.sha @@ -0,0 +1 @@ +38d666a9030ba098d1ac5dabfd995cf3d113a12d512252080978b0cc206af205 \ No newline at end of file diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index dd7a07689..c7e6dd608 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -38,7 +38,8 @@ public static partial class torch RuntimeInformation.OSArchitecture == Architecture.Arm64; static string nativeRid => - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? $"win-x64" : + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? (RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "win-arm64" : "win-x64") : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? $"linux-x64" : isAppleSilicon ? "osx-arm64" : "any"; From a7dd6635bd224972e980598ef43990ec3c5b3a3e Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Wed, 11 Mar 2026 15:47:51 +0100 Subject: [PATCH 2/5] Address PR review feedback for ARM64 support - Use ProcessArchitecture instead of OSArchitecture for nativeRid to correctly handle x64 emulation on ARM64 Windows - Add missing '-c Release' configuration to Windows_arm64 CI job - Consolidate duplicate TargetRuntimeID blocks into single block with mutually exclusive conditions - Update VS version list in gen-buildsys-win.bat usage text to include VS2022 and VS2026 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Directory.Build.props | 7 +------ azure-pipelines.yml | 2 +- src/Native/gen-buildsys-win.bat | 2 +- src/TorchSharp/Torch.cs | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 014fd9495..b4cf70432 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -54,12 +54,7 @@ $(TargetOS)-$(TargetArchitecture) - win-x64 - win-arm64 - linux-x64 - osx-arm64 - - win-x64 + win-x64 win-arm64 linux-x64 osx-$(TargetArchitecture) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index df20611ac..93592674b 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -93,7 +93,7 @@ jobs: parameters: prepScript: echo "no prep needed" name: Windows_arm64 - buildScript: dotnet build /p:SkipCuda=true /p:TargetArchitecture=arm64 /p:SkipNetFxBuild=true -c + buildScript: dotnet build /p:SkipCuda=true /p:TargetArchitecture=arm64 /p:SkipNetFxBuild=true -c Release testScript: echo "Cannot run ARM64 tests on x64 Azure Pipelines agent" pool: vmImage: 'windows-latest' diff --git a/src/Native/gen-buildsys-win.bat b/src/Native/gen-buildsys-win.bat index c4a76bd4f..f58139e92 100644 --- a/src/Native/gen-buildsys-win.bat +++ b/src/Native/gen-buildsys-win.bat @@ -40,7 +40,7 @@ GOTO :DONE :USAGE echo "Usage..." echo "gen-buildsys-win.bat " - echo "Specify the VSVersion to be used - VS2015, VS2017 or VS2019" + echo "Specify the VSVersion to be used - VS2015, VS2017, VS2019, VS2022, or VS2026" echo "Specify the Target Architecture - x86, x64, or ARM64." EXIT /B 1 diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index c7e6dd608..7dbc42ecd 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -39,7 +39,7 @@ public static partial class torch static string nativeRid => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? (RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "win-arm64" : "win-x64") : + ? (RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "win-arm64" : "win-x64") : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? $"linux-x64" : isAppleSilicon ? "osx-arm64" : "any"; From 2b1674aa12540d6426641c5e56f8a011d99ba4fd Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Thu, 12 Mar 2026 10:11:32 +0100 Subject: [PATCH 3/5] Fix Windows ARM64 CI build: remove duplicate Release config The job template appends \ to buildScript, so including 'Release' after '-c' resulted in 'dotnet build ... -c Release Release', where the trailing 'Release' was interpreted as a project path (MSB1009). Remove the explicit 'Release' so the template provides it, matching the pattern used by the MacOS_arm64 job. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 93592674b..df20611ac 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -93,7 +93,7 @@ jobs: parameters: prepScript: echo "no prep needed" name: Windows_arm64 - buildScript: dotnet build /p:SkipCuda=true /p:TargetArchitecture=arm64 /p:SkipNetFxBuild=true -c Release + buildScript: dotnet build /p:SkipCuda=true /p:TargetArchitecture=arm64 /p:SkipNetFxBuild=true -c testScript: echo "Cannot run ARM64 tests on x64 Azure Pipelines agent" pool: vmImage: 'windows-latest' From 33b4855b5d5f1178c6e79be53c844d2e84a86391 Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Wed, 18 Mar 2026 14:09:32 +0100 Subject: [PATCH 4/5] Preload ARM64 native dependencies for NuGet package loading Add preloading of ARM Performance Libraries and other libtorch dependencies on Windows ARM64 before loading torch_cpu.dll and LibTorchSharp.dll. This fixes native library resolution when consuming TorchSharp from NuGet packages, where implicit DLL dependencies cannot be found in the NuGet cache directory. Follows the same pattern as the existing CUDA DLL preloading. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/TorchSharp/Torch.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/TorchSharp/Torch.cs b/src/TorchSharp/Torch.cs index 7dbc42ecd..86ec78d7a 100644 --- a/src/TorchSharp/Torch.cs +++ b/src/TorchSharp/Torch.cs @@ -154,6 +154,19 @@ private static void LoadNativeBackend(bool useCudaBackend, out StringBuilder? tr ok = TryLoadNativeLibraryByName("torch_cuda", typeof(torch).Assembly, trace); ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } else { + var isWindowsArm64 = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + if (isWindowsArm64) { + trace.AppendLine($" Try loading Windows ARM64 native components"); + // Preloading these DLLs on Windows ARM64 ensures dependencies are resolved + // when loading from NuGet package directories, similar to the CUDA preloading above. + // ARM64 libtorch uses ARM Performance Libraries instead of Intel OpenMP. + ok = TryLoadNativeLibraryByName("armpl_lp64", typeof(torch).Assembly, trace); + ok = TryLoadNativeLibraryByName("uv", typeof(torch).Assembly, trace); + ok = TryLoadNativeLibraryByName("c10", typeof(torch).Assembly, trace); + ok = TryLoadNativeLibraryByName("torch_global_deps", typeof(torch).Assembly, trace); + } + ok = TryLoadNativeLibraryByName("torch_cpu", typeof(torch).Assembly, trace); ok = TryLoadNativeLibraryByName("LibTorchSharp", typeof(torch).Assembly, trace); } From 760048fc5fe6eba614dec6a5f9c1ee1598f91693 Mon Sep 17 00:00:00 2001 From: alinpahontu2912 Date: Thu, 19 Mar 2026 14:51:23 +0100 Subject: [PATCH 5/5] Fix CI disk space exhaustion during CUDA libtorch download Add aggressive disk cleanup steps to prevent out-of-memory failures when downloading and extracting large PyTorch 2.10.0 CUDA binaries: - Linux: Remove .git dir and clear NuGet cache in initial cleanup (matching existing Windows behavior) - Both platforms: Delete CPU intermediate extraction dir and downloads before starting CUDA download - Both platforms: Delete CUDA intermediate extraction dir and downloads after CUDA build completes Only intermediate build directories are removed; the final packprep output used for publish artifacts is preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- azure-pipelines.yml | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index df20611ac..839dcd300 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -117,8 +117,10 @@ jobs: vmImage: 'ubuntu-latest' container: UbuntuContainer steps: - # Initial cleanup + # Initial cleanup - free as much disk space as possible - script: | + rm -rf .git + dotnet nuget locals all --clear 2>/dev/null || true rm -rf bin/obj find . -name "*.pdb" -type f -delete find . -name "*.xml" -type f -delete @@ -145,6 +147,15 @@ jobs: condition: eq('${{ parameters.BuildLibTorchPackages }}', true) displayName: Download libtorch native binaries and cleanup archives + # Free intermediate space before CUDA download + - script: | + rm -rf bin/obj/AnyCPU.$(BuildConfig)/libtorch-cpu + rm -rf bin/downloads + df -h + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + displayName: Free disk space before CUDA download + continueOnError: true + # Build libtorch CUDA and clean immediately - script: | dotnet build -c $(BuildConfig) src/Redist/libtorch-cuda-12.8/libtorch-cuda-12.8.proj /p:UpdateSHA=true /p:SkipTests=true /p:TargetOS=linux /t:Build /p:IncludeLibTorchCudaPackages=true @@ -154,6 +165,15 @@ jobs: condition: eq('${{ parameters.BuildLibTorchPackages }}', true) displayName: Download libtorch CUDA binaries and cleanup archives + # Free intermediate space after CUDA build + - script: | + rm -rf bin/obj/AnyCPU.$(BuildConfig)/libtorch-cuda-12.8 + rm -rf bin/downloads + df -h + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + displayName: Free disk space after CUDA build + continueOnError: true + - script: dotnet build -c $(BuildConfig) src/TorchSharp/TorchSharp.csproj /p:SkipCuda=true /p:SkipTests=true displayName: Build TorchSharp @@ -211,6 +231,15 @@ jobs: displayName: Download libtorch native binaries and cleanup condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + # Free intermediate space before CUDA download + - script: | + rmdir /s /q bin\obj\AnyCPU.$(BuildConfig)\libtorch-cpu 2>nul + rmdir /s /q bin\downloads 2>nul + dir + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + displayName: Free disk space before CUDA download + continueOnError: true + # Build libtorch CUDA and clean immediately - script: | dotnet build -c $(BuildConfig) src/Redist/libtorch-cuda-12.8/libtorch-cuda-12.8.proj /p:UpdateSHA=true /p:SkipTests=true /p:TargetOS=windows /t:Build /p:IncludeLibTorchCudaPackages=true @@ -219,6 +248,14 @@ jobs: condition: eq('${{ parameters.BuildLibTorchPackages }}', true) displayName: Download libtorch CUDA binaries and cleanup + # Free intermediate space after CUDA build + - script: | + rmdir /s /q bin\obj\AnyCPU.$(BuildConfig)\libtorch-cuda-12.8 2>nul + rmdir /s /q bin\downloads 2>nul + condition: eq('${{ parameters.BuildLibTorchPackages }}', true) + displayName: Free disk space after CUDA build + continueOnError: true + - script: dotnet build -c $(BuildConfig) src/TorchSharp/TorchSharp.csproj /p:SkipCuda=true /p:SkipTests=true condition: eq('${{ parameters.BuildLibTorchPackages }}', true) displayName: Build TorchSharp