Skip to content

Commit 14fe97c

Browse files
authored
Merge pull request #1888 from shimat/feat/1743-windows-arm64
Add Windows ARM64 support (OpenCvSharp4.runtime.win-arm64)
2 parents 68c1a23 + 51d692b commit 14fe97c

10 files changed

Lines changed: 317 additions & 1 deletion

.github/workflows/publish_nuget.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Publish NuGet
1+
name: Publish NuGet
22

33
on:
44
workflow_dispatch:
@@ -74,6 +74,8 @@ jobs:
7474
check_package "OpenCvSharp4.Extensions.*.nupkg"
7575
check_package "OpenCvSharp4.WpfExtensions.*.nupkg"
7676
check_package "OpenCvSharp4.runtime.win.[0-9]*.nupkg"
77+
check_package "OpenCvSharp4.runtime.win-arm64.[0-9]*.nupkg"
78+
check_package "OpenCvSharp4.runtime.win-arm64.slim.*.nupkg"
7779
check_package "OpenCvSharp4.runtime.win.slim.*.nupkg"
7880
check_package "OpenCvSharp4.Windows.[0-9]*.nupkg"
7981
check_package "OpenCvSharp4.Windows.Slim.*.nupkg"

.github/workflows/windows.yml

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,3 +253,166 @@ jobs:
253253
with:
254254
name: packages_windows
255255
path: ${{ github.workspace }}\artifacts
256+
257+
build-arm64:
258+
259+
runs-on: windows-11-arm
260+
261+
steps:
262+
- name: Checkout
263+
uses: actions/checkout@v6
264+
with:
265+
submodules: true
266+
fetch-depth: 1
267+
268+
- name: Install .NET
269+
uses: actions/setup-dotnet@v5
270+
with:
271+
dotnet-version: |
272+
10.0.x
273+
274+
- name: Restore vcpkg packages cache
275+
id: vcpkg-cache
276+
uses: actions/cache/restore@v5
277+
with:
278+
path: ${{ github.workspace }}/vcpkg_installed
279+
key: vcpkg-${{ hashFiles('vcpkg.json', 'cmake/triplets/*.cmake') }}-arm64-windows-static
280+
281+
- name: Update vcpkg to match builtin-baseline
282+
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
283+
run: |
284+
$baseline = (Get-Content vcpkg.json | ConvertFrom-Json).'builtin-baseline'
285+
git -C $env:VCPKG_INSTALLATION_ROOT fetch --depth=1 origin $baseline
286+
git -C $env:VCPKG_INSTALLATION_ROOT checkout $baseline
287+
288+
- name: Install vcpkg dependencies
289+
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
290+
run: vcpkg install --triplet arm64-windows-static --overlay-triplets=${{ github.workspace }}/cmake/triplets --x-install-root=${{ github.workspace }}/vcpkg_installed
291+
292+
- name: Save vcpkg packages cache
293+
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
294+
uses: actions/cache/save@v5
295+
with:
296+
path: ${{ github.workspace }}/vcpkg_installed
297+
key: vcpkg-${{ hashFiles('vcpkg.json', 'cmake/triplets/*.cmake') }}-arm64-windows-static
298+
299+
- name: Restore OpenCV cache
300+
id: opencv-cache
301+
uses: actions/cache/restore@v5
302+
with:
303+
path: ${{ github.workspace }}/opencv_artifacts
304+
key: opencv-${{ env.OPENCV_VERSION }}-windows-arm64-${{ hashFiles('cmake/opencv_build_options.cmake') }}-${{ hashFiles('vcpkg.json', 'cmake/triplets/*.cmake') }}
305+
306+
- name: Configure OpenCV
307+
if: steps.opencv-cache.outputs.cache-hit != 'true'
308+
shell: powershell
309+
run: |
310+
$ErrorActionPreference = 'Continue'
311+
cmake `
312+
-C cmake/opencv_build_options.cmake `
313+
-S opencv `
314+
-B opencv/build `
315+
-G "Visual Studio 17 2022" -A ARM64 `
316+
-D CMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
317+
-D VCPKG_TARGET_TRIPLET=arm64-windows-static `
318+
-D VCPKG_MANIFEST_INSTALL=OFF `
319+
-D "VCPKG_INSTALLED_DIR=$env:GITHUB_WORKSPACE/vcpkg_installed" `
320+
-D "VCPKG_OVERLAY_TRIPLETS=$env:GITHUB_WORKSPACE/cmake/triplets" `
321+
-D OPENCV_EXTRA_MODULES_PATH="$env:GITHUB_WORKSPACE/opencv_contrib/modules" `
322+
-D CMAKE_INSTALL_PREFIX="$env:GITHUB_WORKSPACE/opencv_artifacts" `
323+
-D WITH_FFMPEG=OFF `
324+
*>&1 | Tee-Object -FilePath "$env:TEMP\opencv-configure.log"
325+
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
326+
327+
- name: Verify OpenCV cmake features
328+
if: steps.opencv-cache.outputs.cache-hit != 'true'
329+
shell: powershell
330+
run: |
331+
$log = Get-Content "$env:TEMP\opencv-configure.log" -Raw
332+
$features = @('Tesseract', 'JPEG', 'PNG', 'TIFF', 'WEBP')
333+
$fail = $false
334+
foreach ($f in $features) {
335+
$m = [regex]::Match($log, "(?m)^--\s+${f}:\s+(.+)$")
336+
if ($m.Success -and $m.Groups[1].Value.Trim() -notmatch '^NO\b') {
337+
Write-Host "OK: $f = $($m.Groups[1].Value.Trim())"
338+
} else {
339+
Write-Host "MISSING or DISABLED: $f"
340+
$log -split "`n" | Select-String -Pattern $f | Select-Object -Last 3 | ForEach-Object { Write-Host $_ }
341+
$fail = $true
342+
}
343+
}
344+
if ($fail) { exit 1 }
345+
346+
- name: Build OpenCV
347+
if: steps.opencv-cache.outputs.cache-hit != 'true'
348+
shell: powershell
349+
run: |
350+
cmake --build opencv/build --config Release -j 4
351+
cmake --install opencv/build --config Release
352+
353+
- name: Save OpenCV cache
354+
if: steps.opencv-cache.outputs.cache-hit != 'true' && github.event_name == 'push' && github.ref == 'refs/heads/main'
355+
uses: actions/cache/save@v5
356+
with:
357+
path: ${{ github.workspace }}/opencv_artifacts
358+
key: opencv-${{ env.OPENCV_VERSION }}-windows-arm64-${{ hashFiles('cmake/opencv_build_options.cmake') }}-${{ hashFiles('vcpkg.json', 'cmake/triplets/*.cmake') }}
359+
360+
- name: Build OpenCvSharpExtern (full)
361+
shell: powershell
362+
run: |
363+
$ErrorActionPreference = "Stop"
364+
cmake `
365+
-S src `
366+
-B src/build_arm64 `
367+
-G "Visual Studio 17 2022" -A ARM64 `
368+
-D CMAKE_PREFIX_PATH="$env:GITHUB_WORKSPACE/opencv_artifacts" `
369+
-D CMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
370+
-D VCPKG_TARGET_TRIPLET=arm64-windows-static `
371+
-D VCPKG_MANIFEST_INSTALL=OFF `
372+
-D "VCPKG_INSTALLED_DIR=$env:GITHUB_WORKSPACE/vcpkg_installed" `
373+
-D "VCPKG_OVERLAY_TRIPLETS=$env:GITHUB_WORKSPACE/cmake/triplets"
374+
cmake --build src/build_arm64 --config Release -j 4
375+
376+
- name: Build OpenCvSharpExtern (slim)
377+
shell: powershell
378+
run: |
379+
$ErrorActionPreference = "Stop"
380+
cmake `
381+
-S src `
382+
-B src/build_arm64_slim `
383+
-G "Visual Studio 17 2022" -A ARM64 `
384+
-D CMAKE_PREFIX_PATH="$env:GITHUB_WORKSPACE/opencv_artifacts" `
385+
-D CMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
386+
-D VCPKG_TARGET_TRIPLET=arm64-windows-static `
387+
-D VCPKG_MANIFEST_INSTALL=OFF `
388+
-D "VCPKG_INSTALLED_DIR=$env:GITHUB_WORKSPACE/vcpkg_installed" `
389+
-D "VCPKG_OVERLAY_TRIPLETS=$env:GITHUB_WORKSPACE/cmake/triplets" `
390+
-D NO_CONTRIB=ON `
391+
-D NO_VIDEOIO=ON `
392+
-D NO_HIGHGUI=ON `
393+
-D NO_DNN=ON `
394+
-D NO_INSTALL_TO_TEST=ON
395+
cmake --build src/build_arm64_slim --config Release -j 4
396+
397+
- name: Test
398+
shell: cmd
399+
run: dotnet test test\OpenCvSharp.Tests -c Release -f net10.0 --runtime win-arm64 --filter "FullyQualifiedName!=OpenCvSharp.Tests.Core.BuildConfigurationTest.FFMPEG_IsEnabled"
400+
401+
- name: Pack NuGet packages
402+
shell: pwsh
403+
run: |
404+
$ErrorActionPreference = "Stop"
405+
$PSNativeCommandUseErrorActionPreference = $true
406+
407+
$date = Get-Date -Format "yyyyMMdd"
408+
$version = "${env:OPENCV_VERSION}.${date}-beta"
409+
Write-Host "version = ${version}"
410+
411+
dotnet pack nuget/OpenCvSharp4.runtime.win-arm64.csproj -o artifacts -p:Version=$version
412+
dotnet pack nuget/OpenCvSharp4.runtime.win-arm64.slim.csproj -o artifacts -p:Version=$version
413+
414+
- name: Upload NuGet packages
415+
uses: actions/upload-artifact@v6
416+
with:
417+
name: packages_windows_arm64
418+
path: ${{ github.workspace }}\artifacts
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
set(VCPKG_TARGET_ARCHITECTURE arm64)
2+
set(VCPKG_CRT_LINKAGE static)
3+
set(VCPKG_LIBRARY_LINKAGE static)
4+
5+
# Release-only build: skip debug libraries to reduce build time and artifact size.
6+
set(VCPKG_BUILD_TYPE release)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;</TargetFrameworks>
4+
<NoBuild>true</NoBuild>
5+
<IncludeBuildOutput>false</IncludeBuildOutput>
6+
7+
<!-- NuGet Package Metadata -->
8+
<PackageId>OpenCvSharp4.runtime.win-arm64</PackageId>
9+
<Title>OpenCvSharp4 native bindings for Windows ARM64</Title>
10+
<Authors>shimat</Authors>
11+
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
12+
<PackageProjectUrl>https://github.com/shimat/opencvsharp</PackageProjectUrl>
13+
<PackageIcon>opencvsharp.png</PackageIcon>
14+
<Description>Internal implementation package for OpenCvSharp to work on Windows ARM64 (e.g. Snapdragon X devices).</Description>
15+
<PackageTags>Image Processing OpenCV Wrapper FFI opencvsharp windows arm64</PackageTags>
16+
<Copyright>Copyright 2008-2026</Copyright>
17+
<PackageReleaseNotes></PackageReleaseNotes>
18+
<RepositoryUrl>https://github.com/shimat/opencvsharp.git</RepositoryUrl>
19+
<RepositoryType>git</RepositoryType>
20+
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
21+
<PackageReadmeFile>README.runtime.md</PackageReadmeFile>
22+
</PropertyGroup>
23+
24+
<ItemGroup>
25+
<None Include="../src/build_arm64/OpenCvSharpExtern/Release/OpenCvSharpExtern.dll" Pack="true" PackagePath="runtimes/win-arm64/native" />
26+
<None Include="OpenCvSharp4.runtime.win-arm64.props" Pack="true" PackagePath="build/netstandard" />
27+
<None Include="OpenCvSharp4.runtime.win-arm64.props" Pack="true" PackagePath="build/netcoreapp" />
28+
<None Include="OpenCvSharp4.runtime.win-arm64.props" Pack="true" PackagePath="build/net8.0" />
29+
<None Include="OpenCvSharp4.runtime.win-arm64.targets" Pack="true" PackagePath="build/netstandard" />
30+
<None Include="OpenCvSharp4.runtime.win-arm64.targets" Pack="true" PackagePath="build/netcoreapp" />
31+
<None Include="OpenCvSharp4.runtime.win-arm64.targets" Pack="true" PackagePath="build/net8.0" />
32+
<None Include="icon/opencvsharp.png" Pack="true" PackagePath="" />
33+
<None Include="README.runtime.md" Pack="true" PackagePath="" />
34+
</ItemGroup>
35+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<PropertyGroup>
3+
<OpenCvSharp4ExternalNativeDlls>$(MSBuildThisFileDirectory)..\..\runtimes</OpenCvSharp4ExternalNativeDlls>
4+
</PropertyGroup>
5+
<ItemGroup Condition="$(TargetFrameworkVersion.StartsWith('v4')) Or $(TargetFramework.StartsWith('net4'))">
6+
<Content Include="$(OpenCvSharp4ExternalNativeDlls)\win-arm64\native\OpenCvSharpExtern.dll">
7+
<Link>dll\arm64\OpenCvSharpExtern.dll</Link>
8+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
9+
</Content>
10+
</ItemGroup>
11+
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;</TargetFrameworks>
4+
<NoBuild>true</NoBuild>
5+
<IncludeBuildOutput>false</IncludeBuildOutput>
6+
7+
<PackageId>OpenCvSharp4.runtime.win-arm64.slim</PackageId>
8+
<Title>OpenCvSharp4 native slim bindings for Windows ARM64</Title>
9+
<Authors>shimat</Authors>
10+
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
11+
<PackageProjectUrl>https://github.com/shimat/opencvsharp</PackageProjectUrl>
12+
<PackageIcon>opencvsharp.png</PackageIcon>
13+
<Description>Slim native runtime package for OpenCvSharp on Windows ARM64. Enabled modules: core,imgproc,imgcodecs,calib3d,features2d,flann,objdetect,photo. Disabled modules: contrib,dnn,ml,video,videoio,highgui,stitching,barcode.</Description>
14+
<PackageTags>Image Processing OpenCV Wrapper FFI opencvsharp windows arm64 slim</PackageTags>
15+
<Copyright>Copyright 2008-2026</Copyright>
16+
<PackageReleaseNotes></PackageReleaseNotes>
17+
<RepositoryUrl>https://github.com/shimat/opencvsharp.git</RepositoryUrl>
18+
<RepositoryType>git</RepositoryType>
19+
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
20+
<PackageReadmeFile>README.runtime.md</PackageReadmeFile>
21+
</PropertyGroup>
22+
23+
<ItemGroup>
24+
<None Include="../src/build_arm64_slim/OpenCvSharpExtern/Release/OpenCvSharpExtern.dll" Pack="true" PackagePath="runtimes/win-arm64/native/OpenCvSharpExtern.dll" />
25+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.props" Pack="true" PackagePath="build/netstandard" />
26+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.props" Pack="true" PackagePath="build/netcoreapp" />
27+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.props" Pack="true" PackagePath="build/net8.0" />
28+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.targets" Pack="true" PackagePath="build/netstandard" />
29+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.targets" Pack="true" PackagePath="build/netcoreapp" />
30+
<None Include="OpenCvSharp4.runtime.win-arm64.slim.targets" Pack="true" PackagePath="build/net8.0" />
31+
<None Include="icon/opencvsharp.png" Pack="true" PackagePath="" />
32+
<None Include="README.runtime.md" Pack="true" PackagePath="" />
33+
</ItemGroup>
34+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<PropertyGroup>
3+
<OpenCvSharp4ExternalNativeDlls>$(MSBuildThisFileDirectory)..\..\runtimes</OpenCvSharp4ExternalNativeDlls>
4+
</PropertyGroup>
5+
<ItemGroup Condition="$(TargetFrameworkVersion.StartsWith('v4')) Or $(TargetFramework.StartsWith('net4'))">
6+
<Content Include="$(OpenCvSharp4ExternalNativeDlls)\win-arm64\native\OpenCvSharpExtern.dll">
7+
<Link>dll\arm64\OpenCvSharpExtern.dll</Link>
8+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
9+
</Content>
10+
</ItemGroup>
11+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<!--
3+
For .NET Framework (net4x) targets using PackageReference, NuGet's build pipeline automatically
4+
copies runtimes/win-arm64/native/ assets to the output root directory. However, the companion
5+
.props file already places these DLLs under dll/arm64/, which is where WindowsLibraryLoader looks
6+
at runtime. The root copies are therefore redundant and bloat the output directory.
7+
8+
This target removes the package's native assets from RuntimeCopyLocalItems — the item group
9+
populated by ResolvePackageAssets — so NuGet does not copy them to the output root.
10+
The dll/arm64/ placement from the .props file is unaffected.
11+
12+
Note: RuntimeCopyLocalItems is only present in SDK-style projects using PackageReference.
13+
Old-style (packages.config) projects do not process runtimes/ assets at all, so this target
14+
has no effect there (which is fine — no duplicate exists in that case either).
15+
16+
See also: OpenCvSharp4.runtime.win.targets for the equivalent x64 implementation.
17+
-->
18+
<Target Name="OpenCvSharp4RuntimeWinArm64Slim_RemoveRootNativeAssets"
19+
AfterTargets="ResolvePackageAssets"
20+
Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFrameworkVersion.StartsWith('v4'))">
21+
<ItemGroup>
22+
<RuntimeCopyLocalItems Remove="@(RuntimeCopyLocalItems)"
23+
Condition="'%(NuGetPackageId)' == 'OpenCvSharp4.runtime.win-arm64.slim'" />
24+
</ItemGroup>
25+
</Target>
26+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<!--
3+
For .NET Framework (net4x) targets using PackageReference, NuGet's build pipeline automatically
4+
copies runtimes/win-arm64/native/ assets to the output root directory. However, the companion
5+
.props file already places these DLLs under dll/arm64/, which is where WindowsLibraryLoader looks
6+
at runtime. The root copies are therefore redundant and bloat the output directory.
7+
8+
This target removes the package's native assets from RuntimeCopyLocalItems — the item group
9+
populated by ResolvePackageAssets — so NuGet does not copy them to the output root.
10+
The dll/arm64/ placement from the .props file is unaffected.
11+
12+
Note: RuntimeCopyLocalItems is only present in SDK-style projects using PackageReference.
13+
Old-style (packages.config) projects do not process runtimes/ assets at all, so this target
14+
has no effect there (which is fine — no duplicate exists in that case either).
15+
16+
See also: OpenCvSharp4.runtime.win.targets for the equivalent x64 implementation.
17+
-->
18+
<Target Name="OpenCvSharp4RuntimeWinArm64_RemoveRootNativeAssets"
19+
AfterTargets="ResolvePackageAssets"
20+
Condition="$(TargetFramework.StartsWith('net4')) Or $(TargetFrameworkVersion.StartsWith('v4'))">
21+
<ItemGroup>
22+
<RuntimeCopyLocalItems Remove="@(RuntimeCopyLocalItems)"
23+
Condition="'%(NuGetPackageId)' == 'OpenCvSharp4.runtime.win-arm64'" />
24+
</ItemGroup>
25+
</Target>
26+
</Project>

src/OpenCvSharp/Internal/PInvoke/WindowsLibraryLoader.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public sealed class WindowsLibraryLoader
3232
{
3333
{"x86", "x86"},
3434
{"AMD64", "x64"},
35+
{"ARM64", "arm64"},
3536
{"IA64", "Itanium"},
3637
{"ARM", "WinCE"}
3738
};
@@ -44,6 +45,7 @@ public sealed class WindowsLibraryLoader
4445
{
4546
{"x86", 4},
4647
{"AMD64", 8},
48+
{"ARM64", 8},
4749
{"IA64", 8},
4850
{"ARM", 4}
4951
};

0 commit comments

Comments
 (0)