diff --git a/.github/sycl-build-deps.env b/.github/sycl-build-deps.env index fb0ab0ea63..f1e2c5cd7c 100644 --- a/.github/sycl-build-deps.env +++ b/.github/sycl-build-deps.env @@ -1,8 +1,10 @@ -# Open source SYCL build deps, loaded by os-llvm-sycl-build.yml and bumped by -# bump-sycl-deps.yml from intel/llvm devops/dependencies.json. +# Open source SYCL build deps, loaded by os-llvm-sycl-build.yml and +# os-llvm-sycl-build-windows.yml, and bumped by bump-sycl-deps.yml from +# intel/llvm devops/dependencies.json. # Kept out of .github/workflows/ since GITHUB_TOKEN can't push workflow files. DRIVER_PATH=2026-WW28 OCLCPUEXP_FN=oclcpuexp-2026.22.6.1.17_160000_rel.tar.gz +WIN_OCLCPUEXP_FN=win-oclcpuexp-2026.22.6.1.17_160000_rel.zip TBB_URL=https://github.com/uxlfoundation/oneTBB/releases/download/v2023.1.0/ TBB_INSTALL_DIR=oneapi-tbb-2023.1.0 TBB_FN=oneapi-tbb-2023.1.0-lin.tgz diff --git a/.github/workflows/bump-sycl-deps.yml b/.github/workflows/bump-sycl-deps.yml index 225426a26a..5da83c33d3 100644 --- a/.github/workflows/bump-sycl-deps.yml +++ b/.github/workflows/bump-sycl-deps.yml @@ -1,7 +1,8 @@ name: Bump open source SYCL build deps # Syncs the oclcpuexp and oneTBB pins in .github/sycl-build-deps.env, used by -# os-llvm-sycl-build.yml, with intel/llvm devops/dependencies.json. +# os-llvm-sycl-build.yml and os-llvm-sycl-build-windows.yml, with intel/llvm +# devops/dependencies.json. on: schedule: @@ -63,9 +64,11 @@ jobs: OCL_TAG=$(jq -er '.linux.oclcpu.github_tag' "${DEPS}") OCL_URL=$(jq -er '.linux.oclcpu.url' "${DEPS}") + WIN_OCL_URL=$(jq -er '.windows.oclcpu.url' "${DEPS}") TBB_VER=$(jq -er '.linux.tbb.version' "${DEPS}") TBB_FULL_URL=$(jq -er '.linux.tbb.url' "${DEPS}") OCLCPUEXP_FN=${OCL_URL##*/} + WIN_OCLCPUEXP_FN=${WIN_OCL_URL##*/} # os-llvm-sycl-build.yml rebuilds these URLs from the pins [[ "${OCL_TAG}" =~ ^[0-9]{4}-WW[0-9]+$ ]] || fail "unexpected oclcpu tag: ${OCL_TAG}" @@ -73,6 +76,11 @@ jobs: || fail "unexpected oclcpu asset: ${OCLCPUEXP_FN}" [[ "${OCL_URL}" == "https://github.com/intel/llvm/releases/download/${OCL_TAG}/${OCLCPUEXP_FN}" ]] \ || fail "unexpected oclcpu url: ${OCL_URL}" + # both platforms download from the same DRIVER_PATH release + [[ "${WIN_OCLCPUEXP_FN}" =~ ^win-oclcpuexp-[0-9A-Za-z._]+_rel\.zip$ ]] \ + || fail "unexpected Windows oclcpu asset: ${WIN_OCLCPUEXP_FN}" + [[ "${WIN_OCL_URL}" == "https://github.com/intel/llvm/releases/download/${OCL_TAG}/${WIN_OCLCPUEXP_FN}" ]] \ + || fail "unexpected Windows oclcpu url: ${WIN_OCL_URL}" [[ "${TBB_VER}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "unexpected tbb version: ${TBB_VER}" [[ "${TBB_FULL_URL}" == "https://github.com/uxlfoundation/oneTBB/releases/download/v${TBB_VER}/oneapi-tbb-${TBB_VER}-lin.tgz" ]] \ || fail "unexpected tbb url: ${TBB_FULL_URL}" @@ -81,6 +89,7 @@ jobs: echo "llvm_sha=${LLVM_SHA}" echo "driver_tag=${OCL_TAG}" echo "oclcpuexp_fn=${OCLCPUEXP_FN}" + echo "win_oclcpuexp_fn=${WIN_OCLCPUEXP_FN}" echo "tbb_ver=${TBB_VER}" echo "tbb_url=${TBB_FULL_URL%/*}/" echo "tbb_fn=${TBB_FULL_URL##*/}" @@ -91,6 +100,7 @@ jobs: env: DRIVER_TAG: ${{ steps.resolve.outputs.driver_tag }} OCLCPUEXP_FN: ${{ steps.resolve.outputs.oclcpuexp_fn }} + WIN_OCLCPUEXP_FN: ${{ steps.resolve.outputs.win_oclcpuexp_fn }} TBB_URL: ${{ steps.resolve.outputs.tbb_url }} TBB_FN: ${{ steps.resolve.outputs.tbb_fn }} TBB_DIR: ${{ steps.resolve.outputs.tbb_dir }} @@ -99,6 +109,7 @@ jobs: sed -i -E \ -e "s|^(DRIVER_PATH=).*|\1${DRIVER_TAG}|" \ -e "s|^(OCLCPUEXP_FN=).*|\1${OCLCPUEXP_FN}|" \ + -e "s|^(WIN_OCLCPUEXP_FN=).*|\1${WIN_OCLCPUEXP_FN}|" \ -e "s|^(TBB_URL=).*|\1${TBB_URL}|" \ -e "s|^(TBB_INSTALL_DIR=).*|\1${TBB_DIR}|" \ -e "s|^(TBB_FN=).*|\1${TBB_FN}|" \ @@ -114,9 +125,10 @@ jobs: delete-branch: true labels: autoupdate commit-message: | - Bump oclcpuexp/oneTBB pins for os-llvm-sycl-build workflow + Bump oclcpuexp/oneTBB pins for os-llvm-sycl-build workflows oclcpuexp: ${{ steps.resolve.outputs.driver_tag }} / ${{ steps.resolve.outputs.oclcpuexp_fn }} + oclcpuexp (Windows): ${{ steps.resolve.outputs.win_oclcpuexp_fn }} oneTBB: ${{ steps.resolve.outputs.tbb_ver }} intel/llvm: ${{ steps.resolve.outputs.llvm_sha }} title: "Bump open source SYCL build dependencies" @@ -128,7 +140,10 @@ jobs: | --- | --- | | intel/llvm driver release | `${{ steps.resolve.outputs.driver_tag }}` | | oclcpuexp | `${{ steps.resolve.outputs.oclcpuexp_fn }}` | + | oclcpuexp (Windows) | `${{ steps.resolve.outputs.win_oclcpuexp_fn }}` | | oneTBB | `${{ steps.resolve.outputs.tbb_ver }}` | Pull requests opened by this workflow don't trigger CI: run - **Build with Open Source LLVM SYCL compiler** on this branch before merging. + **Build with Open Source LLVM SYCL compiler** and + **Build with Open Source LLVM SYCL compiler on Windows** on this + branch before merging. diff --git a/.github/workflows/os-llvm-sycl-build-windows.yml b/.github/workflows/os-llvm-sycl-build-windows.yml new file mode 100644 index 0000000000..a83ada6bab --- /dev/null +++ b/.github/workflows/os-llvm-sycl-build-windows.yml @@ -0,0 +1,180 @@ +name: Build with Open Source LLVM SYCL compiler on Windows +on: + pull_request: + push: + branches: [master] + workflow_dispatch: + inputs: + nightly-tag: + description: "intel/llvm nightly tag, e.g. nightly-2026-11-03 (default: latest with a Windows build)" + required: false + default: "" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + install-compiler: + name: Build with nightly build of DPC++ toolchain on Windows + runs-on: windows-latest + timeout-minutes: 120 + + env: + GH_TOKEN: ${{ github.token }} + PINS: .github/sycl-build-deps.env + + steps: + - name: Checkout repo + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Load pinned SYCL build deps + shell: bash + run: | + set -euo pipefail + # checkout may convert line endings to CRLF + VARS=$(grep -E '^(DRIVER_PATH|WIN_OCLCPUEXP_FN)=' "${PINS}" | tr -d '\r' || true) + if [[ $(wc -l <<< "${VARS}") -ne 2 ]]; then + echo "::error::expected 2 pins in ${PINS}, got:" + echo "${VARS}" + exit 1 + fi + echo "${VARS}" | tee -a "${GITHUB_ENV}" + + - name: Resolve nightly build + shell: bash + env: + NIGHTLY_TAG: ${{ inputs.nightly-tag }} + run: | + set -euo pipefail + if [[ -z "${NIGHTLY_TAG}" ]]; then + NIGHTLY_TAG=$(gh api 'repos/intel/llvm/releases?per_page=30' \ + --jq '[.[] | select(.tag_name | startswith("nightly-")) + | select(any(.assets[]; .name == "sycl_windows.tar.gz"))][0].tag_name // empty') + fi + if [[ ! "${NIGHTLY_TAG}" =~ ^nightly-[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then + echo "::error::unexpected nightly tag: ${NIGHTLY_TAG}" + exit 1 + fi + echo "NIGHTLY_TAG=${NIGHTLY_TAG}" | tee -a "${GITHUB_ENV}" + + - name: Download and install nightly and components + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + $ProgressPreference = 'SilentlyContinue' + + $root = Join-Path $env:RUNNER_TEMP 'sycl_bundle' + $compiler = Join-Path $root 'dpcpp_compiler' + $oclcpu = Join-Path $root 'oclcpuexp' + New-Item -ItemType Directory -Force -Path $compiler, $oclcpu | Out-Null + + gh release download $env:NIGHTLY_TAG -R intel/llvm -p sycl_windows.tar.gz -D $root + $bundle = Join-Path $root 'sycl_windows.tar.gz' + & "$env:SystemRoot\System32\tar.exe" -xzf $bundle -C $compiler + Remove-Item $bundle + + gh release download $env:DRIVER_PATH -R intel/llvm -p $env:WIN_OCLCPUEXP_FN -D $root + $zip = Join-Path $root $env:WIN_OCLCPUEXP_FN + Expand-Archive -Path $zip -DestinationPath $oclcpu + Remove-Item $zip + + # register the CPU runtime with the ICD loader without install.bat; + # runner steps are elevated, so the loader ignores OCL_ICD_FILENAMES + $vendors = 'HKLM:\SOFTWARE\Khronos\OpenCL\Vendors' + if (-not (Test-Path $vendors)) { + # -Force creates the missing parent keys + New-Item -Path $vendors -Force | Out-Null + } + New-ItemProperty -Path $vendors -Name (Join-Path $oclcpu 'intelocl64.dll') ` + -PropertyType DWord -Value 0 -Force | Out-Null + # the runtime directory on PATH also provides tbb12.dll + Add-Content -Path $env:GITHUB_ENV -Value "SYCL_BUNDLE_FOLDER=$root" + Add-Content -Path $env:GITHUB_PATH -Value $oclcpu + Add-Content -Path $env:GITHUB_PATH -Value (Join-Path $compiler 'bin') + + - name: Setup Python + uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 + with: + python-version: '3.15' + architecture: x64 + + - name: Create virtual environment + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + + $venv = Join-Path $env:RUNNER_TEMP 'venv' + python -m venv $venv + # dpctl adds \Library\bin to the DLL search path, so link it to + # the DPC++ runtime + New-Item -ItemType Directory -Path (Join-Path $venv 'Library') | Out-Null + New-Item -ItemType Junction -Path (Join-Path $venv 'Library\bin') ` + -Target (Join-Path $env:SYCL_BUNDLE_FOLDER 'dpcpp_compiler\bin') | Out-Null + Add-Content -Path $env:GITHUB_ENV -Value "VIRTUAL_ENV=$venv" + Add-Content -Path $env:GITHUB_PATH -Value (Join-Path $venv 'Scripts') + + - name: Install dpctl dependencies + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + python -m pip install numpy cython "setuptools<80" pytest scikit-build cmake ninja "versioneer[toml]==0.29" + + - name: Report compiler version + shell: pwsh + run: clang-cl --version + + - name: Run sycl-ls + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + $devices = sycl-ls + $devices + if (-not ($devices -match '^\[opencl:cpu\]')) { + sycl-ls --verbose + Write-Output '::error::no OpenCL CPU device found' + exit 1 + } + + - name: Build dpctl + shell: cmd + run: | + set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" + for /f "usebackq delims=" %%i in (`"%VSWHERE%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VS_PATH=%%i" + if not defined VS_PATH ( + echo ::error::Visual Studio with MSVC x64 tools not found + exit /b 1 + ) + call "%VS_PATH%\VC\Auxiliary\Build\vcvars64.bat" || exit /b 1 + rem -fsycl links sycl9.lib, which the linker looks up on LIB + set "LIB=%SYCL_BUNDLE_FOLDER%\dpcpp_compiler\lib;%LIB%" + rem link.exe can't link the LTO bitcode pybind11 would otherwise build + python scripts\build_locally.py --c-compiler=clang-cl.exe --cxx-compiler=clang-cl.exe ^ + --compiler-root="%SYCL_BUNDLE_FOLDER%\dpcpp_compiler\bin" ^ + --cmake-opts="-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF" || exit /b 1 + + - name: Run lsplatforms + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + python -m dpctl -f + + - name: Run dpctl/tests + shell: pwsh + env: + SYCL_CACHE_PERSISTENT: 1 + run: | + $ErrorActionPreference = 'Stop' + $PSNativeCommandUseErrorActionPreference = $true + python -m pytest -sv dpctl/tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 594dd0bc24..af0ba58f46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,11 @@ cmake_minimum_required(VERSION 3.21...3.27 FATAL_ERROR) +# link clang-cl targets through the compiler driver +set(CMAKE_USER_MAKE_RULES_OVERRIDE_C + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/WindowsClangClLinkRules.cmake) +set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/WindowsClangClLinkRules.cmake) + project(dpctl VERSION 0.24 LANGUAGES CXX diff --git a/cmake/WindowsClangClLinkRules.cmake b/cmake/WindowsClangClLinkRules.cmake new file mode 100644 index 0000000000..d900d7e383 --- /dev/null +++ b/cmake/WindowsClangClLinkRules.cmake @@ -0,0 +1,49 @@ +# CMake links clang-cl targets by calling the linker directly, so link options +# such as -fsycl never reach the compiler driver. Link through the driver +# instead, like Platform/Windows-IntelLLVM does for icx, passing linker flags +# with -Xlinker (clang-cl drops -Wl, arguments). + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + return() +endif() + +foreach(_lang C CXX) + if(NOT CMAKE_${_lang}_COMPILER_ID STREQUAL "Clang" + OR NOT CMAKE_${_lang}_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" + OR CMAKE_${_lang}_LINK_MODE STREQUAL "DRIVER") + continue() + endif() + + if(NOT _dpctl_clang_cl_linker_flags_wrapped) + set(_dpctl_clang_cl_linker_flags_wrapped TRUE) + foreach(_t EXE SHARED MODULE) + foreach(_cfg "" _DEBUG _RELEASE _RELWITHDEBINFO _MINSIZEREL) + set(_var CMAKE_${_t}_LINKER_FLAGS${_cfg}_INIT) + separate_arguments(_flags WINDOWS_COMMAND "${${_var}}") + list(TRANSFORM _flags PREPEND "-Xlinker ") + list(JOIN _flags " " ${_var}) + endforeach() + endforeach() + set(CMAKE_LIBRARY_PATH_FLAG "-Xlinker /LIBPATH:") + set(CMAKE_LINK_DEF_FILE_FLAG "-Xlinker /DEF:") + endif() + + set(CMAKE_${_lang}_LINK_MODE DRIVER) + set(CMAKE_${_lang}_LINKER_WRAPPER_FLAG "-Xlinker" " ") + unset(CMAKE_${_lang}_LINKER_WRAPPER_FLAG_SEP) + set(CMAKE_${_lang}_LINK_DEF_FILE_FLAG "-Xlinker /DEF:") + set(CMAKE_${_lang}_CREATE_WIN32_EXE "-Xlinker /subsystem:windows") + set(CMAKE_${_lang}_CREATE_CONSOLE_EXE "-Xlinker /subsystem:console") + + set(CMAKE_${_lang}_LINK_EXECUTABLE + "${_CMAKE_VS_LINK_EXE} ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} -link /out: /implib: /pdb: /version:.${_PLATFORM_LINK_FLAGS} ${CMAKE_END_TEMP_FILE}") + set(CMAKE_${_lang}_CREATE_SHARED_LIBRARY + "${_CMAKE_VS_LINK_DLL} ${CMAKE_CL_NOLOGO} ${CMAKE_START_TEMP_FILE} -LD -link /out: /implib: /pdb: /version:.${_PLATFORM_LINK_FLAGS} ${CMAKE_END_TEMP_FILE}") + set(CMAKE_${_lang}_CREATE_SHARED_MODULE "${CMAKE_${_lang}_CREATE_SHARED_LIBRARY}") +endforeach() + +unset(_lang) +unset(_t) +unset(_cfg) +unset(_var) +unset(_flags) diff --git a/dpctl/CMakeLists.txt b/dpctl/CMakeLists.txt index 9c9d4f9cad..dab02b8117 100644 --- a/dpctl/CMakeLists.txt +++ b/dpctl/CMakeLists.txt @@ -6,8 +6,14 @@ set(CYTHON_FLAGS "-t -w \"${CMAKE_SOURCE_DIR}\"") find_package(Cython REQUIRED) if(WIN32) + # clang-cl reads -Wall as /Wall, i.e. -Weverything + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(_dpctl_wall_flag "/W3 ") + else() + set(_dpctl_wall_flag "-Wall ") + endif() string(CONCAT WARNING_FLAGS - "-Wall " + "${_dpctl_wall_flag}" "-Wextra " "-Winit-self " "-Wunused-function " @@ -35,7 +41,7 @@ if(WIN32) "${CMAKE_CXX_FLAGS_DEBUG} ${WARNING_FLAGS} ${SDL_FLAGS} -O1 -g1 -DDEBUG" ) set(CMAKE_MODULE_LINKER_FLAGS_COVERAGE "${CMAKE_MODULE_LINKER_FLAGS_DEBUG}") - set(DPCTL_LDFLAGS "/NXCompat;/DynamicBase") + set(DPCTL_LDFLAGS "/NXCompat,/DynamicBase") mark_as_advanced( CMAKE_CXX_FLAGS_COVERAGE CMAKE_C_FLAGS_COVERAGE diff --git a/libsyclinterface/CMakeLists.txt b/libsyclinterface/CMakeLists.txt index 774e1e9cef..87e4ceb23b 100644 --- a/libsyclinterface/CMakeLists.txt +++ b/libsyclinterface/CMakeLists.txt @@ -181,8 +181,14 @@ configure_file( set(CMAKE_CXX_STANDARD 17) if(WIN32) + # clang-cl reads -Wall as /Wall, i.e. -Weverything + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(_dpctl_wall_flag "/W3 ") + else() + set(_dpctl_wall_flag "-Wall ") + endif() string(CONCAT WARNING_FLAGS - "-Wall " + "${_dpctl_wall_flag}" "-Wextra " "-Winit-self " "-Wunused-function "