[llvm] workflows/release-binaries: Improve Windows installer (PR #220414)
Alexandre Ganea via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 05:41:52 PDT 2026
https://github.com/aganea updated https://github.com/llvm/llvm-project/pull/220414
>From 411e160c086f59885e1c909811c1880dd12626e2 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Mon, 31 Aug 2026 15:25:16 -0400
Subject: [PATCH 1/7] Fix some unset WiX settings
---
llvm/CMakeLists.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 44299d51d784a1..c84a297b34902b 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -503,6 +503,12 @@ if(WIN32 AND NOT UNIX)
# cabinet itself, and CAB supports only MSZIP/LZX/Quantum, so an MSI cannot
# use LZMA the way the NSIS generator does.
set(CPACK_WIX_LIGHT_EXTRA_FLAGS "-sval" "-dcl:high")
+ # Make the LLVM installation available for all users.
+ set(CPACK_WIX_INSTALL_SCOPE "perMachine")
+ # Identifies the LLVM product line accross all versions. Must not be changed.
+ # Ensures previous installations are uninstalled and do not live side by
+ # side.
+ set(CPACK_WIX_UPGRADE_GUID "B08613CD-8BD0-4FB6-8937-621936604DE3")
endif()
endif()
include(CPack)
>From 14d3d9e424adc9394956b75a0f7f5a434649aeba Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Tue, 1 Sep 2026 12:12:30 -0400
Subject: [PATCH 2/7] Release notes
---
llvm/docs/ReleaseNotes.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 5c288a0ee6fa74..d39f2c4125c328 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -227,6 +227,10 @@ Makes programs 10x faster by doing Special New Thing.
### Changes to the Windows Target
+* The project has migrated to MSI installers. Previous installations of LLVM,
+ prior (and including) 23.1.0, must be manually uninstalled first, before
+ installing this new release.
+
### Changes to the X86 Backend
### Changes to the OCaml bindings
>From b49d1047858cc9c7eccb0708f137ca2ed7d4bffb Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Tue, 1 Sep 2026 17:36:52 -0400
Subject: [PATCH 3/7] Fix older cmake versions
---
llvm/CMakeLists.txt | 11 +++++++++--
llvm/cmake/WiXPerMachinePatch.xml | 5 +++++
2 files changed, 14 insertions(+), 2 deletions(-)
create mode 100644 llvm/cmake/WiXPerMachinePatch.xml
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index c84a297b34902b..0a268f4fe641a8 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -503,8 +503,15 @@ if(WIN32 AND NOT UNIX)
# cabinet itself, and CAB supports only MSZIP/LZX/Quantum, so an MSI cannot
# use LZMA the way the NSIS generator does.
set(CPACK_WIX_LIGHT_EXTRA_FLAGS "-sval" "-dcl:high")
- # Make the LLVM installation available for all users.
- set(CPACK_WIX_INSTALL_SCOPE "perMachine")
+ # Make the LLVM installation available for all users. CPack only gained
+ # CPACK_WIX_INSTALL_SCOPE in CMake 3.29, so inject the equivalent ALLUSERS
+ # property when packaging with an older CMake supported by LLVM.
+ if(CMAKE_VERSION VERSION_LESS "3.29")
+ list(APPEND CPACK_WIX_PATCH_FILE
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/WiXPerMachinePatch.xml")
+ else()
+ set(CPACK_WIX_INSTALL_SCOPE "perMachine")
+ endif()
# Identifies the LLVM product line accross all versions. Must not be changed.
# Ensures previous installations are uninstalled and do not live side by
# side.
diff --git a/llvm/cmake/WiXPerMachinePatch.xml b/llvm/cmake/WiXPerMachinePatch.xml
new file mode 100644
index 00000000000000..6780214b0b6965
--- /dev/null
+++ b/llvm/cmake/WiXPerMachinePatch.xml
@@ -0,0 +1,5 @@
+<CPackWiXPatch>
+ <CPackWiXFragment Id="#PRODUCT">
+ <Property Id="ALLUSERS" Value="1"/>
+ </CPackWiXFragment>
+</CPackWiXPatch>
>From 5533a614c3fd110fac7542480fe03fca00717d7b Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Wed, 2 Sep 2026 09:25:50 -0400
Subject: [PATCH 4/7] Review comments
---
llvm/CMakeLists.txt | 1 +
llvm/docs/ReleaseNotes.md | 10 ++++++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 0a268f4fe641a8..0bb722c74b5ea8 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -506,6 +506,7 @@ if(WIN32 AND NOT UNIX)
# Make the LLVM installation available for all users. CPack only gained
# CPACK_WIX_INSTALL_SCOPE in CMake 3.29, so inject the equivalent ALLUSERS
# property when packaging with an older CMake supported by LLVM.
+ # TODO: remove after transition to CMake 3.31.
if(CMAKE_VERSION VERSION_LESS "3.29")
list(APPEND CPACK_WIX_PATCH_FILE
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/WiXPerMachinePatch.xml")
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index d39f2c4125c328..9d9fab28f98599 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -150,6 +150,12 @@ Makes programs 10x faster by doing Special New Thing.
`LLVM_ALL_EXPERIMENTAL_TARGETS` to `LLVM_ALL_TARGETS`. It is now built by
default and no longer requires `LLVM_EXPERIMENTAL_TARGETS_TO_BUILD`.
+### Changes to the Windows installer
+
+* The project has migrated to MSI installers. Previous installations of LLVM,
+ prior (and including) 23.1.0, must be manually uninstalled first, before
+ installing this new release.
+
### Changes to TableGen
* `!cond` operator short-circuits at the first `true` condition. Subsequent
@@ -227,10 +233,6 @@ Makes programs 10x faster by doing Special New Thing.
### Changes to the Windows Target
-* The project has migrated to MSI installers. Previous installations of LLVM,
- prior (and including) 23.1.0, must be manually uninstalled first, before
- installing this new release.
-
### Changes to the X86 Backend
### Changes to the OCaml bindings
>From 39111a6abb8fbe9b87e6462d2c97c482a89f9b57 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Wed, 2 Sep 2026 14:49:59 -0400
Subject: [PATCH 5/7] Bikeshed comment
---
llvm/CMakeLists.txt | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 0bb722c74b5ea8..cec32391f97bb2 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -513,9 +513,10 @@ if(WIN32 AND NOT UNIX)
else()
set(CPACK_WIX_INSTALL_SCOPE "perMachine")
endif()
- # Identifies the LLVM product line accross all versions. Must not be changed.
- # Ensures previous installations are uninstalled and do not live side by
- # side.
+ # Permanent WiX UpgradeCode for official LLVM MSI packages. Windows Installer
+ # uses this value to recognize related releases and remove an older LLVM
+ # installation during an upgrade. It must remain identical across all future
+ # releases and release branches. DO NOT regenerate or change this GUID.
set(CPACK_WIX_UPGRADE_GUID "B08613CD-8BD0-4FB6-8937-621936604DE3")
endif()
endif()
>From 37ddca444ff35e69482a843afa4f7ba418bbeee5 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Fri, 4 Sep 2026 07:56:30 -0400
Subject: [PATCH 6/7] Validate MSI upgrade code in build script
---
llvm/utils/release/build_llvm_release.bat | 44 +++++++++++++++++++++--
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/llvm/utils/release/build_llvm_release.bat b/llvm/utils/release/build_llvm_release.bat
index 66c4a0380667a3..2d77ed8f09b619 100644
--- a/llvm/utils/release/build_llvm_release.bat
+++ b/llvm/utils/release/build_llvm_release.bat
@@ -40,7 +40,7 @@ set arm64=
set skip-checkout=
set local-python=
set force-msvc=
-set fast-build=
+set fast-build=
call :parse_args %*
if "%help%" NEQ "" goto usage
@@ -284,6 +284,7 @@ ninja check-lld || exit /b 1
REM ninja check-runtimes || exit /b 1
REM ninja check-clang-tools || exit /b 1
ninja package || exit /b 1
+call :verify_msi_upgrade_code || exit /b 1
cd ..
exit /b 0
@@ -357,7 +358,7 @@ mkdir build_%arch%
cd build_%arch%
if "%fast-build%" neq "true" (
call :do_generate_profile || exit /b 1
-)
+)
cmake -GNinja %cmake_flags% ^
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb;flang;mlir" ^
-DLLVM_ENABLE_RUNTIMES="compiler-rt;openmp" ^
@@ -377,6 +378,7 @@ REM ninja check-flang || exit /b 1
REM ninja check-mlir || exit /b 1
REM ninja check-lldb || exit /b 1
ninja package || exit /b 1
+call :verify_msi_upgrade_code || exit /b 1
:: generate tarball with install toolchain only off
if "%arch%"=="amd64" (
@@ -419,6 +421,42 @@ exit /b 0
::=============================================================================
+::==============================================================================
+:: Verify that the generated MSI has LLVM's permanent UpgradeCode.
+::==============================================================================
+:verify_msi_upgrade_code
+set "expected_upgrade_code=B08613CD-8BD0-4FB6-8937-621936604DE3"
+set "msi_path="
+for %%f in (*.msi) do (
+ if defined msi_path (
+ echo Found more than one MSI in %cd%; cannot determine which one to verify.
+ exit /b 1
+ )
+ set "msi_path=%%~ff"
+)
+if not defined msi_path (
+ echo No MSI found in %cd%.
+ exit /b 1
+)
+
+set "wix_source=%TEMP%\llvm-msi-%RANDOM%.wxs"
+dark.exe -nologo -o "%wix_source%" "%msi_path%"
+if errorlevel 1 (
+ echo Failed to decompile "%msi_path%".
+ exit /b 1
+)
+findstr /i /c:"%expected_upgrade_code%" "%wix_source%" >nul
+if errorlevel 1 (
+ echo "%msi_path%" does not have the expected UpgradeCode %expected_upgrade_code%.
+ del /q "%wix_source%"
+ exit /b 1
+)
+del /q "%wix_source%"
+echo Verified MSI UpgradeCode: %expected_upgrade_code%
+exit /b 0
+
+::=============================================================================
+
::==============================================================================
:: Verify checksum.
::==============================================================================
@@ -482,7 +520,7 @@ exit /b 0
mkdir zstdbuild
cd zstdbuild
cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install ^
- -DZSTD_BUILD_PROGRAMS=ON -DZSTD_BUILD_TESTS=OFF -DZSTD_BUILD_STATIC=ON ^
+ -DZSTD_BUILD_PROGRAMS=ON -DZSTD_BUILD_TESTS=OFF -DZSTD_BUILD_STATIC=ON ^
-DZSTD_BUILD_SHARED=OFF -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded ^
../../zstd-%zstd_version%/build/cmake || exit /b 1
ninja install || exit /b 1
>From f234e52973c025ad120c041bbfc588ace4c69a96 Mon Sep 17 00:00:00 2001
From: Alexandre Ganea <aganea at havenstudios.com>
Date: Tue, 8 Sep 2026 14:57:15 -0400
Subject: [PATCH 7/7] Use Powershell + COM API instead of dark.exe
---
llvm/utils/release/build_llvm_release.bat | 28 +++++++++++++++--------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/llvm/utils/release/build_llvm_release.bat b/llvm/utils/release/build_llvm_release.bat
index 2d77ed8f09b619..e77f2bef432bb8 100644
--- a/llvm/utils/release/build_llvm_release.bat
+++ b/llvm/utils/release/build_llvm_release.bat
@@ -425,6 +425,7 @@ exit /b 0
:: Verify that the generated MSI has LLVM's permanent UpgradeCode.
::==============================================================================
:verify_msi_upgrade_code
+:: This code has to match the value in llvm/CMakeLists.txt
set "expected_upgrade_code=B08613CD-8BD0-4FB6-8937-621936604DE3"
set "msi_path="
for %%f in (*.msi) do (
@@ -439,19 +440,28 @@ if not defined msi_path (
exit /b 1
)
-set "wix_source=%TEMP%\llvm-msi-%RANDOM%.wxs"
-dark.exe -nologo -o "%wix_source%" "%msi_path%"
-if errorlevel 1 (
- echo Failed to decompile "%msi_path%".
+:: Query the MSI's UpgradeCode through the Windows Installer COM API. WiX's
+:: dark.exe would do this too, but it is deprecated and removed in newer WiX.
+set "msi_query=SELECT Value FROM Property WHERE Property='UpgradeCode'"
+set "ps_cmd=$i = New-Object -ComObject WindowsInstaller.Installer;"
+set "ps_cmd=%ps_cmd% $db = $i.OpenDatabase($env:msi_path, 0);"
+set "ps_cmd=%ps_cmd% $v = $db.OpenView($env:msi_query);"
+set "ps_cmd=%ps_cmd% $v.Execute();"
+set "ps_cmd=%ps_cmd% $v.Fetch().StringData(1).Trim('{', '}')"
+
+set "actual_upgrade_code="
+for /f %%i in ('powershell -NoProfile -Command "%ps_cmd%"') do (
+ set "actual_upgrade_code=%%i"
+)
+if not defined actual_upgrade_code (
+ echo Failed to read the UpgradeCode from "%msi_path%".
exit /b 1
)
-findstr /i /c:"%expected_upgrade_code%" "%wix_source%" >nul
-if errorlevel 1 (
- echo "%msi_path%" does not have the expected UpgradeCode %expected_upgrade_code%.
- del /q "%wix_source%"
+if /i not "%actual_upgrade_code%"=="%expected_upgrade_code%" (
+ echo Unexpected UpgradeCode %actual_upgrade_code% in "%msi_path%".
+ echo Expected %expected_upgrade_code%.
exit /b 1
)
-del /q "%wix_source%"
echo Verified MSI UpgradeCode: %expected_upgrade_code%
exit /b 0
More information about the llvm-commits
mailing list