Skip to content

Add MSVC 2026 (Visual Studio 2026) and MinGW workflow support #231

Add MSVC 2026 (Visual Studio 2026) and MinGW workflow support

Add MSVC 2026 (Visual Studio 2026) and MinGW workflow support #231

Workflow file for this run

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