Skip to content
Open
Changes from 9 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
243 changes: 243 additions & 0 deletions .github/workflows/build-win-arm64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
name: Build OpenCVSharp ARM64
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
workflow_dispatch:
jobs:
build-opencv-arm64:
runs-on: windows-11-arm
steps:
- name: Checkout OpenCVSharp
uses: actions/checkout@v4
with:
submodules: recursive

- name: Clone OpenCVSharp source code
shell: powershell
run: |
Write-Host "Cloning OpenCVSharp repository..."
git clone --depth 1 https://github.com/shimat/opencvsharp.git opencvsharp-source

# Remove existing src directory completely and recreate it
Write-Host "Removing existing src directory..."
if (Test-Path "src") {
Remove-Item -Path "src" -Recurse -Force
}

# Copy the entire src directory from cloned repo
Write-Host "Copying source files..."
Copy-Item -Path "opencvsharp-source\src" -Destination "." -Recurse -Force

Write-Host "Source files copied successfully"

Comment on lines +17 to +34
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step clones the OpenCVSharp repository after already checking it out in the previous step. This duplicates the repository unnecessarily and then replaces the checked-out src directory with the cloned one. This is redundant - if you need the latest source, you should just use the checked-out repository directly. If you need a specific version, specify it in the checkout action instead.

Suggested change
- name: Clone OpenCVSharp source code
shell: powershell
run: |
Write-Host "Cloning OpenCVSharp repository..."
git clone --depth 1 https://github.com/shimat/opencvsharp.git opencvsharp-source
# Remove existing src directory completely and recreate it
Write-Host "Removing existing src directory..."
if (Test-Path "src") {
Remove-Item -Path "src" -Recurse -Force
}
# Copy the entire src directory from cloned repo
Write-Host "Copying source files..."
Copy-Item -Path "opencvsharp-source\src" -Destination "." -Recurse -Force
Write-Host "Source files copied successfully"

Copilot uses AI. Check for mistakes.
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2

- name: Cache OpenCV
id: cache-opencv
uses: actions/cache@v4
with:
path: C:\opencv-build
key: opencv-4.11.0-arm64-native-v3-${{ runner.os }}

- name: Clone OpenCV
if: steps.cache-opencv.outputs.cache-hit != 'true'
shell: powershell
run: |
Set-Location C:\
git clone --depth 1 --branch 4.11.0 https://github.com/opencv/opencv.git
git clone --depth 1 --branch 4.11.0 https://github.com/opencv/opencv_contrib.git

- name: Install dependencies via vcpkg
if: steps.cache-opencv.outputs.cache-hit != 'true'
shell: powershell
run: |
& $env:VCPKG_ROOT\vcpkg install libjpeg-turbo:arm64-windows-static
& $env:VCPKG_ROOT\vcpkg integrate install
Comment on lines +57 to +58
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable $env:VCPKG_ROOT is used here, but later in line 138 the code checks for $env:VCPKG_INSTALLATION_ROOT as the standard variable on GitHub runners. This inconsistency could cause issues. Consider using the same logic as lines 138-139 to handle both possible environment variables.

Suggested change
& $env:VCPKG_ROOT\vcpkg install libjpeg-turbo:arm64-windows-static
& $env:VCPKG_ROOT\vcpkg integrate install
# Determine vcpkg root directory
if ($env:VCPKG_INSTALLATION_ROOT) {
$vcpkgRoot = $env:VCPKG_INSTALLATION_ROOT
} else {
$vcpkgRoot = $env:VCPKG_ROOT
}
& "$vcpkgRoot\vcpkg" install libjpeg-turbo:arm64-windows-static
& "$vcpkgRoot\vcpkg" integrate install

Copilot uses AI. Check for mistakes.

- name: Build OpenCV for ARM64
if: steps.cache-opencv.outputs.cache-hit != 'true'
shell: powershell
run: |
New-Item -ItemType Directory -Force -Path C:\opencv-build | Out-Null
Set-Location C:\opencv-build

cmake -G "Visual Studio 17 2022" -A ARM64 `
-D CMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" `
-D VCPKG_TARGET_TRIPLET=arm64-windows-static `
-D CMAKE_BUILD_TYPE=Release `
-D CMAKE_INSTALL_PREFIX=install `
-D OPENCV_EXTRA_MODULES_PATH=C:\opencv_contrib\modules `
-D BUILD_DOCS=OFF `
-D BUILD_EXAMPLES=OFF `
-D BUILD_TESTS=OFF `
-D BUILD_PERF_TESTS=OFF `
-D BUILD_JAVA=OFF `
-D BUILD_opencv_apps=OFF `
-D BUILD_opencv_datasets=OFF `
-D BUILD_opencv_gapi=OFF `
-D BUILD_opencv_dnn=OFF `
-D WITH_MSMF=ON `
-D WITH_MSMF_DXVA=ON `
-D WITH_QT=OFF `
-D WITH_TESSERACT=OFF `
-D WITH_CAROTENE=OFF `
-D WITH_JPEG=ON `
-D BUILD_JPEG=OFF `
-D ENABLE_CXX11=1 `
-D OPENCV_ENABLE_NONFREE=ON `
-D BUILD_SHARED_LIBS=OFF `
-D CPU_BASELINE=NEON `
-D CPU_DISPATCH="" `
-D CV_ENABLE_INTRINSICS=OFF `
-D ENABLE_PRECOMPILED_HEADERS=OFF `
C:\opencv

msbuild INSTALL.vcxproj /t:build /p:Configuration=Release /p:Platform=ARM64 /m:2

- name: Copy missing libraries to install directory
shell: powershell
run: |
Write-Host "Searching for third-party libraries..."
$thirdPartyLibs = @()

if (Test-Path "C:\opencv-build\3rdparty\lib\Release") {
$thirdPartyLibs += Get-ChildItem C:\opencv-build\3rdparty\lib\Release\*.lib
}

if (Test-Path "C:\opencv-build\lib\Release") {
$thirdPartyLibs += Get-ChildItem C:\opencv-build\lib\Release\*.lib
}

if ($thirdPartyLibs.Count -gt 0) {
Copy-Item $thirdPartyLibs -Destination C:\opencv-build\install\ARM64\vc17\staticlib\ -Force -ErrorAction SilentlyContinue
Write-Host "Copied $($thirdPartyLibs.Count) libraries"
} else {
Write-Host "No third-party libraries found to copy"
}

Write-Host "`nLibraries in install directory:"
Get-ChildItem C:\opencv-build\install\ARM64\vc17\staticlib\*.lib | Select-Object Name

# Create stubs for missing libraries that are referenced but not used (DNN/GAPI disabled)
$stubLibs = @("libprotobuf.lib", "ade.lib")
foreach ($lib in $stubLibs) {
$stubPath = "C:\opencv-build\install\ARM64\vc17\staticlib\$lib"
if (-not (Test-Path $stubPath)) {
New-Item -ItemType File -Path $stubPath -Force | Out-Null
Write-Host "Created stub $lib (not used)"
}
}
Comment on lines +124 to +132
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating stub/empty library files is a workaround that could lead to linker errors or undefined behavior at runtime if these libraries are actually referenced. While the comment states these are "not used", this approach is fragile. A better solution would be to fix the build configuration to not reference these libraries at all when DNN/GAPI are disabled.

Suggested change
# Create stubs for missing libraries that are referenced but not used (DNN/GAPI disabled)
$stubLibs = @("libprotobuf.lib", "ade.lib")
foreach ($lib in $stubLibs) {
$stubPath = "C:\opencv-build\install\ARM64\vc17\staticlib\$lib"
if (-not (Test-Path $stubPath)) {
New-Item -ItemType File -Path $stubPath -Force | Out-Null
Write-Host "Created stub $lib (not used)"
}
}
# (Removed) Stub library creation for missing libraries. Instead, ensure build configuration does not reference these when DNN/GAPI are disabled.

Copilot uses AI. Check for mistakes.

- name: Install vcpkg dependencies for OpenCvSharpExtern
shell: powershell
run: |
# Use VCPKG_INSTALLATION_ROOT which is the standard variable on GitHub runners
$vcpkgRoot = if ($env:VCPKG_INSTALLATION_ROOT) { $env:VCPKG_INSTALLATION_ROOT } else { $env:VCPKG_ROOT }
Write-Host "Installing libjpeg-turbo via vcpkg at: $vcpkgRoot"
& "$vcpkgRoot\vcpkg" install libjpeg-turbo:arm64-windows-static
& "$vcpkgRoot\vcpkg" integrate install

# Copy vcpkg libraries to OpenCV install directory so linker can find them
$vcpkgLibPath = "$vcpkgRoot\installed\arm64-windows-static\lib"
if (Test-Path $vcpkgLibPath) {
Write-Host "Copying vcpkg libraries from: $vcpkgLibPath"
Copy-Item "$vcpkgLibPath\*.lib" -Destination C:\opencv-build\install\ARM64\vc17\staticlib\ -Force
Write-Host "Copied vcpkg libraries to OpenCV install directory"
}

- name: Build OpenCVSharp Native
shell: powershell
run: |
# Define paths at the beginning for better maintainability
$oldJpegPath = 'C:\\a\\opencvsharp\.win\.arm64\\opencvsharp\.win\.arm64\\vcpkg\\installed\\arm64-windows-static\\lib\\jpeg\.lib'
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded path C:\\a\\opencvsharp\.win\.arm64\\opencvsharp\.win\.arm64\\vcpkg\\installed\\arm64-windows-static\\lib\\jpeg\.lib appears to be specific to a particular CI environment or local setup. This path is unlikely to exist in the GitHub Actions runner and the replacement logic may not work as intended. Consider using a more generic pattern or removing this path replacement if it's not necessary.

Suggested change
$oldJpegPath = 'C:\\a\\opencvsharp\.win\.arm64\\opencvsharp\.win\.arm64\\vcpkg\\installed\\arm64-windows-static\\lib\\jpeg\.lib'
$oldJpegPath = "$vcpkgRoot\installed\arm64-windows-static\lib\jpeg.lib"

Copilot uses AI. Check for mistakes.
$newJpegPath = 'C:\opencv-build\install\ARM64\vc17\staticlib\jpeg.lib'

# Verify we're in the correct directory
if (-not (Test-Path "src\OpenCvSharpExtern\CMakeLists.txt")) {
Write-Error "CMakeLists.txt not found. Current directory: $PWD"
Get-ChildItem
exit 1
}

$cmakeFile = "src\OpenCvSharpExtern\CMakeLists.txt"
$content = Get-Content $cmakeFile -Raw

# Exclude problematic cpp files (use double backslashes for CMake regex)
$replacement = "file(GLOB OPENCVSHARP_FILES *.cpp)`nlist(FILTER OPENCVSHARP_FILES EXCLUDE REGEX `".*/dnn\\.cpp$`")`nlist(FILTER OPENCVSHARP_FILES EXCLUDE REGEX `".*/dnn_superres\\.cpp$`")`nlist(FILTER OPENCVSHARP_FILES EXCLUDE REGEX `".*/text\\.cpp$`")`nlist(FILTER OPENCVSHARP_FILES EXCLUDE REGEX `".*/wechat_qrcode\\.cpp$`")`nlist(FILTER OPENCVSHARP_FILES EXCLUDE REGEX `".*/cuda\\.cpp$`")"
$content = $content -replace 'file\(GLOB OPENCVSHARP_FILES \*\.cpp\)', $replacement

# Fix ${the_module} references - replace with OpenCvSharpExtern
$content = $content -replace '\$\{the_module\}', 'OpenCvSharpExtern'

# Comment out the problematic iconv calls
$content = $content -replace 'ocv_target_link_libraries\(OpenCvSharpExtern Iconv::Iconv\)', '# ocv_target_link_libraries(OpenCvSharpExtern Iconv::Iconv)'
$content = $content -replace 'ocv_target_compile_definitions\(OpenCvSharpExtern PRIVATE "NO_ICONV=1"\)', '# ocv_target_compile_definitions(OpenCvSharpExtern PRIVATE "NO_ICONV=1")'

Set-Content $cmakeFile -Value $content

# Fix include_opencv.h to comment out missing headers
$includeFile = "src\OpenCvSharpExtern\include_opencv.h"
$includeContent = Get-Content $includeFile -Raw
$includeContent = $includeContent -replace '#include <opencv2/wechat_qrcode\.hpp>', '// #include <opencv2/wechat_qrcode.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/dnn\.hpp>', '// #include <opencv2/dnn.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/dnn_superres\.hpp>', '// #include <opencv2/dnn_superres.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/text\.hpp>', '// #include <opencv2/text.hpp> // Disabled'
Set-Content $includeFile -Value $includeContent

Comment on lines +175 to +189
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying source files directly in the build step (CMakeLists.txt and include_opencv.h) is a fragile anti-pattern. These modifications are not version-controlled and could break with updates to the source code. Consider either: 1) Maintaining patch files that can be applied, 2) Forking and modifying the source repository, or 3) Using CMake's command-line options to control build settings instead of text replacement.

Suggested change
# Comment out the problematic iconv calls
$content = $content -replace 'ocv_target_link_libraries\(OpenCvSharpExtern Iconv::Iconv\)', '# ocv_target_link_libraries(OpenCvSharpExtern Iconv::Iconv)'
$content = $content -replace 'ocv_target_compile_definitions\(OpenCvSharpExtern PRIVATE "NO_ICONV=1"\)', '# ocv_target_compile_definitions(OpenCvSharpExtern PRIVATE "NO_ICONV=1")'
Set-Content $cmakeFile -Value $content
# Fix include_opencv.h to comment out missing headers
$includeFile = "src\OpenCvSharpExtern\include_opencv.h"
$includeContent = Get-Content $includeFile -Raw
$includeContent = $includeContent -replace '#include <opencv2/wechat_qrcode\.hpp>', '// #include <opencv2/wechat_qrcode.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/dnn\.hpp>', '// #include <opencv2/dnn.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/dnn_superres\.hpp>', '// #include <opencv2/dnn_superres.hpp> // Disabled'
$includeContent = $includeContent -replace '#include <opencv2/text\.hpp>', '// #include <opencv2/text.hpp> // Disabled'
Set-Content $includeFile -Value $includeContent
# Apply patch files to CMakeLists.txt and include_opencv.h
# Ensure patch.exe is available (install via Chocolatey if needed)
if (-not (Get-Command patch.exe -ErrorAction SilentlyContinue)) {
choco install patch
}
# Apply CMakeLists.txt patch
patch -p1 < ..\patches\cmakelists-iconv.patch
# Apply include_opencv.h patch
patch -p1 < ..\patches\include_opencv_headers.patch

Copilot uses AI. Check for mistakes.
New-Item -ItemType Directory -Force -Path build_native | Out-Null
Set-Location build_native

# Don't use vcpkg toolchain for OpenCvSharpExtern - OpenCV already has all dependencies
# Using vcpkg toolchain causes incorrect library paths to be embedded in .vcxproj
Write-Host "Configuring OpenCvSharpExtern without vcpkg toolchain..."

cmake -G "Visual Studio 17 2022" -A ARM64 `
-D CMAKE_BUILD_TYPE=Release `
-D OpenCV_DIR=C:\opencv-build\install\ARM64\vc17\staticlib `
-D CMAKE_INSTALL_PREFIX="$PWD\install" `
-D CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded `
..\src\OpenCvSharpExtern

# Fix hardcoded jpeg.lib path in generated .vcxproj files
Write-Host "Fixing jpeg.lib path in OpenCvSharpExtern.vcxproj files..."
$vcxprojFile = "OpenCvSharpExtern.dir\Release\OpenCvSharpExtern.vcxproj"
if (Test-Path $vcxprojFile) {
$vcxprojContent = Get-Content $vcxprojFile -Raw
$vcxprojContent = $vcxprojContent -replace $oldJpegPath, $newJpegPath
Set-Content $vcxprojFile -Value $vcxprojContent
Write-Host "Fixed jpeg.lib path in release vcxproj"
}

# Also fix in the main vcxproj if it exists
$mainVcxproj = "OpenCvSharpExtern.vcxproj"
if (Test-Path $mainVcxproj) {
$mainContent = Get-Content $mainVcxproj -Raw
$mainContent = $mainContent -replace $oldJpegPath, $newJpegPath
Set-Content $mainVcxproj -Value $mainContent
Write-Host "Fixed jpeg.lib path in main vcxproj"
}

Comment on lines +204 to +222
Copy link

Copilot AI Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifying generated .vcxproj files after CMake configuration is an anti-pattern. These files can be regenerated by CMake at any time, losing your changes. The path issue should be fixed at the CMake configuration level by setting appropriate CMAKE variables (like CMAKE_PREFIX_PATH or CMAKE_LIBRARY_PATH) or by fixing the vcpkg integration, rather than post-processing generated files.

Suggested change
# Fix hardcoded jpeg.lib path in generated .vcxproj files
Write-Host "Fixing jpeg.lib path in OpenCvSharpExtern.vcxproj files..."
$vcxprojFile = "OpenCvSharpExtern.dir\Release\OpenCvSharpExtern.vcxproj"
if (Test-Path $vcxprojFile) {
$vcxprojContent = Get-Content $vcxprojFile -Raw
$vcxprojContent = $vcxprojContent -replace $oldJpegPath, $newJpegPath
Set-Content $vcxprojFile -Value $vcxprojContent
Write-Host "Fixed jpeg.lib path in release vcxproj"
}
# Also fix in the main vcxproj if it exists
$mainVcxproj = "OpenCvSharpExtern.vcxproj"
if (Test-Path $mainVcxproj) {
$mainContent = Get-Content $mainVcxproj -Raw
$mainContent = $mainContent -replace $oldJpegPath, $newJpegPath
Set-Content $mainVcxproj -Value $mainContent
Write-Host "Fixed jpeg.lib path in main vcxproj"
}
# [REMOVED] Post-processing of .vcxproj files to fix jpeg.lib path.
# Ensure correct library paths are set in CMake configuration above.

Copilot uses AI. Check for mistakes.
# Find the actual solution file generated by CMake
Write-Host "Looking for solution file..."
$slnFile = Get-ChildItem -Filter "*.sln" | Select-Object -First 1
if ($slnFile) {
Write-Host "Found solution file: $($slnFile.Name)"
msbuild $slnFile.Name /t:build /p:Configuration=Release /p:Platform=ARM64 /m:2
} else {
Write-Error "No .sln file found in build directory"
Get-ChildItem
exit 1
}


- name: Upload Native Artifacts
uses: actions/upload-artifact@v4
with:
name: opencvsharp-native-arm64-windows
path: |
build_native/Release/OpenCvSharpExtern.dll
build_native/Release/OpenCvSharpExtern.lib
build_native/Release/OpenCvSharpExtern.pdb
Loading