Add MSVC 2026 (Visual Studio 2026) and MinGW workflow support #231
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Windows Build | |
| # This workflow builds the project on Windows with multiple Visual Studio versions: | |
| # - build-vs2022: Uses Visual Studio 2022 (stable) | |
| # - build-vs2025: Uses Visual Studio 2025/MSVC 2026 (preview, auto-installs if needed) | |
| # Both jobs test Debug/Release builds with static/shared library configurations. | |
| on: | |
| push: | |
| branches: [ main, ci_test ] | |
| pull_request: | |
| branches: [ main, ci_test ] | |
| workflow_dispatch: | |
| jobs: | |
| build-vs2022: | |
| name: Windows Build VS2022 (${{ matrix.config }}-${{ matrix.library_type }}) | |
| runs-on: windows-latest | |
| strategy: | |
| matrix: | |
| config: [Debug, Release] | |
| library_type: [static, shared] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Visual Studio environment | |
| uses: microsoft/setup-msbuild@v1.1 | |
| - name: Configure CMake | |
| run: | | |
| $SHARED_FLAG = "" | |
| if ("${{ matrix.library_type }}" -eq "shared") { | |
| $SHARED_FLAG = "-DCCAP_BUILD_SHARED=ON" | |
| Write-Host "Configuring Windows build ${{ matrix.config }} - SHARED LIBRARY (DLL)" | |
| } else { | |
| Write-Host "Configuring Windows build ${{ matrix.config }} - STATIC LIBRARY" | |
| } | |
| mkdir -p "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| cd "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| cmake ../.. -G "Visual Studio 17 2022" -A x64 -DCCAP_BUILD_TESTS=ON $SHARED_FLAG | |
| - name: Build | |
| run: | | |
| cd "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| cmake --build . --config ${{ matrix.config }} --parallel | |
| - name: Verify library type | |
| shell: bash | |
| working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }} | |
| run: | | |
| echo "Checking built libraries:" | |
| ls -la | grep -E "ccap" || echo "No ccap libraries found" | |
| # Verify library type | |
| # Debug versions have 'd' suffix, Release versions don't | |
| if [ "${{ matrix.config }}" = "Debug" ]; then | |
| LIB_BASENAME="ccapd" | |
| DLL_NAME="ccapd.dll" | |
| else | |
| LIB_BASENAME="ccap" | |
| DLL_NAME="ccap.dll" | |
| fi | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| if [ -f "$DLL_NAME" ]; then | |
| echo "✓ Windows shared library $DLL_NAME successfully built" | |
| # Check if import library exists | |
| if [ -f "${LIB_BASENAME}.lib" ]; then | |
| echo "✓ Windows import library ${LIB_BASENAME}.lib also created" | |
| fi | |
| else | |
| echo "✗ Windows shared library $DLL_NAME not found" | |
| exit 1 | |
| fi | |
| else | |
| if [ -f "${LIB_BASENAME}.lib" ]; then | |
| echo "✓ Windows static library ${LIB_BASENAME}.lib successfully built" | |
| else | |
| echo "✗ Windows static library ${LIB_BASENAME}.lib not found" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Test shared library linking (Windows) | |
| if: matrix.library_type == 'shared' | |
| shell: bash | |
| working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }} | |
| run: | | |
| echo "Testing Windows shared library linking..." | |
| # Create a simple test program | |
| cat > test_shared.cpp << 'EOF' | |
| #include "ccap_c.h" | |
| #include <stdio.h> | |
| int main() { | |
| const char* version = ccap_get_version(); | |
| printf("Library version: %s\n", version ? version : "unknown"); | |
| CcapProvider* provider = ccap_provider_create(); | |
| if (provider) { | |
| printf("Provider created successfully\n"); | |
| ccap_provider_destroy(provider); | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| EOF | |
| # Find Visual Studio compiler | |
| VCVARS_PATH=$(find "/c/Program Files/Microsoft Visual Studio" -name "vcvars64.bat" 2>/dev/null | head -n1) | |
| if [ -z "$VCVARS_PATH" ]; then | |
| VCVARS_PATH=$(find "/c/Program Files (x86)/Microsoft Visual Studio" -name "vcvars64.bat" 2>/dev/null | head -n1) | |
| fi | |
| if [ -n "$VCVARS_PATH" ]; then | |
| echo "Using Visual Studio environment from: $VCVARS_PATH" | |
| # Convert path for cmd | |
| VCVARS_WIN_PATH=$(echo "$VCVARS_PATH" | sed 's|/c/|C:/|g' | sed 's|/|\\|g') | |
| # Determine library names based on config | |
| if [ "${{ matrix.config }}" = "Debug" ]; then | |
| LIB_NAME="ccapd.lib" | |
| DLL_NAME="ccapd.dll" | |
| else | |
| LIB_NAME="ccap.lib" | |
| DLL_NAME="ccap.dll" | |
| fi | |
| # Create a temporary batch file to avoid quote escaping issues | |
| cat > compile_test.bat << EOF | |
| @echo off | |
| call "$VCVARS_WIN_PATH" | |
| set "INCLUDE_DIR=%GITHUB_WORKSPACE%\\include" | |
| if not exist "%INCLUDE_DIR%" ( | |
| echo Include directory not found: %INCLUDE_DIR% | |
| exit /b 1 | |
| ) | |
| cl /I"%INCLUDE_DIR%" test_shared.cpp $LIB_NAME /Fe:test_shared.exe | |
| EOF | |
| # Execute the batch file | |
| cmd //c compile_test.bat | |
| # Ensure DLL is available beside the test executable | |
| if [ ! -f "./$DLL_NAME" ]; then | |
| DLL_PATH=$(find .. -name "$DLL_NAME" -print -quit) | |
| if [ -z "$DLL_PATH" ]; then | |
| echo "✗ Windows shared library $DLL_NAME not found for runtime" | |
| exit 1 | |
| fi | |
| cp "$DLL_PATH" . | |
| fi | |
| ./test_shared.exe | |
| echo "✓ Windows shared library linking test passed" | |
| else | |
| echo "⚠ Visual Studio compiler not found, skipping link test" | |
| fi | |
| - name: Run Unit Tests | |
| shell: bash | |
| run: | | |
| # Create symbolic links to make test script work with new build directory structure | |
| mkdir -p build/tests | |
| # Create symbolic link for the config directory | |
| if [ ! -L "build/${{ matrix.config }}" ]; then | |
| ln -sf "${{ matrix.config }}-${{ matrix.library_type }}" "build/${{ matrix.config }}" | |
| fi | |
| # Create symbolic link for the tests directory to match expected path structure | |
| if [ ! -L "build/tests/${{ matrix.config }}" ]; then | |
| ln -sf "../${{ matrix.config }}-${{ matrix.library_type }}/tests/${{ matrix.config }}" "build/tests/${{ matrix.config }}" | |
| fi | |
| cd scripts | |
| if [ "${{ matrix.config }}" == "Debug" ]; then | |
| # Set library path for shared library tests | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| export PATH="$PWD/../build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}:$PATH" | |
| fi | |
| ./run_tests.sh --functional --skip-build | |
| else | |
| # Set library path for shared library tests | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| export PATH="$PWD/../build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}:$PATH" | |
| fi | |
| ./run_tests.sh --performance --skip-build | |
| fi | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ccap-windows-vs2022-${{ matrix.config }}-${{ matrix.library_type }} | |
| path: | | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/ccap*.* | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/0-print_camera.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/1-minimal_example.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/2-capture_grab.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/3-capture_callback.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/*_results.xml | |
| if-no-files-found: error | |
| build-vs2025: | |
| name: Windows Build VS2025/MSVC2026 (${{ matrix.config }}-${{ matrix.library_type }}) | |
| runs-on: windows-latest | |
| strategy: | |
| matrix: | |
| config: [Debug, Release] | |
| library_type: [static, shared] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup latest CMake | |
| # Use @latest to ensure CMake 3.31+ is available, which is required for VS 2025 support | |
| # VS 2025 is very new and requires the latest CMake version | |
| uses: lukka/get-cmake@latest | |
| - name: Setup Visual Studio 2025 Preview | |
| shell: pwsh | |
| run: | | |
| Write-Host "Checking for Visual Studio 2025..." | |
| # Check if VS 2025 is available | |
| $vs2025Path = "C:\Program Files\Microsoft Visual Studio\2025" | |
| $vs2025PreviewPath = "C:\Program Files\Microsoft Visual Studio\2025\Preview" | |
| if (Test-Path $vs2025PreviewPath) { | |
| Write-Host "Visual Studio 2025 Preview found at: $vs2025PreviewPath" | |
| echo "VS_2025_AVAILABLE=true" >> $env:GITHUB_ENV | |
| } elseif (Test-Path $vs2025Path) { | |
| Write-Host "Visual Studio 2025 found at: $vs2025Path" | |
| echo "VS_2025_AVAILABLE=true" >> $env:GITHUB_ENV | |
| } else { | |
| Write-Host "Visual Studio 2025 not found on this runner" | |
| Write-Host "Available Visual Studio installations:" | |
| Get-ChildItem "C:\Program Files\Microsoft Visual Studio" -Directory -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_.FullName } | |
| Write-Host "" | |
| Write-Host "Installing Visual Studio 2025 Build Tools Preview..." | |
| # Download VS installer | |
| # Note: Using aka.ms redirect URL per Microsoft's standard distribution method. | |
| # This URL points to the preview version. When VS 2025 is officially released, | |
| # verify and update the URL from Microsoft's official documentation. | |
| # If the URL becomes unavailable, the error handling below will catch it and skip the build. | |
| $installerUrl = "https://aka.ms/vs/18/pre/vs_BuildTools.exe" | |
| $installerPath = "$env:TEMP\vs_buildtools.exe" | |
| Write-Host "Downloading installer from: $installerUrl" | |
| try { | |
| Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath -ErrorAction Stop | |
| Write-Host "Download completed" | |
| # Install VS 2025 Build Tools with required components | |
| Write-Host "Installing Visual Studio 2025 Build Tools (this may take several minutes)..." | |
| $arguments = @( | |
| "--quiet", | |
| "--wait", | |
| "--norestart", | |
| "--nocache", | |
| "--add", "Microsoft.VisualStudio.Workload.VCTools", | |
| "--add", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", | |
| "--add", "Microsoft.VisualStudio.Component.Windows11SDK.22621" | |
| ) | |
| $process = Start-Process -FilePath $installerPath -ArgumentList $arguments -Wait -PassThru -NoNewWindow | |
| # Exit codes: 0 = success, 3010 = success with reboot required (common for VS installers) | |
| if ($process.ExitCode -eq 0 -or $process.ExitCode -eq 3010) { | |
| Write-Host "Visual Studio 2025 Build Tools installed successfully" | |
| echo "VS_2025_AVAILABLE=true" >> $env:GITHUB_ENV | |
| } else { | |
| Write-Host "Installation failed with exit code: $($process.ExitCode)" | |
| Write-Host "Will skip VS2025 builds" | |
| echo "VS_2025_AVAILABLE=false" >> $env:GITHUB_ENV | |
| } | |
| } catch { | |
| Write-Host "Error during installation: $_" | |
| Write-Host "Will skip VS2025 builds" | |
| echo "VS_2025_AVAILABLE=false" >> $env:GITHUB_ENV | |
| } | |
| } | |
| - name: Configure CMake with VS2025 | |
| if: env.VS_2025_AVAILABLE == 'true' | |
| run: | | |
| $SHARED_FLAG = "" | |
| if ("${{ matrix.library_type }}" -eq "shared") { | |
| $SHARED_FLAG = "-DCCAP_BUILD_SHARED=ON" | |
| Write-Host "Configuring Windows build ${{ matrix.config }} with VS2025/MSVC2026 - SHARED LIBRARY (DLL)" | |
| } else { | |
| Write-Host "Configuring Windows build ${{ matrix.config }} with VS2025/MSVC2026 - STATIC LIBRARY" | |
| } | |
| # Check CMake version | |
| cmake --version | |
| mkdir -p "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| cd "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| # Try Visual Studio 18 2025 generator | |
| try { | |
| Write-Host "Attempting to use Visual Studio 18 2025 generator..." | |
| cmake ../.. -G "Visual Studio 18 2025" -A x64 -DCCAP_BUILD_TESTS=ON $SHARED_FLAG | |
| } catch { | |
| Write-Host "Visual Studio 18 2025 generator not available, trying alternative detection..." | |
| cmake ../.. -A x64 -DCCAP_BUILD_TESTS=ON $SHARED_FLAG | |
| } | |
| - name: Skip message | |
| if: env.VS_2025_AVAILABLE != 'true' | |
| run: | | |
| Write-Host "Visual Studio 2025 is not available on this runner" | |
| Write-Host "Skipping VS2025/MSVC2026 build" | |
| - name: Build | |
| if: env.VS_2025_AVAILABLE == 'true' | |
| run: | | |
| cd "build/${{ matrix.config }}-${{ matrix.library_type }}" | |
| cmake --build . --config ${{ matrix.config }} --parallel | |
| - name: Verify library type | |
| if: env.VS_2025_AVAILABLE == 'true' | |
| shell: bash | |
| working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }} | |
| run: | | |
| echo "Checking built libraries:" | |
| ls -la | grep -E "ccap" || echo "No ccap libraries found" | |
| # Verify library type | |
| # Debug versions have 'd' suffix, Release versions don't | |
| if [ "${{ matrix.config }}" = "Debug" ]; then | |
| LIB_BASENAME="ccapd" | |
| DLL_NAME="ccapd.dll" | |
| else | |
| LIB_BASENAME="ccap" | |
| DLL_NAME="ccap.dll" | |
| fi | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| if [ -f "$DLL_NAME" ]; then | |
| echo "✓ Windows shared library $DLL_NAME successfully built with VS2025/MSVC2026" | |
| # Check if import library exists | |
| if [ -f "${LIB_BASENAME}.lib" ]; then | |
| echo "✓ Windows import library ${LIB_BASENAME}.lib also created" | |
| fi | |
| else | |
| echo "✗ Windows shared library $DLL_NAME not found" | |
| exit 1 | |
| fi | |
| else | |
| if [ -f "${LIB_BASENAME}.lib" ]; then | |
| echo "✓ Windows static library ${LIB_BASENAME}.lib successfully built with VS2025/MSVC2026" | |
| else | |
| echo "✗ Windows static library ${LIB_BASENAME}.lib not found" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Test shared library linking (Windows VS2025) | |
| if: env.VS_2025_AVAILABLE == 'true' && matrix.library_type == 'shared' | |
| shell: bash | |
| working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }} | |
| run: | | |
| echo "Testing Windows shared library linking with VS2025/MSVC2026..." | |
| # Create a simple test program | |
| cat > test_shared.cpp << 'EOF' | |
| #include "ccap_c.h" | |
| #include <stdio.h> | |
| int main() { | |
| const char* version = ccap_get_version(); | |
| printf("Library version: %s\n", version ? version : "unknown"); | |
| CcapProvider* provider = ccap_provider_create(); | |
| if (provider) { | |
| printf("Provider created successfully\n"); | |
| ccap_provider_destroy(provider); | |
| return 0; | |
| } | |
| return 1; | |
| } | |
| EOF | |
| # Find Visual Studio 2025 compiler | |
| VCVARS_PATH=$(find "/c/Program Files/Microsoft Visual Studio/2025" -name "vcvars64.bat" 2>/dev/null | head -n1) | |
| if [ -n "$VCVARS_PATH" ]; then | |
| echo "Using Visual Studio 2025 environment from: $VCVARS_PATH" | |
| # Convert path for cmd | |
| VCVARS_WIN_PATH=$(echo "$VCVARS_PATH" | sed 's|/c/|C:/|g' | sed 's|/|\\|g') | |
| # Determine library names based on config | |
| if [ "${{ matrix.config }}" = "Debug" ]; then | |
| LIB_NAME="ccapd.lib" | |
| DLL_NAME="ccapd.dll" | |
| else | |
| LIB_NAME="ccap.lib" | |
| DLL_NAME="ccap.dll" | |
| fi | |
| # Create a temporary batch file to avoid quote escaping issues | |
| cat > compile_test.bat << EOF | |
| @echo off | |
| call "$VCVARS_WIN_PATH" | |
| set "INCLUDE_DIR=%GITHUB_WORKSPACE%\\include" | |
| if not exist "%INCLUDE_DIR%" ( | |
| echo Include directory not found: %INCLUDE_DIR% | |
| exit /b 1 | |
| ) | |
| cl /I"%INCLUDE_DIR%" test_shared.cpp $LIB_NAME /Fe:test_shared.exe | |
| EOF | |
| # Execute the batch file | |
| cmd //c compile_test.bat | |
| # Ensure DLL is available beside the test executable | |
| if [ ! -f "./$DLL_NAME" ]; then | |
| DLL_PATH=$(find .. -name "$DLL_NAME" -print -quit) | |
| if [ -z "$DLL_PATH" ]; then | |
| echo "✗ Windows shared library $DLL_NAME not found for runtime" | |
| exit 1 | |
| fi | |
| cp "$DLL_PATH" . | |
| fi | |
| ./test_shared.exe | |
| echo "✓ Windows shared library linking test with VS2025/MSVC2026 passed" | |
| else | |
| echo "⚠ Visual Studio 2025 compiler not found, skipping link test" | |
| fi | |
| - name: Run Unit Tests | |
| if: env.VS_2025_AVAILABLE == 'true' | |
| shell: bash | |
| run: | | |
| # Create symbolic links to make test script work with new build directory structure | |
| mkdir -p build/tests | |
| # Create symbolic link for the config directory | |
| if [ ! -L "build/${{ matrix.config }}" ]; then | |
| ln -sf "${{ matrix.config }}-${{ matrix.library_type }}" "build/${{ matrix.config }}" | |
| fi | |
| # Create symbolic link for the tests directory to match expected path structure | |
| if [ ! -L "build/tests/${{ matrix.config }}" ]; then | |
| ln -sf "../${{ matrix.config }}-${{ matrix.library_type }}/tests/${{ matrix.config }}" "build/tests/${{ matrix.config }}" | |
| fi | |
| cd scripts | |
| if [ "${{ matrix.config }}" == "Debug" ]; then | |
| # Set library path for shared library tests | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| export PATH="$PWD/../build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}:$PATH" | |
| fi | |
| ./run_tests.sh --functional --skip-build | |
| else | |
| # Set library path for shared library tests | |
| if [ "${{ matrix.library_type }}" = "shared" ]; then | |
| export PATH="$PWD/../build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}:$PATH" | |
| fi | |
| ./run_tests.sh --performance --skip-build | |
| fi | |
| - name: Upload artifacts | |
| if: env.VS_2025_AVAILABLE == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ccap-windows-vs2025-${{ matrix.config }}-${{ matrix.library_type }} | |
| path: | | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/ccap*.* | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/0-print_camera.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/1-minimal_example.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/2-capture_grab.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/${{ matrix.config }}/3-capture_callback.exe | |
| build/${{ matrix.config }}-${{ matrix.library_type }}/*_results.xml | |
| # Use 'warn' instead of 'error' since VS 2025 build is optional (may not be available on all runners) | |
| if-no-files-found: warn |