From e7f5ad8df2f8dda35fea51b7c01f068497c16940 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 19 Mar 2024 19:07:40 -0400 Subject: Tests: Prepare RunCMake.CPack_WIX to cover multiple WiX versions --- .../CPack_WIX/3-AppWiX-cpack-WIX-check.cmake | 1 + .../CPack_WIX/3-AppWiX-cpack-WIX-stdout.txt | 11 ++++++++ .../RunCMake/CPack_WIX/3-AppWiX-verify-stdout.txt | 33 ++++++++++++++++++++++ .../CPack_WIX/AppWiX-cpack-WIX-check.cmake | 1 - .../RunCMake/CPack_WIX/AppWiX-cpack-WIX-stdout.txt | 11 -------- Tests/RunCMake/CPack_WIX/AppWiX-verify-stdout.txt | 33 ---------------------- Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake | 13 +++++++-- 7 files changed, 56 insertions(+), 47 deletions(-) create mode 100644 Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-check.cmake create mode 100644 Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-stdout.txt create mode 100644 Tests/RunCMake/CPack_WIX/3-AppWiX-verify-stdout.txt delete mode 100644 Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-check.cmake delete mode 100644 Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-stdout.txt delete mode 100644 Tests/RunCMake/CPack_WIX/AppWiX-verify-stdout.txt diff --git a/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-check.cmake b/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-check.cmake new file mode 100644 index 0000000..a7a28ae --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-check.cmake @@ -0,0 +1 @@ +include(${RunCMake_SOURCE_DIR}/cpack-check-common.cmake) diff --git a/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-stdout.txt b/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-stdout.txt new file mode 100644 index 0000000..2998440 --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/3-AppWiX-cpack-WIX-stdout.txt @@ -0,0 +1,11 @@ +CPack: Create package using WIX +CPack: Install projects +CPack: - Install project: CPackWiXGenerator \[Release\] +CPack: - Install component: applications +CPack: - Install component: applications2 +CPack: - Install component: extras +CPack: - Install component: headers +CPack: - Install component: libraries +CPack: Create package +CPack: - package: [^ +]*/Tests/RunCMake/CPack_WIX/3-AppWiX-build/MyLib-1\.0\.0-(win64|windows-arm64)\.msi generated\. diff --git a/Tests/RunCMake/CPack_WIX/3-AppWiX-verify-stdout.txt b/Tests/RunCMake/CPack_WIX/3-AppWiX-verify-stdout.txt new file mode 100644 index 0000000..4713447 --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/3-AppWiX-verify-stdout.txt @@ -0,0 +1,33 @@ +-- MyLib-1\.0\.0-(win64|windows-arm64)\.msi +Component: 'CM_CP_applications.bin.my_libapp.exe' 'CM_DP_applications.bin' +Component: 'CM_SHORTCUT_applications' 'PROGRAM_MENU_FOLDER' +Component: 'CM_SHORTCUT_DESKTOP_applications' 'DesktopFolder' +Component: 'CM_CP_applications2.bin.my_other_app.exe' 'CM_DP_applications2.bin' +Component: 'CM_SHORTCUT_applications2' 'PROGRAM_MENU_FOLDER' +Component: 'CM_SHORTCUT_DESKTOP_applications2' 'DesktopFolder' +Component: 'CM_C_EMPTY_CM_DP_extras.extras.empty' 'CM_DP_extras.extras.empty' +Component: 'CM_CP_headers.include.file_with_spaces.h' 'CM_DP_headers.include' +Component: 'CM_CP_headers.include.mylib.h' 'CM_DP_headers.include' +Component: 'CM_CP_libraries.lib.mylib.lib' 'CM_DP_libraries.lib' +Directory: 'INSTALL_ROOT' 'ProgramFiles64Folder' '[^']*\|CPack Component Example' +Directory: 'CM_DP_applications.bin' 'INSTALL_ROOT' 'bin' +Directory: 'PROGRAM_MENU_FOLDER' 'ProgramMenuFolder' 'MyLib' +Directory: 'DesktopFolder' 'TARGETDIR' 'Desktop' +Directory: 'CM_DP_applications2.bin' 'INSTALL_ROOT' 'bin' +Directory: 'CM_DP_extras.extras.empty' 'CM_DP_extras.extras' 'empty' +Directory: 'CM_DP_headers.include' 'INSTALL_ROOT' 'include' +Directory: 'CM_DP_libraries.lib' 'INSTALL_ROOT' 'lib' +Directory: 'CM_DP_extras.extras' 'INSTALL_ROOT' 'extras' +Directory: 'ProgramFiles64Folder' 'TARGETDIR' '.' +Directory: 'TARGETDIR' '' 'SourceDir' +Directory: 'ProgramMenuFolder' 'TARGETDIR' '.' +File: 'CM_FP_applications.bin.my_libapp.exe' 'CM_CP_applications.bin.my_libapp.exe' '[^']*\|my-libapp.exe' +File: 'CM_FP_applications2.bin.my_other_app.exe' 'CM_CP_applications2.bin.my_other_app.exe' '[^']*\|my-other-app.exe' +File: 'CM_FP_headers.include.file_with_spaces.h' 'CM_CP_headers.include.file_with_spaces.h' '[^']*\|file with spaces.h' +File: 'CM_FP_headers.include.mylib.h' 'CM_CP_headers.include.mylib.h' 'mylib.h' +File: 'CM_FP_libraries.lib.mylib.lib' 'CM_CP_libraries.lib.mylib.lib' 'mylib.lib' +Shortcut: 'CM_SP_applications.bin.my_libapp.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_applications' +Shortcut: 'CM_DSP_applications.bin.my_libapp.exe' 'DesktopFolder' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications' +Shortcut: 'CM_SP_applications2.bin.my_other_app.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_applications2' +Shortcut: 'CM_DSP_applications2.bin.my_other_app.exe' 'DesktopFolder' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications2' +-- diff --git a/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-check.cmake b/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-check.cmake deleted file mode 100644 index a7a28ae..0000000 --- a/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-check.cmake +++ /dev/null @@ -1 +0,0 @@ -include(${RunCMake_SOURCE_DIR}/cpack-check-common.cmake) diff --git a/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-stdout.txt b/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-stdout.txt deleted file mode 100644 index 110b36e..0000000 --- a/Tests/RunCMake/CPack_WIX/AppWiX-cpack-WIX-stdout.txt +++ /dev/null @@ -1,11 +0,0 @@ -CPack: Create package using WIX -CPack: Install projects -CPack: - Install project: CPackWiXGenerator \[Release\] -CPack: - Install component: applications -CPack: - Install component: applications2 -CPack: - Install component: extras -CPack: - Install component: headers -CPack: - Install component: libraries -CPack: Create package -CPack: - package: [^ -]*/Tests/RunCMake/CPack_WIX/AppWiX-build/MyLib-1\.0\.0-(win64|windows-arm64)\.msi generated\. diff --git a/Tests/RunCMake/CPack_WIX/AppWiX-verify-stdout.txt b/Tests/RunCMake/CPack_WIX/AppWiX-verify-stdout.txt deleted file mode 100644 index 4713447..0000000 --- a/Tests/RunCMake/CPack_WIX/AppWiX-verify-stdout.txt +++ /dev/null @@ -1,33 +0,0 @@ --- MyLib-1\.0\.0-(win64|windows-arm64)\.msi -Component: 'CM_CP_applications.bin.my_libapp.exe' 'CM_DP_applications.bin' -Component: 'CM_SHORTCUT_applications' 'PROGRAM_MENU_FOLDER' -Component: 'CM_SHORTCUT_DESKTOP_applications' 'DesktopFolder' -Component: 'CM_CP_applications2.bin.my_other_app.exe' 'CM_DP_applications2.bin' -Component: 'CM_SHORTCUT_applications2' 'PROGRAM_MENU_FOLDER' -Component: 'CM_SHORTCUT_DESKTOP_applications2' 'DesktopFolder' -Component: 'CM_C_EMPTY_CM_DP_extras.extras.empty' 'CM_DP_extras.extras.empty' -Component: 'CM_CP_headers.include.file_with_spaces.h' 'CM_DP_headers.include' -Component: 'CM_CP_headers.include.mylib.h' 'CM_DP_headers.include' -Component: 'CM_CP_libraries.lib.mylib.lib' 'CM_DP_libraries.lib' -Directory: 'INSTALL_ROOT' 'ProgramFiles64Folder' '[^']*\|CPack Component Example' -Directory: 'CM_DP_applications.bin' 'INSTALL_ROOT' 'bin' -Directory: 'PROGRAM_MENU_FOLDER' 'ProgramMenuFolder' 'MyLib' -Directory: 'DesktopFolder' 'TARGETDIR' 'Desktop' -Directory: 'CM_DP_applications2.bin' 'INSTALL_ROOT' 'bin' -Directory: 'CM_DP_extras.extras.empty' 'CM_DP_extras.extras' 'empty' -Directory: 'CM_DP_headers.include' 'INSTALL_ROOT' 'include' -Directory: 'CM_DP_libraries.lib' 'INSTALL_ROOT' 'lib' -Directory: 'CM_DP_extras.extras' 'INSTALL_ROOT' 'extras' -Directory: 'ProgramFiles64Folder' 'TARGETDIR' '.' -Directory: 'TARGETDIR' '' 'SourceDir' -Directory: 'ProgramMenuFolder' 'TARGETDIR' '.' -File: 'CM_FP_applications.bin.my_libapp.exe' 'CM_CP_applications.bin.my_libapp.exe' '[^']*\|my-libapp.exe' -File: 'CM_FP_applications2.bin.my_other_app.exe' 'CM_CP_applications2.bin.my_other_app.exe' '[^']*\|my-other-app.exe' -File: 'CM_FP_headers.include.file_with_spaces.h' 'CM_CP_headers.include.file_with_spaces.h' '[^']*\|file with spaces.h' -File: 'CM_FP_headers.include.mylib.h' 'CM_CP_headers.include.mylib.h' 'mylib.h' -File: 'CM_FP_libraries.lib.mylib.lib' 'CM_CP_libraries.lib.mylib.lib' 'mylib.lib' -Shortcut: 'CM_SP_applications.bin.my_libapp.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_applications' -Shortcut: 'CM_DSP_applications.bin.my_libapp.exe' 'DesktopFolder' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications' -Shortcut: 'CM_SP_applications2.bin.my_other_app.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_applications2' -Shortcut: 'CM_DSP_applications2.bin.my_other_app.exe' 'DesktopFolder' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications2' --- diff --git a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake index cd525d0..cf14d7d 100644 --- a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake @@ -1,7 +1,16 @@ include(RunCPack) +set(env_PATH "$ENV{PATH}") + set(RunCPack_GENERATORS WIX) +set(RunCPack_GLOB *.msi) +set(RunCPack_VERIFY powershell -ExecutionPolicy Bypass -File ${CMAKE_CURRENT_LIST_DIR}/print-msi.ps1) -set(ENV{PATH} "${CMake_TEST_CPACK_WIX3};$ENV{PATH}") +function(run_cpack_wix v) + run_cpack(${v}-AppWiX SAMPLE AppWiX BUILD) +endfunction() -run_cpack(AppWiX BUILD GLOB *.msi VERIFY powershell -ExecutionPolicy Bypass -File ${CMAKE_CURRENT_LIST_DIR}/print-msi.ps1) +if(CMake_TEST_CPACK_WIX3) + set(ENV{PATH} "${CMake_TEST_CPACK_WIX3};${env_PATH}") + run_cpack_wix(3) +endif() -- cgit v0.12 From c8e2694679c2be02bbd3d8dbb98278b2ee977147 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Mar 2024 16:36:18 -0400 Subject: ci: Add script to repackage WiX .NET tool for our needs WiX Toolset 4+ is provided only via nuget packages. Add a script to repackage the parts we need for CMake's own testing and packaging. --- .gitlab/ci/repackage/wix.ps1 | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 .gitlab/ci/repackage/wix.ps1 diff --git a/.gitlab/ci/repackage/wix.ps1 b/.gitlab/ci/repackage/wix.ps1 new file mode 100755 index 0000000..6dbd466 --- /dev/null +++ b/.gitlab/ci/repackage/wix.ps1 @@ -0,0 +1,55 @@ +# WiX Toolset 4+ is provided only via nuget packages. +# Download the package artifacts, extract the parts we need, and repackage them. + +param ( + [Parameter(Mandatory=$true)] + [string]$version + ) + +$erroractionpreference = "stop" + +$version_major = $version.Substring(0, $version.IndexOf('.')) + +$release = "v" + $version +$pkg_wix = "wix.$version.nupkg" +$pkg_wixui = "WixToolset.UI.wixext.$version.nupkg" +$packages = $pkg_wix, $pkg_wixui + +$wix_artifacts = "wix-artifacts.zip" + +$ProgressPreference = 'SilentlyContinue' +Invoke-WebRequest -Uri "https://github.com/wixtoolset/wix/releases/download/$release/artifacts.zip" -OutFile "$wix_artifacts" + +Add-Type -AssemblyName System.IO.Compression.FileSystem + +$zip = [System.IO.Compression.ZipFile]::Open("$wix_artifacts", "read") +$zip.Entries | Where-Object FullName -in $packages | ForEach-Object { + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, "$($_.Name)", $true) +} +$zip.Dispose() +Remove-Item "$wix_artifacts" + +$wix_dir = "wix-$version-win-any-1" +[System.IO.Compression.ZipFile]::ExtractToDirectory($pkg_wix, "wix-tmp") +Move-Item -Path "wix-tmp/tools/net6.0/any" -Destination "$wix_dir" +Remove-Item "wix-tmp" -Recurse -Force +Remove-Item "$pkg_wix" + +$ext_dir = New-Item -Force -ItemType Directory -Path "$wix_dir/.wix/extensions/WixToolset.UI.wixext/$version/wixext$version_major" +$zip = [System.IO.Compression.ZipFile]::Open($pkg_wixui, "read") +$zip.Entries | Where-Object Name -eq "WixToolset.UI.wixext.dll" | ForEach-Object { + [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, (Join-Path $ext_dir $_.Name), $true) +} +$zip.Dispose() +Remove-Item "$pkg_wixui" + +@" +This was extracted from WiX Toolset nuget packages and repackaged. +Point both PATH and WIX_EXTENSIONS environment variables at this directory. + +"@ | Add-Content -NoNewline "$wix_dir/README.txt" + +$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal +$includeBaseDirectory = $true +[System.IO.Compression.ZipFile]::CreateFromDirectory("$wix_dir", "$wix_dir.zip", $compressionLevel, $includeBaseDirectory) +Remove-Item "$wix_dir" -Recurse -Force -- cgit v0.12 From cfe5bbdc54d59833047689ad416466d7fd9073f1 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Mar 2024 16:38:36 -0400 Subject: ci: Add scripts to provide WiX 4 package on Windows Run `.gitlab/ci/repackage/wix.ps1` with `-version 4.0.4` and host the package file ourselves. --- .gitlab/.gitignore | 1 + .gitlab/ci/wix4.ps1 | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100755 .gitlab/ci/wix4.ps1 diff --git a/.gitlab/.gitignore b/.gitlab/.gitignore index fd9cf8b..552c02c 100644 --- a/.gitlab/.gitignore +++ b/.gitlab/.gitignore @@ -22,5 +22,6 @@ /unstable-jom* /watcom /wix3 +/wix4 /clang-tidy-fixes /num_warnings.txt diff --git a/.gitlab/ci/wix4.ps1 b/.gitlab/ci/wix4.ps1 new file mode 100755 index 0000000..6209f2b --- /dev/null +++ b/.gitlab/ci/wix4.ps1 @@ -0,0 +1,20 @@ +$erroractionpreference = "stop" + +$version = "4.0.4" +$sha256sum = "FB6E94C89B12FB65D3AA0CF9E9C630DAFCC7D57F1E66C7D6035CAD37A38CC284" +$filename = "wix-$version-win-any-1" +$tarball = "$filename.zip" + +$outdir = $pwd.Path +$outdir = "$outdir\.gitlab" +$ProgressPreference = 'SilentlyContinue' +Invoke-WebRequest -Uri "https://cmake.org/files/dependencies/$tarball" -OutFile "$outdir\$tarball" +$hash = Get-FileHash "$outdir\$tarball" -Algorithm SHA256 +if ($hash.Hash -ne $sha256sum) { + exit 1 +} + +Add-Type -AssemblyName System.IO.Compression.FileSystem +[System.IO.Compression.ZipFile]::ExtractToDirectory("$outdir\$tarball", "$outdir") +Move-Item -Path "$outdir\$filename" -Destination "$outdir\wix4" +Remove-Item "$outdir\$tarball" -- cgit v0.12 From 03884f4f3230f150af26ae1c503d4a43e612323c Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 19 Mar 2024 19:41:34 -0400 Subject: CPack/WIX: Add support for WiX Toolset v4 Add a `CPACK_WIX_VERSION` option to specify version WiX for which the project is configured. Fixes: #23910 --- .gitlab/ci/configure_windows_wix_common.cmake | 3 + .gitlab/ci/env_windows_arm64_vs2022_ninja.ps1 | 1 + .gitlab/ci/env_windows_vs2022_x64_ninja.ps1 | 1 + Help/cpack_gen/wix.rst | 99 +++++++++++-- Help/release/dev/cpack-wix.rst | 5 + Modules/Internal/CPack/CPackWIX.cmake | 28 ++-- Modules/Internal/CPack/WIX.template.in | 53 +++++++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 157 +++++++++++++++++---- Source/CPack/WiX/cmCPackWIXGenerator.h | 5 + Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx | 45 +++--- Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h | 14 +- Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx | 11 +- Source/CPack/WiX/cmWIXFeaturesSourceWriter.h | 3 +- Source/CPack/WiX/cmWIXFilesSourceWriter.cxx | 5 +- Source/CPack/WiX/cmWIXFilesSourceWriter.h | 3 +- Source/CPack/WiX/cmWIXSourceWriter.cxx | 30 +++- Source/CPack/WiX/cmWIXSourceWriter.h | 8 +- Tests/RunCMake/CMakeLists.txt | 3 +- .../CPack_WIX/4-AppWiX-cpack-WIX-check.cmake | 1 + .../CPack_WIX/4-AppWiX-cpack-WIX-stdout.txt | 11 ++ .../RunCMake/CPack_WIX/4-AppWiX-verify-stdout.txt | 34 +++++ Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake | 8 ++ 22 files changed, 446 insertions(+), 82 deletions(-) create mode 100644 Help/release/dev/cpack-wix.rst create mode 100644 Modules/Internal/CPack/WIX.template.in create mode 100644 Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-check.cmake create mode 100644 Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-stdout.txt create mode 100644 Tests/RunCMake/CPack_WIX/4-AppWiX-verify-stdout.txt diff --git a/.gitlab/ci/configure_windows_wix_common.cmake b/.gitlab/ci/configure_windows_wix_common.cmake index faf2464..4219c41 100644 --- a/.gitlab/ci/configure_windows_wix_common.cmake +++ b/.gitlab/ci/configure_windows_wix_common.cmake @@ -1,2 +1,5 @@ get_filename_component(wix3_dir "${CMAKE_CURRENT_LIST_DIR}/../wix3" ABSOLUTE) set(CMake_TEST_CPACK_WIX3 "${wix3_dir}" CACHE PATH "") + +get_filename_component(wix4_dir "${CMAKE_CURRENT_LIST_DIR}/../wix4" ABSOLUTE) +set(CMake_TEST_CPACK_WIX4 "${wix4_dir}" CACHE PATH "") diff --git a/.gitlab/ci/env_windows_arm64_vs2022_ninja.ps1 b/.gitlab/ci/env_windows_arm64_vs2022_ninja.ps1 index b0085d2..eb7bf6e 100755 --- a/.gitlab/ci/env_windows_arm64_vs2022_ninja.ps1 +++ b/.gitlab/ci/env_windows_arm64_vs2022_ninja.ps1 @@ -1 +1,2 @@ & "$pwsh" -File .gitlab/ci/wix3.ps1 +& "$pwsh" -File .gitlab/ci/wix4.ps1 diff --git a/.gitlab/ci/env_windows_vs2022_x64_ninja.ps1 b/.gitlab/ci/env_windows_vs2022_x64_ninja.ps1 index 9dde3a2..ae4a058 100755 --- a/.gitlab/ci/env_windows_vs2022_x64_ninja.ps1 +++ b/.gitlab/ci/env_windows_vs2022_x64_ninja.ps1 @@ -5,3 +5,4 @@ if ("$env:CMAKE_CI_NIGHTLY" -eq "true") { } & "$pwsh" -File .gitlab/ci/wix3.ps1 +& "$pwsh" -File .gitlab/ci/wix4.ps1 diff --git a/Help/cpack_gen/wix.rst b/Help/cpack_gen/wix.rst index 4b627e7..dfa3434 100644 --- a/Help/cpack_gen/wix.rst +++ b/Help/cpack_gen/wix.rst @@ -9,8 +9,68 @@ Use the `WiX Toolset`_ to produce a Windows Installer ``.msi`` database. The :variable:`CPACK_COMPONENT__DISABLED` variable is now supported. +WiX Toolsets +^^^^^^^^^^^^ + +CPack selects one of the following variants of the WiX Toolset +based on the :variable:`CPACK_WIX_VERSION` variable: + +* `WiX .NET Tools`_ +* `WiX Toolset v3`_ + +WiX .NET Tools +"""""""""""""" + +Packaging is performed using the following tools: + +``wix build`` + Build WiX source files directly into a Windows Installer ``.msi`` database. + + Invocations may be customized using tool-specific variables: + + * :variable:`CPACK_WIX_BUILD_EXTENSIONS _EXTENSIONS>` + * :variable:`CPACK_WIX_BUILD_EXTRA_FLAGS _EXTRA_FLAGS>` + +WiX extensions must be named with the form ``WixToolset..wixext``. + +CPack expects the ``wix`` .NET tool to be available for command-line use +with any required WiX extensions already installed. Be sure the ``wix`` +version is compatible with :variable:`CPACK_WIX_VERSION`, and that WiX +extension versions match the ``wix`` tool version. For example: + +1. Install the ``wix`` command-line tool using ``dotnet``. + + To install ``wix`` globally for the current user: + + .. code-block:: bat + + dotnet tool install --global wix --version 4.0.4 + + This places ``wix.exe`` in ``%USERPROFILE%\.dotnet\tools`` and adds + the directory to the current user's ``PATH`` environment variable. + + Or, to install ``wix`` in a specific path, e.g., in ``c:\WiX``: + + .. code-block:: bat + + dotnet tool install --tool-path c:\WiX wix --version 4.0.4 + + This places ``wix.exe`` in ``c:\WiX``, but does *not* add it to the + current user's ``PATH`` environment variable. The ``WIX`` environment + variable may be set to tell CPack where to find the tool, + e.g., ``set WIX=c:\WiX``. + +2. Add the WiX ``UI`` extension, needed by CPack's default WiX template: + + .. code-block:: bat + + wix extension add --global WixToolset.UI.wixext/4.0.4 + + Extensions added globally are stored in ``%USERPROFILE%\.wix``, or if the + ``WIX_EXTENSIONS`` environment variable is set, in ``%WIX_EXTENSIONS%\.wix``. + WiX Toolset v3 -^^^^^^^^^^^^^^ +"""""""""""""" Packaging is performed using the following tools: @@ -45,6 +105,19 @@ Variables specific to CPack WIX generator The following variables are specific to the installers built on Windows using WiX. +.. variable:: CPACK_WIX_VERSION + + .. versionadded:: 3.30 + + Specify the version of WiX Toolset for which the configuration + is written. The value must be one of + + ``4`` + Package using `WiX .NET Tools`_. + + ``3`` + Package using `WiX Toolset v3`_. This is the default. + .. variable:: CPACK_WIX_UPGRADE_GUID Upgrade GUID (``Product/@UpgradeCode``) @@ -101,8 +174,13 @@ Windows using WiX. .. variable:: CPACK_WIX_UI_REF - Specify the WiX ``UI`` extension's dialog set. - This is the Id of the ```` element in the default WiX template. + Specify the WiX ``UI`` extension's dialog set: + + * With `WiX .NET Tools`_, this is the Id of the + ```` element in the default WiX template. + + * With `WiX Toolset v3`_, this is the Id of the + ```` element in the default WiX template. The default is ``WixUI_InstallDir`` in case no CPack components have been defined and ``WixUI_FeatureTree`` otherwise. @@ -234,7 +312,7 @@ Windows using WiX. .. variable:: CPACK_WIX_EXTRA_OBJECTS - Extra WiX object files or libraries. + Extra WiX object files or libraries to use with `WiX Toolset v3`_. This variable provides an optional list of extra WiX object (``.wixobj``) and/or WiX library (``.wixlib``) files. The paths must be absolute. @@ -242,17 +320,17 @@ Windows using WiX. .. variable:: CPACK_WIX_EXTENSIONS Specify a list of additional extensions for WiX tools. - See `WiX Toolset v3`_ for extension naming patterns. + See `WiX Toolsets`_ for extension naming patterns. .. variable:: CPACK_WIX__EXTENSIONS Specify a list of additional extensions for a specific WiX tool. - See `WiX Toolset v3`_ for possible ```` names. + See `WiX Toolsets`_ for possible ```` names. .. variable:: CPACK_WIX__EXTRA_FLAGS Specify a list of additional command-line flags for a specific WiX tool. - See `WiX Toolset v3`_ for possible ```` names. + See `WiX Toolsets`_ for possible ```` names. Use it at your own risk. Future versions of CPack may generate flags which may be in conflict @@ -356,8 +434,8 @@ Windows using WiX. .. versionadded:: 3.23 If this variable is set to true, the default inclusion of the WiX ``UI`` - extension is skipped, i.e., the ``-ext WixUIExtension`` flag is not - passed to WiX tools. + extension is skipped, i.e., the ``-ext WixUIExtension`` or + ``-ext WixToolset.UI.wixext`` flag is not passed to WiX tools. .. variable:: CPACK_WIX_ARCHITECTURE @@ -386,6 +464,9 @@ Windows using WiX. ``NONE`` Create an installer without any ``InstallScope`` attribute. + This is not supported if :variable:`CPACK_WIX_VERSION` is set + to any value other than ``3``. + .. deprecated:: 3.29 This value is only for compatibility with the inconsistent behavior used diff --git a/Help/release/dev/cpack-wix.rst b/Help/release/dev/cpack-wix.rst new file mode 100644 index 0000000..020dfeb --- /dev/null +++ b/Help/release/dev/cpack-wix.rst @@ -0,0 +1,5 @@ +cpack-wix +--------- + +* The :cpack_gen:`CPack WIX Generator` gained support for WiX Toolset v4. + See the :variable:`CPACK_WIX_VERSION` variable. diff --git a/Modules/Internal/CPack/CPackWIX.cmake b/Modules/Internal/CPack/CPackWIX.cmake index 5fe772e..103d21c 100644 --- a/Modules/Internal/CPack/CPackWIX.cmake +++ b/Modules/Internal/CPack/CPackWIX.cmake @@ -5,18 +5,24 @@ if(NOT CPACK_WIX_ROOT) string(REPLACE "\\" "/" CPACK_WIX_ROOT "$ENV{WIX}") endif() -find_program(CPACK_WIX_CANDLE_EXECUTABLE candle - PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin") +if(CPACK_WIX_VERSION VERSION_GREATER_EQUAL 4) + find_program(CPACK_WIX_EXECUTABLE NAMES wix + PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin") + if(NOT CPACK_WIX_EXECUTABLE) + message(FATAL_ERROR "Could not find the 'wix' executable.") + endif() +else() + find_program(CPACK_WIX_CANDLE_EXECUTABLE candle + PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin") + if(NOT CPACK_WIX_CANDLE_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX candle executable.") + endif() -if(NOT CPACK_WIX_CANDLE_EXECUTABLE) - message(FATAL_ERROR "Could not find the WiX candle executable.") -endif() - -find_program(CPACK_WIX_LIGHT_EXECUTABLE light - PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin") - -if(NOT CPACK_WIX_LIGHT_EXECUTABLE) - message(FATAL_ERROR "Could not find the WiX light executable.") + find_program(CPACK_WIX_LIGHT_EXECUTABLE light + PATHS "${CPACK_WIX_ROOT}" PATH_SUFFIXES "bin") + if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX light executable.") + endif() endif() if(NOT DEFINED CPACK_WIX_INSTALL_SCOPE) diff --git a/Modules/Internal/CPack/WIX.template.in b/Modules/Internal/CPack/WIX.template.in new file mode 100644 index 0000000..7cad186 --- /dev/null +++ b/Modules/Internal/CPack/WIX.template.in @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index b1bb0ca..8532b3e 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -166,6 +166,16 @@ int cmCPackWIXGenerator::PackageFiles() bool cmCPackWIXGenerator::InitializeWiXConfiguration() { + if (cmValue wixVersion = GetOption("CPACK_WIX_VERSION")) { + if (!cmStrToULong(*wixVersion, &this->WixVersion) || + this->WixVersion < 3 || this->WixVersion > 4) { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_WIX_VERSION has unknown value '" + << *wixVersion << "'" << std::endl); + return false; + } + } + if (!ReadListFile("Internal/CPack/CPackWIX.cmake")) { cmCPackLogger(cmCPackLog::LOG_ERROR, "Error while executing CPackWIX.cmake" << std::endl); @@ -232,14 +242,22 @@ bool cmCPackWIXGenerator::InitializeWiXConfiguration() SetOption("CPACK_WIX_PROPERTY_ARPCONTACT", packageContact); } - CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions); - CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions); + if (this->WixVersion >= 4) { + CollectExtensions("CPACK_WIX_EXTENSIONS", this->WixExtensions); + if (!GetOption("CPACK_WIX_SKIP_WIX_UI_EXTENSION").IsOn()) { + this->WixExtensions.insert("WixToolset.UI.wixext"); + } + } else { + CollectExtensions("CPACK_WIX_EXTENSIONS", this->CandleExtensions); + CollectExtensions("CPACK_WIX_CANDLE_EXTENSIONS", this->CandleExtensions); - if (!GetOption("CPACK_WIX_SKIP_WIX_UI_EXTENSION").IsOn()) { - this->LightExtensions.insert("WixUIExtension"); + if (!GetOption("CPACK_WIX_SKIP_WIX_UI_EXTENSION").IsOn()) { + this->LightExtensions.insert("WixUIExtension"); + } + CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions); + CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions); } - CollectExtensions("CPACK_WIX_EXTENSIONS", this->LightExtensions); - CollectExtensions("CPACK_WIX_LIGHT_EXTENSIONS", this->LightExtensions); + CollectXmlNamespaces("CPACK_WIX_CUSTOM_XMLNS", this->CustomXmlNamespaces); cmValue patchFilePath = GetOption("CPACK_WIX_PATCH_FILE"); @@ -278,6 +296,53 @@ bool cmCPackWIXGenerator::PackageFilesImpl() AppendUserSuppliedExtraSources(); + return this->WixVersion >= 4 ? this->PackageWithWix() + : this->PackageWithWix3(); +} + +bool cmCPackWIXGenerator::PackageWithWix() +{ + std::string wixExecutable; + if (!RequireOption("CPACK_WIX_EXECUTABLE", wixExecutable)) { + return false; + } + + std::string arch; + if (cmValue archOpt = GetOption("CPACK_WIX_ARCHITECTURE")) { + arch = *archOpt; + } else { + arch = GetArchitecture(); + cmCPackLogger( + cmCPackLog::LOG_VERBOSE, + "CPACK_WIX_ARCHITECTURE was not set. Invoking WiX with architecture " + << arch << ". " << std::endl); + } + + std::ostringstream command; + command << QuotePath(wixExecutable) << " build" + << " -arch " << arch << " -out " + << QuotePath(CMakeToWixPath(packageFileNames.at(0))); + + for (std::string const& ext : this->WixExtensions) { + command << " -ext " << QuotePath(ext); + } + + cmList cultures{ GetOption("CPACK_WIX_CULTURES") }; + for (std::string const& culture : cultures) { + command << " -culture \"" << culture << "\""; + } + + AddCustomFlags("CPACK_WIX_BUILD_EXTRA_FLAGS", command); + + for (std::string const& sourceFilename : this->WixSources) { + command << " -src " << QuotePath(CMakeToWixPath(sourceFilename)); + } + + return RunWiXCommand(command.str()); +} + +bool cmCPackWIXGenerator::PackageWithWix3() +{ std::set usedBaseNames; std::ostringstream objectFiles; @@ -341,8 +406,8 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() std::string includeFilename = cmStrCat(this->CPackTopLevel, "/cpack_variables.wxi"); - cmWIXSourceWriter includeFile(this->Logger, includeFilename, - this->ComponentGuidType, + cmWIXSourceWriter includeFile(this->WixVersion, this->Logger, + includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); InjectXmlNamespaces(includeFile); @@ -367,8 +432,8 @@ void cmCPackWIXGenerator::CreateWiXPropertiesIncludeFile() std::string includeFilename = cmStrCat(this->CPackTopLevel, "/properties.wxi"); - cmWIXSourceWriter includeFile(this->Logger, includeFilename, - this->ComponentGuidType, + cmWIXSourceWriter includeFile(this->WixVersion, this->Logger, + includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); InjectXmlNamespaces(includeFile); @@ -417,8 +482,8 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile() std::string includeFilename = cmStrCat(this->CPackTopLevel, "/product_fragment.wxi"); - cmWIXSourceWriter includeFile(this->Logger, includeFilename, - this->ComponentGuidType, + cmWIXSourceWriter includeFile(this->WixVersion, this->Logger, + includeFilename, this->ComponentGuidType, cmWIXSourceWriter::INCLUDE_ELEMENT_ROOT); InjectXmlNamespaces(includeFile); @@ -459,7 +524,8 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() this->WixSources.push_back(directoryDefinitionsFilename); cmWIXDirectoriesSourceWriter directoryDefinitions( - this->Logger, directoryDefinitionsFilename, this->ComponentGuidType); + this->WixVersion, this->Logger, directoryDefinitionsFilename, + this->ComponentGuidType); InjectXmlNamespaces(directoryDefinitions); directoryDefinitions.BeginElement("Fragment"); @@ -468,11 +534,13 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() return false; } - directoryDefinitions.BeginElement("Directory"); - directoryDefinitions.AddAttribute("Id", "TARGETDIR"); - directoryDefinitions.AddAttribute("Name", "SourceDir"); + if (this->WixVersion == 3) { + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "TARGETDIR"); + directoryDefinitions.AddAttribute("Name", "SourceDir"); + } - size_t installRootSize = + auto installationPrefixDirectory = directoryDefinitions.BeginInstallationPrefixDirectory(GetRootFolderId(), installRoot); @@ -481,7 +549,8 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() this->WixSources.push_back(fileDefinitionsFilename); - cmWIXFilesSourceWriter fileDefinitions(this->Logger, fileDefinitionsFilename, + cmWIXFilesSourceWriter fileDefinitions(this->WixVersion, this->Logger, + fileDefinitionsFilename, this->ComponentGuidType); InjectXmlNamespaces(fileDefinitions); @@ -492,8 +561,9 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() this->WixSources.push_back(featureDefinitionsFilename); - cmWIXFeaturesSourceWriter featureDefinitions( - this->Logger, featureDefinitionsFilename, this->ComponentGuidType); + cmWIXFeaturesSourceWriter featureDefinitions(this->WixVersion, this->Logger, + featureDefinitionsFilename, + this->ComponentGuidType); InjectXmlNamespaces(featureDefinitions); featureDefinitions.BeginElement("Fragment"); @@ -501,7 +571,11 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() featureDefinitions.BeginElement("Feature"); featureDefinitions.AddAttribute("Id", "ProductFeature"); featureDefinitions.AddAttribute("Display", "expand"); - featureDefinitions.AddAttribute("Absent", "disallow"); + if (this->WixVersion >= 4) { + featureDefinitions.AddAttribute("AllowAbsent", "no"); + } else { + featureDefinitions.AddAttribute("Absent", "disallow"); + } featureDefinitions.AddAttribute("ConfigurableDirectory", "INSTALL_ROOT"); std::string cpackPackageName; @@ -583,7 +657,8 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() featureDefinitions.EndElement("Fragment"); fileDefinitions.EndElement("Fragment"); - directoryDefinitions.EndInstallationPrefixDirectory(installRootSize); + directoryDefinitions.EndInstallationPrefixDirectory( + installationPrefixDirectory); if (emittedShortcutTypes.find(cmWIXShortcuts::START_MENU) != emittedShortcutTypes.end()) { @@ -601,7 +676,9 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() directoryDefinitions.EmitStartupFolder(); } - directoryDefinitions.EndElement("Directory"); + if (this->WixVersion == 3) { + directoryDefinitions.EndElement("Directory"); + } directoryDefinitions.EndElement("Fragment"); if (!GenerateMainSourceFileFromTemplate()) { @@ -613,15 +690,19 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() std::string cmCPackWIXGenerator::GetRootFolderId() const { + std::string result; + if (GetOption("CPACK_WIX_SKIP_PROGRAM_FOLDER").IsOn()) { - return ""; + return result; } - std::string result = "ProgramFiles<64>Folder"; - cmValue rootFolderId = GetOption("CPACK_WIX_ROOT_FOLDER_ID"); if (rootFolderId) { result = *rootFolderId; + } else if (this->WixVersion >= 4) { + result = "ProgramFiles6432Folder"; + } else { + result = "ProgramFiles<64>Folder"; } if (GetArchitecture() == "x86"_s) { @@ -640,7 +721,9 @@ bool cmCPackWIXGenerator::GenerateMainSourceFileFromTemplate() wixTemplate = *wixtpl; } else { cm::optional alt; - alt = "WIX-v3/"_s; + if (this->WixVersion == 3) { + alt = "WIX-v3/"_s; + } wixTemplate = FindTemplate("WIX.template.in"_s, alt); } @@ -768,21 +851,31 @@ bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType( cmWIXFeaturesSourceWriter& featureDefinitions) { std::string directoryId; + std::string directoryRef = "DirectoryRef"; switch (type) { case cmWIXShortcuts::START_MENU: { cmValue cpackWixProgramMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"); if (cpackWixProgramMenuFolder && cpackWixProgramMenuFolder == "."_s) { directoryId = "ProgramMenuFolder"; + if (this->WixVersion >= 4) { + directoryRef = "StandardDirectory"; + } } else { directoryId = "PROGRAM_MENU_FOLDER"; } } break; case cmWIXShortcuts::DESKTOP: directoryId = "DesktopFolder"; + if (this->WixVersion >= 4) { + directoryRef = "StandardDirectory"; + } break; case cmWIXShortcuts::STARTUP: directoryId = "StartupFolder"; + if (this->WixVersion >= 4) { + directoryRef = "StandardDirectory"; + } break; default: return false; @@ -814,7 +907,7 @@ bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType( componentId += idSuffix; - fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.BeginElement(directoryRef); fileDefinitions.AddAttribute("Id", directoryId); fileDefinitions.BeginElement("Component"); @@ -844,7 +937,7 @@ bool cmCPackWIXGenerator::CreateShortcutsOfSpecificType( } fileDefinitions.EndElement("Component"); - fileDefinitions.EndElement("DirectoryRef"); + fileDefinitions.EndElement(directoryRef); featureDefinitions.EmitComponentRef(componentId); featureDefinitions.EndElement("FeatureRef"); @@ -1199,6 +1292,12 @@ void cmCPackWIXGenerator::CollectXmlNamespaces(std::string const& variableName, } } std::string xmlns; + if (this->WixVersion >= 4 && + cm::contains(this->WixExtensions, "WixToolset.UI.wixext") && + !cm::contains(namespaces, "ui")) { + xmlns = cmStrCat( + xmlns, "\n xmlns:ui=\"http://wixtoolset.org/schemas/v4/wxs/ui\""); + } for (auto& ns : namespaces) { xmlns = cmStrCat(xmlns, "\n xmlns:", ns.first, "=\"", cmWIXSourceWriter::EscapeAttributeValue(ns.second), '"'); diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 8609cf3..63530d4 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -59,6 +59,8 @@ private: bool InitializeWiXConfiguration(); bool PackageFilesImpl(); + bool PackageWithWix(); + bool PackageWithWix3(); void CreateWiXVariablesIncludeFile(); @@ -160,6 +162,7 @@ private: id_map_t PathToIdMap; ambiguity_map_t IdAmbiguityCounter; + extension_set_t WixExtensions; extension_set_t CandleExtensions; extension_set_t LightExtensions; xmlns_map_t CustomXmlNamespaces; @@ -168,5 +171,7 @@ private: std::unique_ptr Patch; + unsigned long WixVersion = 3; + cmWIXSourceWriter::GuidType ComponentGuidType; }; diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx index a655d86..b1e7bd2 100644 --- a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.cxx @@ -5,15 +5,16 @@ #include cmWIXDirectoriesSourceWriter::cmWIXDirectoriesSourceWriter( - cmCPackLog* logger, std::string const& filename, GuidType componentGuidType) - : cmWIXSourceWriter(logger, filename, componentGuidType) + unsigned long wixVersion, cmCPackLog* logger, std::string const& filename, + GuidType componentGuidType) + : cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType) { } void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder( std::string const& startMenuFolder) { - BeginElement("Directory"); + BeginElement_StandardDirectory(); AddAttribute("Id", "ProgramMenuFolder"); if (startMenuFolder != "."_s) { @@ -23,34 +24,39 @@ void cmWIXDirectoriesSourceWriter::EmitStartMenuFolder( EndElement("Directory"); } - EndElement("Directory"); + EndElement_StandardDirectory(); } void cmWIXDirectoriesSourceWriter::EmitDesktopFolder() { - BeginElement("Directory"); + BeginElement_StandardDirectory(); AddAttribute("Id", "DesktopFolder"); - AddAttribute("Name", "Desktop"); - EndElement("Directory"); + if (this->WixVersion == 3) { + AddAttribute("Name", "Desktop"); + } + EndElement_StandardDirectory(); } void cmWIXDirectoriesSourceWriter::EmitStartupFolder() { - BeginElement("Directory"); + BeginElement_StandardDirectory(); AddAttribute("Id", "StartupFolder"); - AddAttribute("Name", "Startup"); - EndElement("Directory"); + if (this->WixVersion == 3) { + AddAttribute("Name", "Startup"); + } + EndElement_StandardDirectory(); } -size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( +cmWIXDirectoriesSourceWriter::InstallationPrefixDirectory +cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( std::string const& programFilesFolderId, std::string const& installRootString) { - size_t offset = 1; + InstallationPrefixDirectory installationPrefixDirectory; if (!programFilesFolderId.empty()) { - BeginElement("Directory"); + installationPrefixDirectory.HasStandardDirectory = true; + this->BeginElement_StandardDirectory(); AddAttribute("Id", programFilesFolderId); - offset = 0; } std::vector installRoot; @@ -62,6 +68,7 @@ size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( } for (size_t i = 1; i < installRoot.size(); ++i) { + ++installationPrefixDirectory.Depth; BeginElement("Directory"); if (i == installRoot.size() - 1) { @@ -75,12 +82,16 @@ size_t cmWIXDirectoriesSourceWriter::BeginInstallationPrefixDirectory( AddAttribute("Name", installRoot[i]); } - return installRoot.size() - offset; + return installationPrefixDirectory; } -void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory(size_t size) +void cmWIXDirectoriesSourceWriter::EndInstallationPrefixDirectory( + InstallationPrefixDirectory installationPrefixDirectory) { - for (size_t i = 0; i < size; ++i) { + for (size_t i = 0; i < installationPrefixDirectory.Depth; ++i) { EndElement("Directory"); } + if (installationPrefixDirectory.HasStandardDirectory) { + this->EndElement_StandardDirectory(); + } } diff --git a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h index 0af3094..b0aa1e2 100644 --- a/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h +++ b/Source/CPack/WiX/cmWIXDirectoriesSourceWriter.h @@ -13,7 +13,8 @@ class cmWIXDirectoriesSourceWriter : public cmWIXSourceWriter { public: - cmWIXDirectoriesSourceWriter(cmCPackLog* logger, std::string const& filename, + cmWIXDirectoriesSourceWriter(unsigned long wixVersion, cmCPackLog* logger, + std::string const& filename, GuidType componentGuidType); void EmitStartMenuFolder(std::string const& startMenuFolder); @@ -22,9 +23,16 @@ public: void EmitStartupFolder(); - size_t BeginInstallationPrefixDirectory( + struct InstallationPrefixDirectory + { + bool HasStandardDirectory = false; + size_t Depth = 0; + }; + + InstallationPrefixDirectory BeginInstallationPrefixDirectory( std::string const& programFilesFolderId, std::string const& installRootString); - void EndInstallationPrefixDirectory(size_t size); + void EndInstallationPrefixDirectory( + InstallationPrefixDirectory installationPrefixDirectory); }; diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx index 78c2208..0d2e6e8 100644 --- a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.cxx @@ -5,8 +5,9 @@ #include "cmStringAlgorithms.h" cmWIXFeaturesSourceWriter::cmWIXFeaturesSourceWriter( - cmCPackLog* logger, std::string const& filename, GuidType componentGuidType) - : cmWIXSourceWriter(logger, filename, componentGuidType) + unsigned long wixVersion, cmCPackLog* logger, std::string const& filename, + GuidType componentGuidType) + : cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType) { } @@ -69,7 +70,11 @@ void cmWIXFeaturesSourceWriter::EmitFeatureForComponent( AddAttributeUnlessEmpty("Description", component.Description); if (component.IsRequired) { - AddAttribute("Absent", "disallow"); + if (this->WixVersion >= 4) { + AddAttribute("AllowAbsent", "no"); + } else { + AddAttribute("Absent", "disallow"); + } } if (component.IsHidden) { diff --git a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h index 0facf97..95de8fe 100644 --- a/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h +++ b/Source/CPack/WiX/cmWIXFeaturesSourceWriter.h @@ -12,7 +12,8 @@ class cmWIXFeaturesSourceWriter : public cmWIXSourceWriter { public: - cmWIXFeaturesSourceWriter(cmCPackLog* logger, std::string const& filename, + cmWIXFeaturesSourceWriter(unsigned long wixVersion, cmCPackLog* logger, + std::string const& filename, GuidType componentGuidType); void CreateCMakePackageRegistryEntry(std::string const& package, diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx index b4085d5..87ac6ac 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.cxx @@ -15,10 +15,11 @@ #include "cmUuid.h" #include "cmWIXAccessControlList.h" -cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger, +cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(unsigned long wixVersion, + cmCPackLog* logger, std::string const& filename, GuidType componentGuidType) - : cmWIXSourceWriter(logger, filename, componentGuidType) + : cmWIXSourceWriter(wixVersion, logger, filename, componentGuidType) { } diff --git a/Source/CPack/WiX/cmWIXFilesSourceWriter.h b/Source/CPack/WiX/cmWIXFilesSourceWriter.h index 60dddd4..f560304 100644 --- a/Source/CPack/WiX/cmWIXFilesSourceWriter.h +++ b/Source/CPack/WiX/cmWIXFilesSourceWriter.h @@ -13,7 +13,8 @@ class cmWIXFilesSourceWriter : public cmWIXSourceWriter { public: - cmWIXFilesSourceWriter(cmCPackLog* logger, std::string const& filename, + cmWIXFilesSourceWriter(unsigned long wixVersion, cmCPackLog* logger, + std::string const& filename, GuidType componentGuidType); void EmitShortcut(std::string const& id, cmWIXShortcut const& shortcut, diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx index ef6712a..33e8a70 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.cxx +++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx @@ -8,11 +8,13 @@ #include "cmCryptoHash.h" #include "cmUuid.h" -cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger, +cmWIXSourceWriter::cmWIXSourceWriter(unsigned long wixVersion, + cmCPackLog* logger, std::string const& filename, GuidType componentGuidType, RootElementType rootElementType) - : Logger(logger) + : WixVersion(wixVersion) + , Logger(logger) , File(filename.c_str()) , State(DEFAULT) , SourceFilename(filename) @@ -26,7 +28,11 @@ cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger, BeginElement("Wix"); } - AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi"); + if (this->WixVersion >= 4) { + AddAttribute("xmlns", "http://wixtoolset.org/schemas/v4/wxs"); + } else { + AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi"); + } } cmWIXSourceWriter::~cmWIXSourceWriter() @@ -42,6 +48,24 @@ cmWIXSourceWriter::~cmWIXSourceWriter() EndElement(Elements.back()); } +void cmWIXSourceWriter::BeginElement_StandardDirectory() +{ + if (this->WixVersion >= 4) { + BeginElement("StandardDirectory"); + } else { + BeginElement("Directory"); + } +} + +void cmWIXSourceWriter::EndElement_StandardDirectory() +{ + if (this->WixVersion >= 4) { + EndElement("StandardDirectory"); + } else { + EndElement("Directory"); + } +} + void cmWIXSourceWriter::BeginElement(std::string const& name) { if (State == BEGIN) { diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h index f643acd..1089cf5 100644 --- a/Source/CPack/WiX/cmWIXSourceWriter.h +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -27,12 +27,15 @@ public: INCLUDE_ELEMENT_ROOT }; - cmWIXSourceWriter(cmCPackLog* logger, std::string const& filename, - GuidType componentGuidType, + cmWIXSourceWriter(unsigned long wixVersion, cmCPackLog* logger, + std::string const& filename, GuidType componentGuidType, RootElementType rootElementType = WIX_ELEMENT_ROOT); ~cmWIXSourceWriter(); + void BeginElement_StandardDirectory(); + void EndElement_StandardDirectory(); + void BeginElement(std::string const& name); void EndElement(std::string const& name); @@ -52,6 +55,7 @@ public: static std::string EscapeAttributeValue(std::string const& value); protected: + unsigned long WixVersion; cmCPackLog* Logger; private: diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index ec05b90..575a321 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -1100,9 +1100,10 @@ endif() add_RunCMake_test_group(CPack "${cpack_tests}") -if(CMake_TEST_CPACK_WIX3) +if(CMake_TEST_CPACK_WIX3 OR CMake_TEST_CPACK_WIX4) add_RunCMake_test(CPack_WIX -DCMake_TEST_CPACK_WIX3=${CMake_TEST_CPACK_WIX3} + -DCMake_TEST_CPACK_WIX4=${CMake_TEST_CPACK_WIX4} ) endif() diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-check.cmake b/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-check.cmake new file mode 100644 index 0000000..a7a28ae --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-check.cmake @@ -0,0 +1 @@ +include(${RunCMake_SOURCE_DIR}/cpack-check-common.cmake) diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-stdout.txt b/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-stdout.txt new file mode 100644 index 0000000..51f06ca --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-cpack-WIX-stdout.txt @@ -0,0 +1,11 @@ +CPack: Create package using WIX +CPack: Install projects +CPack: - Install project: CPackWiXGenerator \[Release\] +CPack: - Install component: applications +CPack: - Install component: applications2 +CPack: - Install component: extras +CPack: - Install component: headers +CPack: - Install component: libraries +CPack: Create package +CPack: - package: [^ +]*/Tests/RunCMake/CPack_WIX/4-AppWiX-build/MyLib-1\.0\.0-(win64|windows-arm64)\.msi generated\. diff --git a/Tests/RunCMake/CPack_WIX/4-AppWiX-verify-stdout.txt b/Tests/RunCMake/CPack_WIX/4-AppWiX-verify-stdout.txt new file mode 100644 index 0000000..a379859 --- /dev/null +++ b/Tests/RunCMake/CPack_WIX/4-AppWiX-verify-stdout.txt @@ -0,0 +1,34 @@ +-- MyLib-1\.0\.0-(win64|windows-arm64)\.msi +Component: 'CM_CP_applications.bin.my_libapp.exe' 'CM_DP_applications.bin' +Component: 'CM_SHORTCUT_applications' 'PROGRAM_MENU_FOLDER' +Component: 'CM_SHORTCUT_DESKTOP_applications' 'DesktopFolder' +Component: 'CM_CP_applications2.bin.my_other_app.exe' 'CM_DP_applications2.bin' +Component: 'CM_SHORTCUT_applications2' 'PROGRAM_MENU_FOLDER' +Component: 'CM_SHORTCUT_DESKTOP_applications2' 'DesktopFolder' +Component: 'CM_C_EMPTY_CM_DP_extras.extras.empty' 'CM_DP_extras.extras.empty' +Component: 'CM_CP_headers.include.file_with_spaces.h' 'CM_DP_headers.include' +Component: 'CM_CP_headers.include.mylib.h' 'CM_DP_headers.include' +Component: 'CM_CP_libraries.lib.mylib.lib' 'CM_DP_libraries.lib' +Directory: 'INSTALL_ROOT' 'ProgramFiles6432Folder' '[^']*\|CPack Component Example' +Directory: 'CM_DP_applications.bin' 'INSTALL_ROOT' 'bin' +Directory: 'CM_DP_applications2.bin' 'INSTALL_ROOT' 'bin' +Directory: 'CM_DP_extras.extras.empty' 'CM_DP_extras.extras' 'empty' +Directory: 'CM_DP_extras.extras' 'INSTALL_ROOT' 'extras' +Directory: 'CM_DP_headers.include' 'INSTALL_ROOT' 'include' +Directory: 'CM_DP_libraries.lib' 'INSTALL_ROOT' 'lib' +Directory: 'ProgramFiles6432Folder' 'ProgramFiles64Folder' '.' +Directory: 'PROGRAM_MENU_FOLDER' 'ProgramMenuFolder' 'MyLib' +Directory: 'ProgramMenuFolder' 'TARGETDIR' 'PMenu' +Directory: 'ProgramFiles64Folder' 'TARGETDIR' 'PFiles64' +Directory: 'TARGETDIR' '' 'SourceDir' +Directory: 'DesktopFolder' 'TARGETDIR' 'Desktop' +File: 'CM_FP_applications.bin.my_libapp.exe' 'CM_CP_applications.bin.my_libapp.exe' '[^']*\|my-libapp.exe' +File: 'CM_FP_applications2.bin.my_other_app.exe' 'CM_CP_applications2.bin.my_other_app.exe' '[^']*\|my-other-app.exe' +File: 'CM_FP_headers.include.file_with_spaces.h' 'CM_CP_headers.include.file_with_spaces.h' '[^']*\|file with spaces.h' +File: 'CM_FP_headers.include.mylib.h' 'CM_CP_headers.include.mylib.h' 'mylib.h' +File: 'CM_FP_libraries.lib.mylib.lib' 'CM_CP_libraries.lib.mylib.lib' 'mylib.lib' +Shortcut: 'CM_SP_applications.bin.my_libapp.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_applications' +Shortcut: 'CM_DSP_applications.bin.my_libapp.exe' 'DesktopFolder' '[^']*\|CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications' +Shortcut: 'CM_SP_applications2.bin.my_other_app.exe' 'PROGRAM_MENU_FOLDER' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_applications2' +Shortcut: 'CM_DSP_applications2.bin.my_other_app.exe' 'DesktopFolder' '[^']*\|Second CPack WiX Test' 'CM_SHORTCUT_DESKTOP_applications2' +-- diff --git a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake index cf14d7d..816d949 100644 --- a/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack_WIX/RunCMakeTest.cmake @@ -7,6 +7,7 @@ set(RunCPack_GLOB *.msi) set(RunCPack_VERIFY powershell -ExecutionPolicy Bypass -File ${CMAKE_CURRENT_LIST_DIR}/print-msi.ps1) function(run_cpack_wix v) + set(RunCMake_TEST_OPTIONS -DCPACK_WIX_VERSION=${v}) run_cpack(${v}-AppWiX SAMPLE AppWiX BUILD) endfunction() @@ -14,3 +15,10 @@ if(CMake_TEST_CPACK_WIX3) set(ENV{PATH} "${CMake_TEST_CPACK_WIX3};${env_PATH}") run_cpack_wix(3) endif() + +if(CMake_TEST_CPACK_WIX4) + set(ENV{PATH} "${CMake_TEST_CPACK_WIX4};${env_PATH}") + set(ENV{WIX_EXTENSIONS} "${CMake_TEST_CPACK_WIX4}") + run_cpack_wix(4) + unset(ENV{WIX_EXTENSIONS}) +endif() -- cgit v0.12