Conversation
This workflow builds OpenCVSharp for ARM64 on Windows, including setup for dependencies, caching, and artifact uploading.
…in build workflow
…fore copying files
There was a problem hiding this comment.
Pull request overview
This PR adds a GitHub Actions workflow to build OpenCVSharp native libraries for Windows ARM64 architecture. The workflow automates the compilation of both OpenCV 4.11.0 and OpenCVSharp's native components targeting ARM64, with caching for efficiency.
Key changes:
- Adds complete CI/CD pipeline for Windows ARM64 builds
- Implements OpenCV 4.11.0 compilation with ARM64-specific optimizations (NEON, static linking)
- Includes workarounds for missing dependencies and path issues through runtime modifications
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - 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" | ||
|
|
There was a problem hiding this comment.
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.
| - 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" | |
| & $env:VCPKG_ROOT\vcpkg install libjpeg-turbo:arm64-windows-static | ||
| & $env:VCPKG_ROOT\vcpkg integrate install |
There was a problem hiding this comment.
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.
| & $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 |
| # 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)" | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| # 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. |
| 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' |
There was a problem hiding this comment.
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.
| $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" |
| # 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 | ||
|
|
There was a problem hiding this comment.
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.
| # 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 | |
| # 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" | ||
| } | ||
|
|
There was a problem hiding this comment.
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.
| # 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. | |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
No description provided.