Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
feb3d90
Minimal Windows CI Build requirements
coatless Dec 28, 2025
6cb3060
Are we shipping configure.win?
coatless Dec 28, 2025
1786428
Downloaded windows?
coatless Dec 28, 2025
3f136a4
Mirror suggested deployment by using vcpkg and custom tooling on CLBl…
coatless Dec 28, 2025
e843c34
Clarify linking
coatless Dec 28, 2025
36d0799
Use chocolately to grab the intel cpu emulation.
coatless Dec 28, 2025
98c6b1a
Add a _lot_ more debug statements. Move OpenCL Emulation to front. Tr…
coatless Dec 28, 2025
de1c81f
Update R-CMD-check.yaml
coatless Jan 5, 2026
8967f88
Simplify OpenCL installation in R-CMD-check workflow
coatless Jan 5, 2026
89fae3a
Simplify installation commands in R-CMD-check.yaml
coatless Jan 5, 2026
fca36f2
Modify R-CMD-check.yaml for Windows OpenCL setup
coatless Jan 5, 2026
5ea7992
Modify OpenCL paths and add debug step
coatless Jan 5, 2026
3226f6b
Fix vcpkg path to use forward slashes
coatless Jan 5, 2026
2b6db80
Register CLBlast locations in workflow
coatless Jan 5, 2026
b934a04
Install clblast alongside OpenCL SDK on Windows
coatless Jan 5, 2026
bba0ece
missing clblast.dll and OpenCL.dll ?
coatless Jan 5, 2026
cfc9252
generate R/flags.R from R/flags.R.in with all required variable subst…
coatless Jan 5, 2026
823a2c1
Remove non-portable flag.
coatless Jan 5, 2026
a5231d5
Standardize line endings to avoid complaints from the Windows CI runs...
coatless Jan 5, 2026
567be6d
Update configure.win
coatless Jan 6, 2026
f6af274
Update configure.win
coatless Jan 6, 2026
e001f02
Update .Rbuildignore
coatless Jan 6, 2026
6bc4b96
Update src/Makevars.win.in
coatless Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
^autom4te\.cache$
^config\.log$
^config\.status$
^\.gitattributes$
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Ensure shell scripts and configure files always use LF line endings
configure text eol=lf
configure.ac text eol=lf
configure.win text eol=lf
cleanup text eol=lf
*.sh text eol=lf
76 changes: 73 additions & 3 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ jobs:
fail-fast: false
matrix:
config:
- {os: macos-latest, r: 'release'}
- {os: ubuntu-latest, r: 'release'}
#- {os: macos-latest, r: 'release'}
#- {os: ubuntu-latest, r: 'release'}
Comment on lines +21 to +22
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macOS and Ubuntu build configurations are commented out, leaving only Windows enabled. While the PR description mentions this is for testing Windows builds, this should not be committed to the main branch as it disables CI testing for other platforms. Either re-enable these platforms once Windows testing is complete, or add a clear TODO comment explaining when they will be re-enabled.

Copilot uses AI. Check for mistakes.
- {os: windows-latest, r: 'release'}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes
INTEL_OPENCL_URL: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/b6dccdb7-b503-41ea-bd4b-a78e9c2d8dd6/w_opencl_runtime_p_2025.1.0.972.exe"

steps:
- uses: actions/checkout@v4
Expand All @@ -38,12 +40,80 @@ jobs:

- name: Install clblast via Homebrew (macOS)
if: runner.os == 'macOS'
run: brew install clblast clblas
run: brew install clblast clblas clinfo

- name: Install clblast via apt (Ubuntu)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y opencl-headers ocl-icd-opencl-dev libclblast-dev

- name: Cache Intel OpenCL Runtime
if: runner.os == 'Windows'
id: cache-opencl-win
uses: actions/cache@v5
with:
# Default install location is x86 ...
path: C:\Program Files (x86)\Common Files\Intel\Shared Libraries
key: intel-opencl-runtime-2025.3.1
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache key "intel-opencl-runtime-2025.3.1" does not match the actual version being downloaded. The INTEL_OPENCL_URL points to version 2025.1.0.972, but the cache key references 2025.3.1. This mismatch will cause cache invalidation issues. The cache key should be updated to match the actual version: "intel-opencl-runtime-2025.1.0.972"

Suggested change
key: intel-opencl-runtime-2025.3.1
key: intel-opencl-runtime-2025.1.0.972

Copilot uses AI. Check for mistakes.

- name: Install OpenCL SDK (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
vcpkg install opencl:x64-windows clblast:x64-windows
# Convert to forward slashes to avoid escaping issues in configure.win
$vcpkgPath = "$env:VCPKG_INSTALLATION_ROOT/installed/x64-windows" -replace '\\','/'

# Register OpenCL location
echo "OPENCL_CPPFLAGS=-I$vcpkgPath/include" >> $env:GITHUB_ENV
echo "OPENCL_LIBS=-L$vcpkgPath/lib -lOpenCL" >> $env:GITHUB_ENV

# Register CLBlast location
echo "CLBLAST_CPPFLAGS=-I$vcpkgPath/include" >> $env:GITHUB_ENV
echo "CLBLAST_LIBS=-L$vcpkgPath/lib -lclblast" >> $env:GITHUB_ENV

# Add vcpkg bin to PATH so DLLs can be found at runtime
echo "$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows\bin" >> $env:GITHUB_PATH

- name: Install Intel CPU Runtime for OpenCL (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
# Download
curl -o opencl-installer.exe "${{ env.INTEL_OPENCL_URL }}"

# Extract MSI from the self-extracting exe
$proc = Start-Process "./opencl-installer.exe" "-s -x -f extracted" -NoNewWindow -PassThru
$proc.WaitForExit()

# Install via msiexec
$msi = Get-ChildItem ./extracted/*.msi | Select-Object -First 1
$proc = Start-Process "msiexec" "/i `"$msi`" /qn /l*! install.log" -NoNewWindow -PassThru
$proc.WaitForExit()

if ($proc.ExitCode -ne 0) {
Get-Content install.log
exit $proc.ExitCode
}

Remove-Item -Recurse -Force extracted, opencl-installer.exe
Comment on lines +77 to +98
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache step is configured but never checked for a cache hit. The Intel OpenCL Runtime installation (lines 77-98) runs unconditionally, even if the cache was restored. This wastes build time re-installing when the cache is available. Add a condition like "if: runner.os == 'Windows' && steps.cache-opencl-win.outputs.cache-hit != 'true'" to the installation step.

Copilot uses AI. Check for mistakes.

- name: Register Intel OpenCL ICD (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$dllPath = "C:\Program Files (x86)\Common Files\Intel\Shared Libraries\bin\OpenCL.dll"
REG ADD "HKLM\SOFTWARE\Khronos\OpenCL\Vendors" /v $dllPath /t REG_DWORD /d 0 /f
REG ADD "HKLM\SOFTWARE\Wow6432Node\Khronos\OpenCL\Vendors" /v $dllPath /t REG_DWORD /d 0 /f
Comment on lines +105 to +106
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential security risk: Registry modifications using REG ADD require elevated privileges and should verify success. These commands modify HKLM (HKEY_LOCAL_MACHINE) which typically requires administrator rights. If the commands fail silently, OpenCL runtime won't be properly registered. Add error checking after each REG ADD command to ensure they succeeded, or wrap them in a try-catch block with appropriate error handling.

Copilot uses AI. Check for mistakes.
Add-Content $env:GITHUB_PATH "C:\Program Files (x86)\Common Files\Intel\Shared Libraries\bin\"

- name: Debug OpenCL paths
if: runner.os == 'Windows'
shell: pwsh
run: |
echo "OPENCL_CPPFLAGS: $env:OPENCL_CPPFLAGS"
echo "OPENCL_LIBS: $env:OPENCL_LIBS"
ls "$env:VCPKG_INSTALLATION_ROOT\installed\x64-windows\include\CL"

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::rcmdcheck
Expand Down
184 changes: 184 additions & 0 deletions configure.win
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#!/bin/sh
##
## RcppBandicoot configure.win
##
## Windows-specific configuration script
## Detects OpenCL and CLBlast from environment variables
##
## Copyright (C) 2023-2025 James Balamuta
## Licensed under GPL-2 or later
##

echo "Configuring RcppBandicoot for Windows..."

## Get R_HOME
: ${R_HOME=$(R RHOME)}
if test -z "${R_HOME}"; then
echo "ERROR: Could not determine R_HOME"
exit 1
fi

## Default values
BANDICOOT_CXXFLAGS=""
BANDICOOT_LIBS=""
OPENMP_CXXFLAGS='$(SHLIB_OPENMP_CXXFLAGS)'
OPENCL_TARGET_VERSION=300

## Kernel source directory (matches configure.ac logic)
BANDICOOT_KERNELS_DIR=$("${R_HOME}/bin/Rscript" -e 'cat(paste(head(.libPaths(),1), "RcppBandicoot", "include", "bandicoot_bits", "ks", "", sep="/"))')
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple issues with BANDICOOT_KERNELS_DIR path handling: (1) The path uses forward slashes from R (sep="/") but is being used on Windows where backslashes are native; (2) No validation that the Rscript command succeeded or returned a valid path; (3) The path may contain spaces or special characters that will break sed substitution on line 109. Consider: validating the path exists, using normalizePath() in R for proper Windows path handling, and escaping special sed characters before substitution.

Suggested change
BANDICOOT_KERNELS_DIR=$("${R_HOME}/bin/Rscript" -e 'cat(paste(head(.libPaths(),1), "RcppBandicoot", "include", "bandicoot_bits", "ks", "", sep="/"))')
BANDICOOT_KERNELS_DIR=$("${R_HOME}/bin/Rscript" -e 'p <- file.path(head(.libPaths(), 1L), "RcppBandicoot", "include", "bandicoot_bits", "ks"); p <- normalizePath(p, winslash="\\", mustWork=FALSE); if (dir.exists(p)) cat(p)')
if [ $? -ne 0 ] || [ -z "${BANDICOOT_KERNELS_DIR}" ] || [ ! -d "${BANDICOOT_KERNELS_DIR}" ]; then
echo "ERROR: Could not determine BANDICOOT_KERNELS_DIR"
exit 1
fi

Copilot uses AI. Check for mistakes.

## Always disable CUDA on Windows (requires manual setup)
BANDICOOT_CXXFLAGS="${BANDICOOT_CXXFLAGS} -DCOOT_DONT_USE_CUDA"

## Check for OpenCL headers via environment variable
if [ -n "${OPENCL_CPPFLAGS}" ]; then
echo " OpenCL headers: found (via OPENCL_CPPFLAGS)"
BANDICOOT_CXXFLAGS="${BANDICOOT_CXXFLAGS} -DCOOT_USE_OPENCL ${OPENCL_CPPFLAGS}"
HAVE_OPENCL=1
else
echo " OpenCL headers: not found"
echo " Set OPENCL_CPPFLAGS to specify OpenCL header location"
HAVE_OPENCL=0
fi

## Check for OpenCL library
if [ -n "${OPENCL_LIBS}" ]; then
echo " OpenCL library: found (via OPENCL_LIBS): ${OPENCL_LIBS}"
BANDICOOT_LIBS="${BANDICOOT_LIBS} ${OPENCL_LIBS}"
else
echo " OpenCL library: not found (OPENCL_LIBS not set)"
echo " WARNING: Linking will fail without OpenCL library!"
fi

## Check for CLBlast via environment variable
if [ -n "${CLBLAST_CPPFLAGS}" ]; then
echo " CLBlast: found (via CLBLAST_CPPFLAGS)"
BANDICOOT_CXXFLAGS="${BANDICOOT_CXXFLAGS} -DCOOT_USE_CLBLAST ${CLBLAST_CPPFLAGS}"
HAVE_CLBLAST=1
else
echo " CLBlast: not found, disabling"
BANDICOOT_CXXFLAGS="${BANDICOOT_CXXFLAGS} -DCOOT_DONT_USE_CLBLAST"
HAVE_CLBLAST=0
fi

## Check for CLBlast library
if [ -n "${CLBLAST_LIBS}" ]; then
echo " CLBlast library: ${CLBLAST_LIBS}"
BANDICOOT_LIBS="${BANDICOOT_LIBS} ${CLBLAST_LIBS}"
fi

## Always disable clBLAS (CLBlast is preferred)
BANDICOOT_CXXFLAGS="${BANDICOOT_CXXFLAGS} -DCOOT_DONT_USE_CLBLAS"
HAVE_CLBLAS=0

## Add common flags
BANDICOOT_CXXFLAGS="${OPENMP_CXXFLAGS} ${BANDICOOT_CXXFLAGS}"

## Add R's LAPACK/BLAS
BANDICOOT_LIBS="${BANDICOOT_LIBS} \$(LAPACK_LIBS) \$(BLAS_LIBS) \$(FLIBS)"

## Check if we have at least OpenCL
if [ "${HAVE_OPENCL}" = "0" ]; then
echo ""
echo "WARNING: No GPU backend detected!"
echo ""
echo "RcppBandicoot requires OpenCL headers to compile on Windows."
echo "Set the following environment variables before building:"
echo ""
echo " OPENCL_CPPFLAGS - Path to OpenCL headers (e.g., -IC:/OpenCL/include)"
echo " OPENCL_LIBS - OpenCL library flags (e.g., -LC:/OpenCL/lib -lOpenCL)"
echo " CLBLAST_CPPFLAGS - Path to CLBlast headers (optional)"
echo " CLBLAST_LIBS - CLBlast library flags (optional)"
echo ""
fi
Comment on lines +81 to +93
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script continues to generate R/flags.R even when OpenCL is not detected (HAVE_OPENCL=0). While this may be intentional to allow builds without GPU support, the warning message on lines 82-93 suggests OpenCL is required ("RcppBandicoot requires OpenCL headers to compile on Windows"). This is contradictory. Either the script should exit with an error when HAVE_OPENCL=0, or the warning message should be softened to indicate GPU features will be unavailable but the build can continue.

Copilot uses AI. Check for mistakes.

echo ""
echo "Configuration Summary:"
echo " OpenCL: ${HAVE_OPENCL}"
echo " CLBlast: ${HAVE_CLBLAST}"
echo " CUDA: disabled (Windows)"
echo " Kernels: ${BANDICOOT_KERNELS_DIR}"
echo ""

## Generate Makevars.win from template
if [ -f "src/Makevars.win.in" ]; then
sed -e "s|@BANDICOOT_CXXFLAGS@|${BANDICOOT_CXXFLAGS}|g" \
-e "s|@BANDICOOT_LIBS@|${BANDICOOT_LIBS}|g" \
-e "s|@OPENMP_CXXFLAGS@|${OPENMP_CXXFLAGS}|g" \
-e "s|@OPENCL_TARGET_VERSION@|${OPENCL_TARGET_VERSION}|g" \
-e "s|@BANDICOOT_KERNELS_DIR@|${BANDICOOT_KERNELS_DIR}|g" \
src/Makevars.win.in > src/Makevars.win
Comment on lines +105 to +110
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sed substitution does not escape special sed characters that may appear in the variable values. If BANDICOOT_KERNELS_DIR or other paths contain characters like '&', '', or '/', the sed command will fail or produce incorrect output. The '/' is especially problematic since Windows paths converted from backslashes often use it. Consider escaping these characters before substitution or using a different templating approach.

Copilot uses AI. Check for mistakes.
echo "Generated src/Makevars.win"
else
echo "ERROR: src/Makevars.win.in not found!"
exit 1
fi

## Verify the generated file
if [ -f "src/Makevars.win" ]; then
echo "Contents of src/Makevars.win:"
cat src/Makevars.win
else
echo "ERROR: Failed to generate src/Makevars.win!"
exit 1
fi

## Generate R/flags.R from template
## Set variables for flags.R.in substitution
HAVE_CUDA=0
HAVE_OPENMP=1
DEFAULT_BACKEND="CL_BACKEND"
OPENCL_CXXFLAGS_FOR_R=""
OPENCL_LIBS_FOR_R=""
CUDA_CXXFLAGS=""
CUDA_LIBS=""
CLBLAST_CXXFLAGS_FOR_R=""
CLBLAST_LIBS_FOR_R=""
CLBLAS_CXXFLAGS=""
CLBLAS_LIBS=""
LAPACK_BLAS_LIBS="\$(LAPACK_LIBS) \$(BLAS_LIBS) \$(FLIBS)"
CLBLAST_PREFIX=""
CLBLAS_PREFIX=""
CUDA_HOME=""
SDKPATH=""

## Set OpenCL flags for R if detected
if [ "${HAVE_OPENCL}" = "1" ]; then
OPENCL_CXXFLAGS_FOR_R="-DCOOT_USE_OPENCL ${OPENCL_CPPFLAGS}"
OPENCL_LIBS_FOR_R="${OPENCL_LIBS}"
fi

## Set CLBlast flags for R if detected
if [ "${HAVE_CLBLAST}" = "1" ]; then
CLBLAST_CXXFLAGS_FOR_R="-DCOOT_USE_CLBLAST ${CLBLAST_CPPFLAGS}"
CLBLAST_LIBS_FOR_R="${CLBLAST_LIBS}"
fi

if [ -f "R/flags.R.in" ]; then
sed -e "s|@BANDICOOT_CXXFLAGS@|${BANDICOOT_CXXFLAGS}|g" \
-e "s|@BANDICOOT_LIBS@|${BANDICOOT_LIBS}|g" \
-e "s|@OPENCL_CXXFLAGS@|${OPENCL_CXXFLAGS_FOR_R}|g" \
-e "s|@OPENCL_LIBS@|${OPENCL_LIBS_FOR_R}|g" \
-e "s|@CUDA_CXXFLAGS@|${CUDA_CXXFLAGS}|g" \
-e "s|@CUDA_LIBS@|${CUDA_LIBS}|g" \
-e "s|@CLBLAST_CXXFLAGS@|${CLBLAST_CXXFLAGS_FOR_R}|g" \
-e "s|@CLBLAST_LIBS@|${CLBLAST_LIBS_FOR_R}|g" \
-e "s|@CLBLAS_CXXFLAGS@|${CLBLAS_CXXFLAGS}|g" \
-e "s|@CLBLAS_LIBS@|${CLBLAS_LIBS}|g" \
-e "s|@LAPACK_BLAS_LIBS@|${LAPACK_BLAS_LIBS}|g" \
-e "s|@HAVE_OPENCL@|${HAVE_OPENCL}|g" \
-e "s|@HAVE_CUDA@|${HAVE_CUDA}|g" \
-e "s|@HAVE_CLBLAST@|${HAVE_CLBLAST}|g" \
-e "s|@HAVE_CLBLAS@|${HAVE_CLBLAS}|g" \
-e "s|@HAVE_OPENMP@|${HAVE_OPENMP}|g" \
-e "s|@DEFAULT_BACKEND@|${DEFAULT_BACKEND}|g" \
-e "s|@CLBLAST_PREFIX@|${CLBLAST_PREFIX}|g" \
-e "s|@CLBLAS_PREFIX@|${CLBLAS_PREFIX}|g" \
-e "s|@CUDA_HOME@|${CUDA_HOME}|g" \
-e "s|@SDKPATH@|${SDKPATH}|g" \
R/flags.R.in > R/flags.R
echo "Generated R/flags.R"
else
echo "ERROR: R/flags.R.in not found!"
exit 1
fi
2 changes: 2 additions & 0 deletions src/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.o
*.so
*.dll
Makevars
Makevars.win
11 changes: 0 additions & 11 deletions src/Makevars.win

This file was deleted.

12 changes: 12 additions & 0 deletions src/Makevars.win.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## RcppBandicoot Makevars.win.in
##
## This file is processed by configure.win to generate Makevars.win
## It includes GPU backend configuration (OpenCL, CLBlast) for Windows

PKG_CPPFLAGS = -I../inst/include -DCOOT_TARGET_OPENCL_VERSION=@OPENCL_TARGET_VERSION@ -DCOOT_KERNEL_SOURCE_DIR=\"@BANDICOOT_KERNELS_DIR@\"

## Compiler flags from configure.win
PKG_CXXFLAGS = @BANDICOOT_CXXFLAGS@

## Linker flags from configure.win
PKG_LIBS = @OPENMP_CXXFLAGS@ @BANDICOOT_LIBS@
Loading