Skip to content
Open
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"

- 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

- 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)"
}
}

- 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'
$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

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

# 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