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";