From 8c0e32550cf8afbb8419dff3698915b550e9c86d Mon Sep 17 00:00:00 2001 From: Fredrik Axelsson Date: Fri, 1 Mar 2013 11:09:58 +0900 Subject: [PATCH 1/6] CPackWIX: Handle CPACK_PACKAGE_EXECUTABLES (#13967) Add start menu items including an uninstall shortcut. Add variable CPACK_WIX_PROGRAM_MENU_FOLDER to configure folder name. --- Modules/CPackWIX.cmake | 6 ++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 126 +++++++++++++++++++++-- Source/CPack/WiX/cmCPackWIXGenerator.h | 6 +- Tests/CPackWiXGenerator/CMakeLists.txt | 2 + 4 files changed, 129 insertions(+), 11 deletions(-) diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 0c0a8f19fa..69a181e649 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -76,6 +76,12 @@ # This image must be 493 by 312 pixels. # ##end +# +##variable +# CPACK_WIX_PROGRAM_MENU_FOLDER - Start menu folder name for launcher. +# +# If this variable is not set, it will be initialized with CPACK_PACKAGE_NAME +##end #============================================================================= # Copyright 2012 Kitware, Inc. diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index e8b0ea9715..fc51b772e1 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -224,6 +224,9 @@ bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON"); CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER"); CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG"); + SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER", + GetOption("CPACK_PACKAGE_NAME")); + CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER"); return true; } @@ -339,22 +342,105 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() featureDefinitions.BeginElement("FeatureRef"); featureDefinitions.AddAttribute("Id", "ProductFeature"); + const char *cpackPackageExecutables = GetOption("CPACK_PACKAGE_EXECUTABLES"); + std::vector cpackPkgExecutables; + std::string regKey; + if ( cpackPackageExecutables ) + { + cmSystemTools::ExpandListArgument(cpackPackageExecutables, + cpackPkgExecutables); + if ( cpackPkgExecutables.size() % 2 != 0 ) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "CPACK_PACKAGE_EXECUTABLES should contain pairs of and " + "." << std::endl); + cpackPkgExecutables.clear(); + } + + const char *cpackVendor = GetOption("CPACK_PACKAGE_VENDOR"); + const char *cpackPkgName = GetOption("CPACK_PACKAGE_NAME"); + if (!cpackVendor || !cpackPkgName) + { + cmCPackLogger(cmCPackLog::LOG_WARNING, "CPACK_PACKAGE_VENDOR and " + "CPACK_PACKAGE_NAME must be defined for shortcut creation" << std::endl); + cpackPkgExecutables.clear(); + } + else + { + regKey = std::string("Software/") + cpackVendor + "/" + cpackPkgName; + } + } + + std::vector dirIdExecutables; AddDirectoryAndFileDefinitons( toplevel, "INSTALL_ROOT", directoryDefinitions, fileDefinitions, featureDefinitions, - directoryCounter, fileCounter); - - featureDefinitions.EndElement(); - featureDefinitions.EndElement(); - fileDefinitions.EndElement(); + directoryCounter, fileCounter, cpackPkgExecutables, dirIdExecutables); for(size_t i = 1; i < install_root.size(); ++i) { directoryDefinitions.EndElement(); } + directoryDefinitions.EndElement(); + directoryDefinitions.EndElement(); - directoryDefinitions.EndElement(); - directoryDefinitions.EndElement(); + if (dirIdExecutables.size() > 0 && dirIdExecutables.size() % 3 == 0) { + std::vector::iterator it; + for ( it = dirIdExecutables.begin() ; + it != dirIdExecutables.end(); + ++it) + { + std::string fileName = *it++; + std::string iconName = *it++; + std::string directoryId = *it; + + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", "SHORTCUT"); + fileDefinitions.AddAttribute("Guid", "*"); + fileDefinitions.BeginElement("Shortcut"); + fileDefinitions.AddAttribute("Id", "SHORTCUT_"); + fileDefinitions.AddAttribute("Name", iconName); + std::string target = "[" + directoryId + "]" + fileName; + fileDefinitions.AddAttribute("Target", target); + fileDefinitions.AddAttribute("WorkingDirectory", directoryId); + fileDefinitions.EndElement(); + } + fileDefinitions.BeginElement("Shortcut"); + fileDefinitions.AddAttribute("Id", "UNINSTALL"); + std::string pkgName = GetOption("CPACK_PACKAGE_NAME"); + fileDefinitions.AddAttribute("Name", "Uninstall " + pkgName); + fileDefinitions.AddAttribute("Description", "Uninstalls " + pkgName); + fileDefinitions.AddAttribute("Target", "[SystemFolder]msiexec.exe"); + fileDefinitions.AddAttribute("Arguments", "/x [ProductCode]"); + fileDefinitions.EndElement(); + fileDefinitions.BeginElement("RemoveFolder"); + fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.AddAttribute("On", "uninstall"); + fileDefinitions.EndElement(); + fileDefinitions.BeginElement("RegistryValue"); + fileDefinitions.AddAttribute("Root", "HKCU"); + fileDefinitions.AddAttribute("Key", regKey); + fileDefinitions.AddAttribute("Name", "installed"); + fileDefinitions.AddAttribute("Type", "integer"); + fileDefinitions.AddAttribute("Value", "1"); + fileDefinitions.AddAttribute("KeyPath", "yes"); + + featureDefinitions.BeginElement("ComponentRef"); + featureDefinitions.AddAttribute("Id", "SHORTCUT"); + featureDefinitions.EndElement(); + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "ProgramMenuFolder"); + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + const char *startMenuFolder = GetOption("CPACK_WIX_PROGRAM_MENU_FOLDER"); + directoryDefinitions.AddAttribute("Name", startMenuFolder); + } + + featureDefinitions.EndElement(); + featureDefinitions.EndElement(); + fileDefinitions.EndElement(); directoryDefinitions.EndElement(); std::string wixTemplate = FindTemplate("WIX.template.in"); @@ -435,7 +521,9 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( cmWIXSourceWriter& fileDefinitions, cmWIXSourceWriter& featureDefinitions, size_t& directoryCounter, - size_t& fileCounter) + size_t& fileCounter, + const std::vector& pkgExecutables, + std::vector& dirIdExecutables) { cmsys::Directory dir; dir.Load(topdir.c_str()); @@ -467,9 +555,10 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( fileDefinitions, featureDefinitions, directoryCounter, - fileCounter); + fileCounter, + pkgExecutables, + dirIdExecutables); - directoryDefinitions.EndElement(); } else { @@ -499,6 +588,23 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( featureDefinitions.BeginElement("ComponentRef"); featureDefinitions.AddAttribute("Id", componentId); featureDefinitions.EndElement(); + + std::vector::const_iterator it; + for (it = pkgExecutables.begin() ; + it != pkgExecutables.end() ; + ++it) + { + std::string execName = *it++; + std::string iconName = *it; + + if (cmSystemTools::LowerCase(fileName) == + cmSystemTools::LowerCase(execName) + ".exe") + { + dirIdExecutables.push_back(fileName); + dirIdExecutables.push_back(iconName); + dirIdExecutables.push_back(directoryId); + } + } } } } diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h index 0e95d70f6c..aaccf9d467 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.h +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -83,7 +83,11 @@ private: cmWIXSourceWriter& fileDefinitions, cmWIXSourceWriter& featureDefinitions, size_t& directoryCounter, - size_t& fileCounter); + size_t& fileCounter, + const std::vector& pkgExecutables, + std::vector& dirIdExecutables + ); + bool RequireOption(const std::string& name, std::string& value) const; diff --git a/Tests/CPackWiXGenerator/CMakeLists.txt b/Tests/CPackWiXGenerator/CMakeLists.txt index ce02f110db..475e60d09d 100644 --- a/Tests/CPackWiXGenerator/CMakeLists.txt +++ b/Tests/CPackWiXGenerator/CMakeLists.txt @@ -35,6 +35,8 @@ set(CPACK_PACKAGE_VERSION_PATCH "0") set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example") set(CPACK_WIX_UPGRADE_GUID "BF20CE5E-7F7C-401D-8F7C-AB45E8D170E6") +set(CPACK_WIX_UNINSTALL "1") +set(CPACK_PACKAGE_EXECUTABLES "mylibapp; CPack Wix Test") include(CPack) From 6d77e1ab3f6cfe5e2019a418da7c18cc3515ab54 Mon Sep 17 00:00:00 2001 From: Ian Monroe Date: Thu, 18 Apr 2013 10:19:13 -0700 Subject: [PATCH 2/6] CPackWIX: Fix MSI package layout regression from parent The parent commit added a regression where if the install directory had: parent child A child B the produced MSI would install: parent child A child B --- Source/CPack/WiX/cmCPackWIXGenerator.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index fc51b772e1..f443905691 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -377,10 +377,6 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() directoryDefinitions, fileDefinitions, featureDefinitions, directoryCounter, fileCounter, cpackPkgExecutables, dirIdExecutables); - for(size_t i = 1; i < install_root.size(); ++i) - { - directoryDefinitions.EndElement(); - } directoryDefinitions.EndElement(); directoryDefinitions.EndElement(); @@ -558,7 +554,7 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( fileCounter, pkgExecutables, dirIdExecutables); - + directoryDefinitions.EndElement(); } else { From 6e51ea9870658ca39e9b3050caada121519da673 Mon Sep 17 00:00:00 2001 From: Richard Ulrich Date: Wed, 8 May 2013 16:39:32 +0200 Subject: [PATCH 3/6] CPackWIX: Handle multiple shortcuts in the start menu --- Source/CPack/WiX/cmCPackWIXGenerator.cxx | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index f443905691..cfb655b228 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -380,7 +380,14 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() directoryDefinitions.EndElement(); directoryDefinitions.EndElement(); - if (dirIdExecutables.size() > 0 && dirIdExecutables.size() % 3 == 0) { + if (dirIdExecutables.size() > 0 && dirIdExecutables.size() % 3 == 0) + { + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", "SHORTCUT"); + fileDefinitions.AddAttribute("Guid", "*"); + std::vector::iterator it; for ( it = dirIdExecutables.begin() ; it != dirIdExecutables.end(); @@ -390,13 +397,12 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() std::string iconName = *it++; std::string directoryId = *it; - fileDefinitions.BeginElement("DirectoryRef"); - fileDefinitions.AddAttribute("Id", "PROGRAM_MENU_FOLDER"); - fileDefinitions.BeginElement("Component"); - fileDefinitions.AddAttribute("Id", "SHORTCUT"); - fileDefinitions.AddAttribute("Guid", "*"); fileDefinitions.BeginElement("Shortcut"); - fileDefinitions.AddAttribute("Id", "SHORTCUT_"); + std::string shortcutName = fileName; // the iconName is mor likely to contain blanks early on + std::string::size_type const dotPos = shortcutName.find('.'); + if(std::string::npos == dotPos) + { shortcutName = shortcutName.substr(0, dotPos); } + fileDefinitions.AddAttribute("Id", "SHORTCUT_" + shortcutName); fileDefinitions.AddAttribute("Name", iconName); std::string target = "[" + directoryId + "]" + fileName; fileDefinitions.AddAttribute("Target", target); From bfa2e299ae9a8687c6f13e701c87e68b9e4a5054 Mon Sep 17 00:00:00 2001 From: Richard Ulrich Date: Mon, 6 May 2013 17:21:42 +0200 Subject: [PATCH 4/6] CPackWIX: Add option to specify the language(s) of the installer Add option "CPACK_WIX_CULTURES". --- Modules/CPackWIX.cmake | 11 +++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 69a181e649..4f57efac03 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -81,6 +81,17 @@ # CPACK_WIX_PROGRAM_MENU_FOLDER - Start menu folder name for launcher. # # If this variable is not set, it will be initialized with CPACK_PACKAGE_NAME +# +##end +##variable +# CPACK_WIX_CULTURES - Language(s) of the installer +# +# Languages are compiled into the WixUI extension library. To use them, +# simply provide the name of the culture. If you specify more than one +# culture identifier in a comma or semicolon delimited list, the first one +# that is found will be used. You can find a list of supported languages at: +# http://wix.sourceforge.net/manual-wix3/WixUI_localization.htm +# ##end #============================================================================= diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index cfb655b228..373a14dd68 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -100,6 +100,11 @@ bool cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) command << " -nologo"; command << " -out " << QuotePath(packageFileNames.at(0)); command << " -ext WixUIExtension"; + const char* const cultures = GetOption("CPACK_WIX_CULTURES"); + if(cultures) + { + command << " -cultures:" << cultures; + } command << " " << objectFiles; return RunWiXCommand(command.str()); From 155bb01bd5126f36066653a209a3209f6363a7cd Mon Sep 17 00:00:00 2001 From: Richard Ulrich Date: Wed, 8 May 2013 17:13:31 +0200 Subject: [PATCH 5/6] CMakeCPack: Provide an upgrade guid for WiX Set CPACK_WIX_UPGRADE_GUID. Without this upgrade GUID, you end up with multiple instances of the same installation when installing cmake from a WIX generated installer. --- CMakeCPack.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake index a27d000043..2495c4476b 100644 --- a/CMakeCPack.cmake +++ b/CMakeCPack.cmake @@ -113,6 +113,8 @@ if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake") include(Utilities/Release/Cygwin/CMakeLists.txt) endif() + set(CPACK_WIX_UPGRADE_GUID "8ffd1d72-b7f1-11e2-8ee5-00238bca4991") + # Set the options file that needs to be included inside CMakeCPackOptions.cmake set(QT_DIALOG_CPACK_OPTIONS_FILE ${CMake_BINARY_DIR}/Source/QtDialog/QtDialogCPack.cmake) configure_file("${CMake_SOURCE_DIR}/CMakeCPackOptions.cmake.in" From bf23891942d95a4075f349f6c4043647d47e546b Mon Sep 17 00:00:00 2001 From: "Adam J. Weigold" Date: Tue, 2 Jul 2013 17:19:31 -0500 Subject: [PATCH 6/6] CPackWIX: Add support for custom WiX templates WiX provides a lot of functionality for installers that cannot be supported (easily) in the default WIX.template.in file. For most users, the default template should be fine. However if users want to produce merge modules, include custom actions, etc, this new option allows for a hook into how the wxs is produced. --- Modules/CPackWIX.cmake | 9 +++++++++ Source/CPack/WiX/cmCPackWIXGenerator.cxx | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 4f57efac03..fce25f07a9 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -93,6 +93,15 @@ # http://wix.sourceforge.net/manual-wix3/WixUI_localization.htm # ##end +##variable +# CPACK_WIX_TEMPLATE - Template file for WiX generation +# +# If this variable is set, the specified template will be used to generate the WiX wxs file. +# This should be used if further customization of the output is required. +# +# If this variable is not set, the default MSI template included with CMake will be used. +# +##end #============================================================================= # Copyright 2012 Kitware, Inc. diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx index 373a14dd68..cc9dec7b86 100644 --- a/Source/CPack/WiX/cmCPackWIXGenerator.cxx +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -451,6 +451,10 @@ bool cmCPackWIXGenerator::CreateWiXSourceFiles() directoryDefinitions.EndElement(); std::string wixTemplate = FindTemplate("WIX.template.in"); + if(GetOption("CPACK_WIX_TEMPLATE") != 0) + { + wixTemplate = GetOption("CPACK_WIX_TEMPLATE"); + } if(wixTemplate.empty()) { cmCPackLogger(cmCPackLog::LOG_ERROR,