From 7daf200748f3c2a9a539490d065a5a78096789e7 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 10 Sep 2026 13:35:35 +0200 Subject: [PATCH] build Windows with clang-cl instead of MSVC clang-cl keeps the MSVC ABI, so the Windows SDK, the vcpkg packages and D3D12 all still link; only the front end changes. That front end is the one whose module support has been giving way - global module fragment merging and type completeness at a template's instantiation point. Switches the job to Ninja, which is where CMake's module scanning is best supported, with vcvars64 for the SDK paths. Ninja is single-config, so the artifacts move from build/bin// to build/bin/. CMakeLists: the MSVC-only blocks tested CMAKE_CXX_COMPILER_ID, which clang-cl reports as Clang, so the version resource, the icon and /utf-8 would have been dropped silently. They test MSVC now, which is true for both. /MAP and /MP stay behind a real-MSVC check - the first is a link.exe spelling, the second clang-cl rejects. --- .github/workflows/build_bin.yml | 59 ++++++++++++++++++++------------- CMakeLists.txt | 29 +++++++++++----- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build_bin.yml b/.github/workflows/build_bin.yml index 9219ed6d..60dce0c4 100644 --- a/.github/workflows/build_bin.yml +++ b/.github/workflows/build_bin.yml @@ -24,11 +24,11 @@ env: jobs: # ============================================================ - # Windows / MSVC + # Windows / Clang (clang-cl) # ============================================================ windows: - name: Windows x64 / MSVC + name: Windows x64 / Clang runs-on: windows-2022 steps: @@ -45,16 +45,27 @@ jobs: python-version: "3.14" architecture: "x64" + # clang-cl rather than plain clang: it keeps the MSVC ABI, so it links + # against the same Windows SDK, vcpkg packages and D3D12 libraries, and + # only the front end changes. Pinned to the version the Linux job uses. + - name: Install LLVM and Ninja + shell: pwsh + run: | + choco install llvm --version=22.1.8 -y --no-progress + choco install ninja -y --no-progress + - name: Show environment shell: pwsh run: | python --version cmake --version + ninja --version + & "$env:ProgramFiles\LLVM\bin\clang-cl.exe" --version Write-Host "Python:" Get-Command python - Write-Host "MSVC:" + Write-Host "Visual Studio (for the SDK and the MSVC STL):" & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" ` -latest ` -products * ` @@ -67,30 +78,32 @@ jobs: run: | call setup.bat + # Ninja, not MSBuild: CMake's module dependency scanning is best supported + # there, and vcvars64 supplies the SDK and library paths clang-cl needs. - name: Configure - shell: pwsh + shell: cmd run: | - $pythonExe = "${{ steps.python.outputs.python-path }}" - $pythonRoot = Split-Path $pythonExe - - Write-Host "Python root: $pythonRoot" - - cmake -S . -B build ` - -G "Visual Studio 17 2022" ` - -A x64 ` - "-DPython3_ROOT_DIR=$pythonRoot" + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSPATH=%%i + call "%VSPATH%\VC\Auxiliary\Build\vcvars64.bat" + for %%p in ("${{ steps.python.outputs.python-path }}") do set PYROOT=%%~dpp + cmake -S . -B build ^ + -G Ninja ^ + -DCMAKE_BUILD_TYPE=%CONFIG_WIN% ^ + -DCMAKE_C_COMPILER="%ProgramFiles%/LLVM/bin/clang-cl.exe" ^ + -DCMAKE_CXX_COMPILER="%ProgramFiles%/LLVM/bin/clang-cl.exe" ^ + -DPython3_ROOT_DIR=%PYROOT% - name: Build - shell: pwsh + shell: cmd run: | - cmake --build build ` - --config $env:CONFIG_WIN ` - --parallel + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set VSPATH=%%i + call "%VSPATH%\VC\Auxiliary\Build\vcvars64.bat" + cmake --build build --parallel - name: Copy shaders shell: pwsh run: | - $output = "build/bin/$env:CONFIG_WIN" + $output = "build/bin" New-Item ` -ItemType Directory ` @@ -108,7 +121,7 @@ jobs: with: name: maszyna-windows-x64-${{ env.CONFIG_WIN }} path: | - build/bin/${{ env.CONFIG_WIN }}/ + build/bin/ if-no-files-found: error retention-days: 14 @@ -117,18 +130,18 @@ jobs: with: name: maszyna-windows-x64-symbols-${{ env.CONFIG_WIN }} path: | - build/pdb/${{ env.CONFIG_WIN }}/*.pdb - build/bin/${{ env.CONFIG_WIN }}/*.map + build/pdb/*.pdb + build/bin/*.map if-no-files-found: warn retention-days: 14 # ============================================================ - # Linux / GCC + # Linux / Clang # ============================================================ linux: - name: Linux x64 / GCC + name: Linux x64 / Clang runs-on: ubuntu-24.04 steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index d13a0a7b..e9f4da47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,9 +17,10 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/CMake_modules/") set(DEPS_DIR ${DEPS_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/ref") project("eu07") -# Clang is the only compiler this project is built and tested with on Linux -# (Clang 22 in CI); MSVC covers Windows. GCC is not supported: its lazy loading -# of module interfaces is broken here, and working around it costs roughly twice +# Clang is the compiler this project is built and tested with: clang on Linux, +# clang-cl on Windows, both pinned to 22 in CI. MSVC still configures and is not +# rejected, but nothing verifies it. GCC is not supported: its lazy loading of +# module interfaces is broken here, and working around it costs roughly twice # the memory per compiler process. if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang|MSVC") message(FATAL_ERROR @@ -444,7 +445,12 @@ set(GLM_INCLUDE_DIR ${GLM_INCLUDE_DIR} "${DEPS_DIR}/glm/") configure_file(${CMAKE_SOURCE_DIR}/eu07.rc.in ${CMAKE_BINARY_DIR}/eu07.rc @ONLY) -if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) +# MSVC is true for clang-cl as well - it targets the same ABI and takes the same +# command line. Testing CMAKE_CXX_COMPILER_ID instead would silently drop the +# version resource and the icon from a clang-cl build. +if (MSVC) + # the Visual Studio generators enable RC on their own; Ninja does not + enable_language(RC) set(SOURCES ${SOURCES} ${CMAKE_BINARY_DIR}/eu07.rc) set(SOURCES ${SOURCES} eu07.ico) add_compile_options("/utf-8") @@ -508,18 +514,23 @@ target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_BINARY_DIR}/geninc" "${GLOBAL_INCLUDE_DIR}") -if (${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) +if (MSVC) # override cmake defaults set(CMAKE_CXX_FLAGS_RELWITHDEBINFO " /MD /Zi /O2 /DNDEBUG") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO " /DEBUG /INCREMENTAL:NO /OPT:REF /OPT:ICF") - target_link_options(${PROJECT_NAME} PRIVATE "/MAP") - # /wd4996: disable "deprecation" warnings # /wd4244: disable warnings for conversion with possible loss of data # /wd5033: disable because it is all over Python headers set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4996 /wd4244 /wd5033") set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/LARGEADDRESSAWARE") + + # /MAP is a link.exe option; lld-link, which clang-cl usually drives, spells + # it differently. The map only feeds the debug-symbols artifact, whose upload + # tolerates it being absent. + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_link_options(${PROJECT_NAME} PRIVATE "/MAP") + endif() endif() set_target_properties( ${PROJECT_NAME} @@ -724,7 +735,9 @@ if(GENERATE_PDB) endif() endif() -if(ENABLE_MCC AND MSVC) +# /MP is an MSVC-only option; clang-cl rejects it, and under Ninja the generator +# already runs one compiler process per core. +if(ENABLE_MCC AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_GENERATOR MATCHES "Ninja") message(STATUS "Enabling multi-processor compilation for MSVC.") add_compile_options(/MP) endif()