Skip to content

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

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

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

Workflow file for this run

name: Windows Build
# This workflow builds the project on Windows with multiple compilers:
# - build-vs2022: Uses Visual Studio 2022 (stable)
# - build-vs2026: Uses Visual Studio 2026 (when available on GitHub runners, skips gracefully if not)
# - build-mingw: Uses MinGW-w64 (latest version)
# All 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-vs2026:
name: Windows Build VS2026 (${{ 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: Check for Visual Studio 2026
id: check-vs2026
shell: pwsh
run: |
Write-Host "Checking for Visual Studio 2026 on this runner..."
# Check if VS 2026 is available (stable or preview)
$vs2026Path = "C:\Program Files\Microsoft Visual Studio\2026"
$vs2026PreviewPath = "C:\Program Files\Microsoft Visual Studio\2026\Preview"
$vs2026EnterprisePath = "C:\Program Files\Microsoft Visual Studio\2026\Enterprise"
$vs2026ProfessionalPath = "C:\Program Files\Microsoft Visual Studio\2026\Professional"
$vs2026CommunityPath = "C:\Program Files\Microsoft Visual Studio\2026\Community"
$found = $false
if (Test-Path $vs2026PreviewPath) {
Write-Host "✓ Visual Studio 2026 Preview found at: $vs2026PreviewPath"
$found = $true
} elseif (Test-Path $vs2026EnterprisePath) {
Write-Host "✓ Visual Studio 2026 Enterprise found at: $vs2026EnterprisePath"
$found = $true
} elseif (Test-Path $vs2026ProfessionalPath) {
Write-Host "✓ Visual Studio 2026 Professional found at: $vs2026ProfessionalPath"
$found = $true
} elseif (Test-Path $vs2026CommunityPath) {
Write-Host "✓ Visual Studio 2026 Community found at: $vs2026CommunityPath"
$found = $true
} elseif (Test-Path $vs2026Path) {
Write-Host "✓ Visual Studio 2026 found at: $vs2026Path"
$found = $true
}
if ($found) {
echo "VS_2026_AVAILABLE=true" >> $env:GITHUB_ENV
} else {
Write-Host "ℹ Visual Studio 2026 is not available on this GitHub runner yet."
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 "⏭ Skipping VS2026 build - this job will complete successfully without running the build."
Write-Host "Once GitHub adds VS2026 to their runners, this job will automatically start building."
echo "VS_2026_AVAILABLE=false" >> $env:GITHUB_ENV
}
- name: Setup latest CMake
if: env.VS_2026_AVAILABLE == 'true'
# Use @latest to ensure CMake 3.31+ is available, which is required for VS 2026 support
uses: lukka/get-cmake@latest
- name: Configure CMake with VS2026
if: env.VS_2026_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 VS2026 - SHARED LIBRARY (DLL)"
} else {
Write-Host "Configuring Windows build ${{ matrix.config }} with VS2026 - 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 2026 generator
try {
Write-Host "Attempting to use Visual Studio 18 2026 generator..."
cmake ../.. -G "Visual Studio 18 2026" -A x64 -DCCAP_BUILD_TESTS=ON $SHARED_FLAG
} catch {
Write-Host "Visual Studio 18 2026 generator not available, trying alternative detection..."
cmake ../.. -A x64 -DCCAP_BUILD_TESTS=ON $SHARED_FLAG
}
- name: Build
if: env.VS_2026_AVAILABLE == 'true'
run: |
cd "build/${{ matrix.config }}-${{ matrix.library_type }}"
cmake --build . --config ${{ matrix.config }} --parallel
- name: Verify library type
if: env.VS_2026_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 VS2026"
# 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 VS2026"
else
echo "✗ Windows static library ${LIB_BASENAME}.lib not found"
exit 1
fi
fi
- name: Test shared library linking (Windows VS2026)
if: env.VS_2026_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 VS2026..."
# 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 2026 compiler
VCVARS_PATH=$(find "/c/Program Files/Microsoft Visual Studio/2026" -name "vcvars64.bat" 2>/dev/null | head -n1)
if [ -n "$VCVARS_PATH" ]; then
echo "Using Visual Studio 2026 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 VS2026 passed"
else
echo "⚠ Visual Studio 2026 compiler not found, skipping link test"
fi
- name: Run Unit Tests
if: env.VS_2026_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_2026_AVAILABLE == 'true'
uses: actions/upload-artifact@v4
with:
name: ccap-windows-vs2026-${{ 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 2026 build is optional (may not be available on all runners)
if-no-files-found: warn
build-mingw:
name: Windows Build MinGW (${{ 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 MinGW-w64
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >-
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-cmake
mingw-w64-x86_64-ninja
make
- name: Configure CMake with MinGW
shell: msys2 {0}
run: |
SHARED_FLAG=""
if [ "${{ matrix.library_type }}" = "shared" ]; then
SHARED_FLAG="-DCCAP_BUILD_SHARED=ON"
echo "Configuring Windows build ${{ matrix.config }} with MinGW - SHARED LIBRARY (DLL)"
else
echo "Configuring Windows build ${{ matrix.config }} with MinGW - STATIC LIBRARY"
fi
# Check compiler version
gcc --version
cmake --version
mkdir -p "build/${{ matrix.config }}-${{ matrix.library_type }}"
cd "build/${{ matrix.config }}-${{ matrix.library_type }}"
cmake ../.. -G "Ninja" -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DCCAP_BUILD_TESTS=ON $SHARED_FLAG
- name: Build
shell: msys2 {0}
run: |
cd "build/${{ matrix.config }}-${{ matrix.library_type }}"
cmake --build . --parallel
- name: Verify library type
shell: msys2 {0}
working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}
run: |
echo "Checking built libraries:"
ls -la | grep -E "ccap" || echo "No ccap libraries found"
if [ "${{ matrix.library_type }}" = "shared" ]; then
# MinGW shared libraries use .dll extension
if [ -f "libccap.dll" ]; then
echo "✓ Windows shared library libccap.dll successfully built with MinGW"
else
echo "✗ Windows shared library libccap.dll not found"
exit 1
fi
else
# MinGW static libraries use .a extension
if [ -f "libccap.a" ]; then
echo "✓ Windows static library libccap.a successfully built with MinGW"
else
echo "✗ Windows static library libccap.a not found"
exit 1
fi
fi
- name: Test shared library linking (Windows MinGW)
if: matrix.library_type == 'shared'
shell: msys2 {0}
working-directory: build/${{ matrix.config }}-${{ matrix.library_type }}
run: |
echo "Testing Windows shared library linking with MinGW..."
# 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
# Compile and run with shared library
g++ -I../../include test_shared.cpp -L. -lccap -o test_shared.exe
./test_shared.exe
echo "✓ Windows shared library linking test with MinGW passed"
- name: Run Unit Tests
if: matrix.config == 'Release'
shell: msys2 {0}
run: |
# Create symbolic links to make test script work with new build directory structure
mkdir -p build
if [ ! -L "build/${{ matrix.config }}" ]; then
ln -sf "${{ matrix.config }}-${{ matrix.library_type }}" "build/${{ matrix.config }}"
fi
cd scripts
# Set library path for shared library tests
if [ "${{ matrix.library_type }}" = "shared" ]; then
export PATH="$PWD/../build/${{ matrix.config }}-${{ matrix.library_type }}:$PATH"
fi
./run_tests.sh --functional --skip-build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ccap-windows-mingw-${{ matrix.config }}-${{ matrix.library_type }}
path: |
build/${{ matrix.config }}-${{ matrix.library_type }}/libccap.*
build/${{ matrix.config }}-${{ matrix.library_type }}/0-print_camera.exe
build/${{ matrix.config }}-${{ matrix.library_type }}/1-minimal_example.exe
build/${{ matrix.config }}-${{ matrix.library_type }}/2-capture_grab.exe
build/${{ matrix.config }}-${{ matrix.library_type }}/3-capture_callback.exe
build/${{ matrix.config }}-${{ matrix.library_type }}/*_results.xml
if-no-files-found: warn