diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake index a27d00004..2495c4476 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" diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake index 0c0a8f19f..fce25f07a 100644 --- a/Modules/CPackWIX.cmake +++ b/Modules/CPackWIX.cmake @@ -76,6 +76,32 @@ # 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 +##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 +##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 e8b0ea971..cc9dec7b8 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()); @@ -224,6 +229,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,25 +347,114 @@ 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); + directoryCounter, fileCounter, cpackPkgExecutables, dirIdExecutables); + + directoryDefinitions.EndElement(); + directoryDefinitions.EndElement(); + + 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(); + ++it) + { + std::string fileName = *it++; + std::string iconName = *it++; + std::string directoryId = *it; + + fileDefinitions.BeginElement("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); + 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(); - - for(size_t i = 1; i < install_root.size(); ++i) - { - directoryDefinitions.EndElement(); - } - - directoryDefinitions.EndElement(); - directoryDefinitions.EndElement(); 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, @@ -435,7 +532,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,8 +566,9 @@ void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( fileDefinitions, featureDefinitions, directoryCounter, - fileCounter); - + fileCounter, + pkgExecutables, + dirIdExecutables); directoryDefinitions.EndElement(); } else @@ -499,6 +599,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 0e95d70f6..aaccf9d46 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 ce02f110d..475e60d09 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)