[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