View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0011575 | CMake | CPack | public | 2010-12-07 08:55 | 2013-05-06 09:32 | ||||
Reporter | Timothy St. Clair | ||||||||
Assigned To | David Cole | ||||||||
Priority | high | Severity | feature | Reproducibility | always | ||||
Status | closed | Resolution | fixed | ||||||
Platform | Windows | OS | Windows | OS Version | * | ||||
Product Version | CMake 2.8.3 | ||||||||
Target Version | CMake 2.8.11 | Fixed in Version | CMake 2.8.11 | ||||||
Summary | 0011575: Addition of WiX to CPack | ||||||||
Description | The attached patch are the modifications needed to add WiX to cpack. Please let me know what you require in order to get upstream. e.g. what docs are needed, etc. | ||||||||
Steps To Reproduce | http://annealingtechnologies.blogspot.com/2010/02/wix-and-cpack-integration.html [^] | ||||||||
Tags | No tags attached. | ||||||||
Attached Files | cmake-2.8.3-wix.patch [^] (10,010 bytes) 2010-12-07 08:55 [Show Content] [Hide Content]diff --git a/cmake-2.8.3/Modules/CPack.cmake b/cmake-2.8.3/Modules/CPack.cmake index f677ea3..7033e31 100644 --- a/cmake-2.8.3/Modules/CPack.cmake +++ b/cmake-2.8.3/Modules/CPack.cmake @@ -837,7 +837,6 @@ if(NOT CPACK_GENERATOR) else(UNIX) option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) - option(CPACK_BINARY_WIX "Enable to build WIX packages" OFF) endif(UNIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_BUNDLE Bundle) @@ -853,7 +852,6 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) - cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) endif(NOT CPACK_GENERATOR) @@ -885,7 +883,7 @@ mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ - CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP CPACK_BINARY_WIX) + CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) # Set some other variables cpack_set_if_not_set(CPACK_INSTALL_CMAKE_PROJECTS diff --git a/cmake-2.8.3/Modules/CPackWIX.cmake b/cmake-2.8.3/Modules/CPackWIX.cmake deleted file mode 100755 index 0dd9c4e..0000000 --- a/cmake-2.8.3/Modules/CPackWIX.cmake +++ /dev/null @@ -1,49 +0,0 @@ - -#============================================================================= -# Copyright 2007-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distributed this file outside of CMake, substitute the full -# License text for the above reference.) - -IF(CMAKE_BINARY_DIR) - MESSAGE(FATAL_ERROR "CPackWIX.cmake may only be used by CPack internally.") -ENDIF(CMAKE_BINARY_DIR) - -IF(NOT CPACK_WIX_XSL OR NOT CPACK_PACKAGE_FILE_NAME OR NOT CPACK_RESOURCE_FILE_LICENSE OR NOT CPACK_PACKAGE_INSTALL_DIRECTORY) - MESSAGE(FATAL_ERROR "Variables required CPACK_WIX_XSL, CPACK_PACKAGE_FILE_NAME, CPACK_RESOURCE_FILE_LICENSE, CPACK_PACKAGE_INSTALL_DIRECTORY") -ENDIF() - -# use the package defaults if none exists. -# for the community. -#IF ( NOT CPACK_WIX_XSL ) -# -#ENDIF( NOT CPACK_WIX_XSL ) -# - -IF ( CPACK_WIX_WXS_FILES ) - # this could probably be a single expression but I'm no regex guru. - string(REGEX MATCH "[^/]*$" wix_temp "${CPACK_WIX_WXS_FILES}") - string(REGEX REPLACE "[.]wxs" ".wixobj" CPACK_WIX_OBJS "${wix_temp}" ) -ENDIF( CPACK_WIX_WXS_FILES ) - -FIND_PROGRAM(WIX_EXE_HEAT heat PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") -FIND_PROGRAM(WIX_EXE_CNDL candle PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") -FIND_PROGRAM(WIX_EXE_LGHT light PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") - -IF( WIX_EXE_HEAT AND WIX_EXE_CNDL AND WIX_EXE_LGHT ) - SET(CPACK_WIX_HEAT_COMMAND "\"${WIX_EXE_HEAT}\" dir ${CPACK_PACKAGE_INSTALL_DIRECTORY} -ke -g1 -gg -var var.Source -t:${CPACK_WIX_XSL} -out ${CPACK_PACKAGE_FILE_NAME}.wxs") - SET(CPACK_WIX_CNDL_COMMAND "\"${WIX_EXE_CNDL}\" -ext WixFirewallExtension -dSource=${CPACK_PACKAGE_FILE_NAME} ${CPACK_PACKAGE_FILE_NAME}.wxs ${CPACK_WIX_WXS_FILES}") - SET(CPACK_WIX_LGHT_COMMAND "\"${WIX_EXE_LGHT}\" -ext WixUIExtension -ext WixFirewallExtension -dWixUILicenseRtf=${CPACK_RESOURCE_FILE_LICENSE} -out ${CPACK_PACKAGE_FILE_NAME}.msi ${CPACK_PACKAGE_FILE_NAME}.wixobj ${CPACK_WIX_OBJS}") -ELSE() - MESSAGE(FATAL_ERROR "Can not find Wix Executables.") -ENDIF() - - - diff --git a/cmake-2.8.3/Source/CMakeLists.txt b/cmake-2.8.3/Source/CMakeLists.txt index e749497..71284b2 100644 --- a/cmake-2.8.3/Source/CMakeLists.txt +++ b/cmake-2.8.3/Source/CMakeLists.txt @@ -424,7 +424,6 @@ SET(CPACK_SRCS CPack/cmCPackTarBZip2Generator.cxx CPack/cmCPackTarCompressGenerator.cxx CPack/cmCPackZIPGenerator.cxx - CPack/cmCPackWIXGenerator.cxx ) IF(CYGWIN) diff --git a/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx b/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx index 0aca468..a04b403 100644 --- a/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,8 +19,6 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" -#include "cmCPackWIXGenerator.h" - #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -60,8 +58,6 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); - this->RegisterGenerator("WIX", "MSI file format", - cmCPackWIXGenerator::CreateGenerator); this->RegisterGenerator("TBZ2", "Tar BZip2 compression", cmCPackTarBZip2Generator::CreateGenerator); this->RegisterGenerator("TZ", "Tar Compress compression", diff --git a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx deleted file mode 100644 index debb357..0000000 --- a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx +++ /dev/null @@ -1,91 +0,0 @@ -/*============================================================================ - CMake - Cross Platform Makefile Generator - Copyright 2000-2009 Kitware, Inc., Insight Software Consortium - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ - -#include "cmCPackWIXGenerator.h" - -#include "cmSystemTools.h" -#include "cmGeneratedFileStream.h" -#include "cmCPackLog.h" - -#include <cmsys/SystemTools.hxx> - -//---------------------------------------------------------------------- -cmCPackWIXGenerator::cmCPackWIXGenerator() -{ -} - -//---------------------------------------------------------------------- -cmCPackWIXGenerator::~cmCPackWIXGenerator() -{ -} - -//---------------------------------------------------------------------- -int cmCPackWIXGenerator::InitializeInternal() -{ - this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); - this->ReadListFile("CPackWIX.cmake"); - if ((!this->IsSet("WIX_EXE_HEAT")) - || (!this->IsSet("CPACK_WIX_HEAT_COMMAND")) - || (!this->IsSet("WIX_EXE_CNDL")) - || (!this->IsSet("CPACK_WIX_CNDL_COMMAND")) - || (!this->IsSet("WIX_EXE_LGHT")) - || (!this->IsSet("CPACK_WIX_LGHT_COMMAND")) ) - { - cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find a suitable WiX XXprogram" - << std::endl); - return 0; - } - return this->Superclass::InitializeInternal(); -} - -bool cmCPackWIXGenerator::RunWiXCommand(const char * pszVar, const char* toplevel) -{ - bool bRet=true; - std::string output; - int retVal = -1; - std::string cmd = this->GetOption(pszVar); - int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, - &retVal, toplevel, this->GeneratorVerbose, 0); - - int iLevel = cmCPackLog::LOG_OUTPUT; - - cmCPackLogger(iLevel, cmd.c_str() << std::endl ); - - if ( !res || retVal ) - { - iLevel = cmCPackLog::LOG_ERROR; - bRet=false; - } - - cmCPackLogger(iLevel, output.c_str() << std::endl ); - - return bRet; - -} - -//---------------------------------------------------------------------- -int cmCPackWIXGenerator::CompressFiles(const char* outFileName, - const char* toplevel, const std::vector<std::string>& files) -{ - bool bRet=true; - - bRet = this->RunWiXCommand("CPACK_WIX_HEAT_COMMAND", toplevel); - - if (bRet) - bRet = this->RunWiXCommand("CPACK_WIX_CNDL_COMMAND", toplevel); - - if (bRet) - bRet = this->RunWiXCommand("CPACK_WIX_LGHT_COMMAND", toplevel); - - return ((int) bRet); - -} diff --git a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h deleted file mode 100644 index 3aa2d13..0000000 --- a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h +++ /dev/null @@ -1,44 +0,0 @@ -/*============================================================================ - CMake - Cross Platform Makefile Generator - Copyright 2000-2009 Kitware, Inc. - - Distributed under the OSI-approved BSD License (the "License"); - see accompanying file Copyright.txt for details. - - This software is distributed WITHOUT ANY WARRANTY; without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the License for more information. -============================================================================*/ - -#ifndef cmCPackWIXGenerator_h -#define cmCPackWIXGenerator_h - -#include "cmCPackGenerator.h" - - -/** \class cmCPackWIXGenerator - * \brief A generator for WIX files - */ -class cmCPackWIXGenerator : public cmCPackGenerator -{ -public: - cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); - - /** - * Construct generator - */ - cmCPackWIXGenerator(); - virtual ~cmCPackWIXGenerator(); - -protected: - virtual int InitializeInternal(); - int CompressFiles(const char* outFileName, const char* toplevel, - const std::vector<std::string>& files); - virtual const char* GetOutputExtension() { return ".msi"; } - - bool RunWiXCommand(const char * pszVar, const char* toplevel); - -}; - -#endif - cmake-2.8.3-wix-forward.patch [^] (9,998 bytes) 2010-12-07 09:06 [Show Content] [Hide Content] diff --git a/cmake-2.8.3/Modules/CPack.cmake b/cmake-2.8.3/Modules/CPack.cmake index 7033e31..f677ea3 100644 --- a/cmake-2.8.3/Modules/CPack.cmake +++ b/cmake-2.8.3/Modules/CPack.cmake @@ -837,6 +837,7 @@ if(NOT CPACK_GENERATOR) else(UNIX) option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) + option(CPACK_BINARY_WIX "Enable to build WIX packages" OFF) endif(UNIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_BUNDLE Bundle) @@ -852,6 +853,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) endif(NOT CPACK_GENERATOR) @@ -883,7 +885,7 @@ mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ - CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) + CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP CPACK_BINARY_WIX) # Set some other variables cpack_set_if_not_set(CPACK_INSTALL_CMAKE_PROJECTS diff --git a/cmake-2.8.3/Modules/CPackWIX.cmake b/cmake-2.8.3/Modules/CPackWIX.cmake new file mode 100755 index 0000000..0dd9c4e --- /dev/null +++ b/cmake-2.8.3/Modules/CPackWIX.cmake @@ -0,0 +1,49 @@ + +#============================================================================= +# Copyright 2007-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distributed this file outside of CMake, substitute the full +# License text for the above reference.) + +IF(CMAKE_BINARY_DIR) + MESSAGE(FATAL_ERROR "CPackWIX.cmake may only be used by CPack internally.") +ENDIF(CMAKE_BINARY_DIR) + +IF(NOT CPACK_WIX_XSL OR NOT CPACK_PACKAGE_FILE_NAME OR NOT CPACK_RESOURCE_FILE_LICENSE OR NOT CPACK_PACKAGE_INSTALL_DIRECTORY) + MESSAGE(FATAL_ERROR "Variables required CPACK_WIX_XSL, CPACK_PACKAGE_FILE_NAME, CPACK_RESOURCE_FILE_LICENSE, CPACK_PACKAGE_INSTALL_DIRECTORY") +ENDIF() + +# use the package defaults if none exists. +# for the community. +#IF ( NOT CPACK_WIX_XSL ) +# +#ENDIF( NOT CPACK_WIX_XSL ) +# + +IF ( CPACK_WIX_WXS_FILES ) + # this could probably be a single expression but I'm no regex guru. + string(REGEX MATCH "[^/]*$" wix_temp "${CPACK_WIX_WXS_FILES}") + string(REGEX REPLACE "[.]wxs" ".wixobj" CPACK_WIX_OBJS "${wix_temp}" ) +ENDIF( CPACK_WIX_WXS_FILES ) + +FIND_PROGRAM(WIX_EXE_HEAT heat PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") +FIND_PROGRAM(WIX_EXE_CNDL candle PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") +FIND_PROGRAM(WIX_EXE_LGHT light PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") + +IF( WIX_EXE_HEAT AND WIX_EXE_CNDL AND WIX_EXE_LGHT ) + SET(CPACK_WIX_HEAT_COMMAND "\"${WIX_EXE_HEAT}\" dir ${CPACK_PACKAGE_INSTALL_DIRECTORY} -ke -g1 -gg -var var.Source -t:${CPACK_WIX_XSL} -out ${CPACK_PACKAGE_FILE_NAME}.wxs") + SET(CPACK_WIX_CNDL_COMMAND "\"${WIX_EXE_CNDL}\" -ext WixFirewallExtension -dSource=${CPACK_PACKAGE_FILE_NAME} ${CPACK_PACKAGE_FILE_NAME}.wxs ${CPACK_WIX_WXS_FILES}") + SET(CPACK_WIX_LGHT_COMMAND "\"${WIX_EXE_LGHT}\" -ext WixUIExtension -ext WixFirewallExtension -dWixUILicenseRtf=${CPACK_RESOURCE_FILE_LICENSE} -out ${CPACK_PACKAGE_FILE_NAME}.msi ${CPACK_PACKAGE_FILE_NAME}.wixobj ${CPACK_WIX_OBJS}") +ELSE() + MESSAGE(FATAL_ERROR "Can not find Wix Executables.") +ENDIF() + + + diff --git a/cmake-2.8.3/Source/CMakeLists.txt b/cmake-2.8.3/Source/CMakeLists.txt index 71284b2..e749497 100644 --- a/cmake-2.8.3/Source/CMakeLists.txt +++ b/cmake-2.8.3/Source/CMakeLists.txt @@ -424,6 +424,7 @@ SET(CPACK_SRCS CPack/cmCPackTarBZip2Generator.cxx CPack/cmCPackTarCompressGenerator.cxx CPack/cmCPackZIPGenerator.cxx + CPack/cmCPackWIXGenerator.cxx ) IF(CYGWIN) diff --git a/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx b/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx index a04b403..0aca468 100644 --- a/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/cmake-2.8.3/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,8 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" +#include "cmCPackWIXGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -58,6 +60,8 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); + this->RegisterGenerator("WIX", "MSI file format", + cmCPackWIXGenerator::CreateGenerator); this->RegisterGenerator("TBZ2", "Tar BZip2 compression", cmCPackTarBZip2Generator::CreateGenerator); this->RegisterGenerator("TZ", "Tar Compress compression", diff --git a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..debb357 --- /dev/null +++ b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.cxx @@ -0,0 +1,91 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include "cmSystemTools.h" +#include "cmGeneratedFileStream.h" +#include "cmCPackLog.h" + +#include <cmsys/SystemTools.hxx> + +//---------------------------------------------------------------------- +cmCPackWIXGenerator::cmCPackWIXGenerator() +{ +} + +//---------------------------------------------------------------------- +cmCPackWIXGenerator::~cmCPackWIXGenerator() +{ +} + +//---------------------------------------------------------------------- +int cmCPackWIXGenerator::InitializeInternal() +{ + this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); + this->ReadListFile("CPackWIX.cmake"); + if ((!this->IsSet("WIX_EXE_HEAT")) + || (!this->IsSet("CPACK_WIX_HEAT_COMMAND")) + || (!this->IsSet("WIX_EXE_CNDL")) + || (!this->IsSet("CPACK_WIX_CNDL_COMMAND")) + || (!this->IsSet("WIX_EXE_LGHT")) + || (!this->IsSet("CPACK_WIX_LGHT_COMMAND")) ) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot find a suitable WiX XXprogram" + << std::endl); + return 0; + } + return this->Superclass::InitializeInternal(); +} + +bool cmCPackWIXGenerator::RunWiXCommand(const char * pszVar, const char* toplevel) +{ + bool bRet=true; + std::string output; + int retVal = -1; + std::string cmd = this->GetOption(pszVar); + int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, + &retVal, toplevel, this->GeneratorVerbose, 0); + + int iLevel = cmCPackLog::LOG_OUTPUT; + + cmCPackLogger(iLevel, cmd.c_str() << std::endl ); + + if ( !res || retVal ) + { + iLevel = cmCPackLog::LOG_ERROR; + bRet=false; + } + + cmCPackLogger(iLevel, output.c_str() << std::endl ); + + return bRet; + +} + +//---------------------------------------------------------------------- +int cmCPackWIXGenerator::CompressFiles(const char* outFileName, + const char* toplevel, const std::vector<std::string>& files) +{ + bool bRet=true; + + bRet = this->RunWiXCommand("CPACK_WIX_HEAT_COMMAND", toplevel); + + if (bRet) + bRet = this->RunWiXCommand("CPACK_WIX_CNDL_COMMAND", toplevel); + + if (bRet) + bRet = this->RunWiXCommand("CPACK_WIX_LGHT_COMMAND", toplevel); + + return ((int) bRet); + +} diff --git a/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h new file mode 100644 index 0000000..3aa2d13 --- /dev/null +++ b/cmake-2.8.3/Source/CPack/cmCPackWIXGenerator.h @@ -0,0 +1,44 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include "cmCPackGenerator.h" + + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + + /** + * Construct generator + */ + cmCPackWIXGenerator(); + virtual ~cmCPackWIXGenerator(); + +protected: + virtual int InitializeInternal(); + int CompressFiles(const char* outFileName, const char* toplevel, + const std::vector<std::string>& files); + virtual const char* GetOutputExtension() { return ".msi"; } + + bool RunWiXCommand(const char * pszVar, const char* toplevel); + +}; + +#endif + 0001-CPack-Add-WiX-generator-for-building-.msi-installers.patch [^] (10,966 bytes) 2012-08-25 11:53 [Show Content] [Hide Content] From 990f206ce4a7a87ba97ce39d057ce4e670138dbd Mon Sep 17 00:00:00 2001 From: David Cole <david.cole@kitware.com> Date: Sat, 25 Aug 2012 10:30:35 -0400 Subject: [PATCH] CPack: Add WiX generator for building *.msi installers via WiX tools. Thanks to Timothy St. Clair for the initial patch in the CMake bug tracker. --- Modules/CPack.cmake | 4 +- Modules/CPackWIX.cmake | 58 +++++++++++++++++++ Source/CMakeLists.txt | 1 + Source/CPack/cmCPackGeneratorFactory.cxx | 7 ++ Source/CPack/cmCPackWIXGenerator.cxx | 92 ++++++++++++++++++++++++++++++ Source/CPack/cmCPackWIXGenerator.h | 43 ++++++++++++++ 6 files changed, 204 insertions(+), 1 deletions(-) create mode 100644 Modules/CPackWIX.cmake create mode 100644 Source/CPack/cmCPackWIXGenerator.cxx create mode 100644 Source/CPack/cmCPackWIXGenerator.h diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 6886ed9..506d2f5 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -438,6 +438,7 @@ if(NOT CPACK_GENERATOR) endif() else() option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) + option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) endif() @@ -453,6 +454,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WiX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) endif() @@ -483,7 +485,7 @@ endif() mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11 CPACK_BINARY_STGZ CPACK_BINARY_TGZ CPACK_BINARY_TBZ2 CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ - CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE + CPACK_BINARY_NSIS CPACK_BINARY_WIX CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake new file mode 100644 index 0000000..0776980 --- /dev/null +++ b/Modules/CPackWIX.cmake @@ -0,0 +1,58 @@ +##section Variables specific to CPack WiX generator +##end +##module +# - CPack WiX generator specific options +# +# The following variables are specific to the installers built +# on Windows using WiX. +##end +# +##variable +# CPACK_WIX_XSL - The WiX xsl file +##end + +#============================================================================= +# Copyright 2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(CMAKE_BINARY_DIR) + message(FATAL_ERROR "CPackWIX.cmake may only be used by CPack internally.") +endif() + +if(NOT CPACK_WIX_XSL OR NOT CPACK_PACKAGE_FILE_NAME OR NOT CPACK_RESOURCE_FILE_LICENSE OR NOT CPACK_PACKAGE_INSTALL_DIRECTORY) + message(FATAL_ERROR "Variables required CPACK_WIX_XSL, CPACK_PACKAGE_FILE_NAME, CPACK_RESOURCE_FILE_LICENSE, CPACK_PACKAGE_INSTALL_DIRECTORY") +endif() + +# use the package defaults if none exists. +# for the community. +#if(NOT CPACK_WIX_XSL) +# +#endif() +# + +if(CPACK_WIX_WXS_FILES) + # this could probably be a single expression but I'm no regex guru. + string(REGEX MATCH "[^/]*$" wix_temp "${CPACK_WIX_WXS_FILES}") + string(REGEX REPLACE "[.]wxs" ".wixobj" CPACK_WIX_OBJS "${wix_temp}") +endif() + +find_program(WIX_EXE_HEAT heat PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") +find_program(WIX_EXE_CNDL candle PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") +find_program(WIX_EXE_LGHT light PATHS "$ENV{ProgramFiles}/Windows Installer XML v3/bin") + +if(WIX_EXE_HEAT AND WIX_EXE_CNDL AND WIX_EXE_LGHT) + set(CPACK_WIX_HEAT_COMMAND "\"${WIX_EXE_HEAT}\" dir ${CPACK_PACKAGE_INSTALL_DIRECTORY} -ke -g1 -gg -var var.Source -t:${CPACK_WIX_XSL} -out ${CPACK_PACKAGE_FILE_NAME}.wxs") + set(CPACK_WIX_CNDL_COMMAND "\"${WIX_EXE_CNDL}\" -ext WixFirewallExtension -dSource=${CPACK_PACKAGE_FILE_NAME} ${CPACK_PACKAGE_FILE_NAME}.wxs ${CPACK_WIX_WXS_FILES}") + set(CPACK_WIX_LGHT_COMMAND "\"${WIX_EXE_LGHT}\" -ext WixUIExtension -ext WixFirewallExtension -dWixUILicenseRtf=${CPACK_RESOURCE_FILE_LICENSE} -out ${CPACK_PACKAGE_FILE_NAME}.msi ${CPACK_PACKAGE_FILE_NAME}.wixobj ${CPACK_WIX_OBJS}") +else() + message(FATAL_ERROR "Can not find Wix Executables.") +endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e79689b..5b725d6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -478,6 +478,7 @@ set(CPACK_SRCS CPack/cmCPackTGZGenerator.cxx CPack/cmCPackTarBZip2Generator.cxx CPack/cmCPackTarCompressGenerator.cxx + CPack/cmCPackWIXGenerator.cxx CPack/cmCPackZIPGenerator.cxx CPack/cmCPackDocumentVariables.cxx CPack/cmCPackDocumentMacros.cxx diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 37ff460..e2219fd 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,8 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" +#include "cmCPackWIXGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -80,6 +82,11 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); } + if (cmCPackWIXGenerator::CanGenerate()) + { + this->RegisterGenerator("WIX", "MSI file format via WiX tools", + cmCPackWIXGenerator::CreateGenerator); + } if (cmCPackTarBZip2Generator::CanGenerate()) { this->RegisterGenerator("TBZ2", "Tar BZip2 compression", diff --git a/Source/CPack/cmCPackWIXGenerator.cxx b/Source/CPack/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..589078d --- /dev/null +++ b/Source/CPack/cmCPackWIXGenerator.cxx @@ -0,0 +1,92 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include "cmSystemTools.h" +#include "cmGeneratedFileStream.h" +#include "cmCPackLog.h" + +#include <cmsys/SystemTools.hxx> + +//---------------------------------------------------------------------- +cmCPackWIXGenerator::cmCPackWIXGenerator() +{ +} + +//---------------------------------------------------------------------- +cmCPackWIXGenerator::~cmCPackWIXGenerator() +{ +} + +//---------------------------------------------------------------------- +int cmCPackWIXGenerator::InitializeInternal() +{ + this->SetOptionIfNotSet("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", "1"); + this->ReadListFile("CPackWIX.cmake"); + if ((!this->IsSet("WIX_EXE_HEAT")) + || (!this->IsSet("CPACK_WIX_HEAT_COMMAND")) + || (!this->IsSet("WIX_EXE_CNDL")) + || (!this->IsSet("CPACK_WIX_CNDL_COMMAND")) + || (!this->IsSet("WIX_EXE_LGHT")) + || (!this->IsSet("CPACK_WIX_LGHT_COMMAND")) ) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Cannot find a suitable WiX program" << std::endl); + return 0; + } + return this->Superclass::InitializeInternal(); +} + +bool cmCPackWIXGenerator::RunWiXCommand(const char * pszVar, + const char* toplevel) +{ + bool bRet=true; + std::string output; + int retVal = -1; + std::string cmd = this->GetOption(pszVar); + int res = cmSystemTools::RunSingleCommand(cmd.c_str(), &output, + &retVal, toplevel, this->GeneratorVerbose, 0); + + int iLevel = cmCPackLog::LOG_OUTPUT; + + cmCPackLogger(iLevel, cmd.c_str() << std::endl ); + + if ( !res || retVal ) + { + iLevel = cmCPackLog::LOG_ERROR; + bRet=false; + } + + cmCPackLogger(iLevel, output.c_str() << std::endl ); + + return bRet; +} + +//---------------------------------------------------------------------- +int cmCPackWIXGenerator::CompressFiles(const char* outFileName, + const char* toplevel, const std::vector<std::string>& files) +{ + bool bRet = this->RunWiXCommand("CPACK_WIX_HEAT_COMMAND", toplevel); + + if (bRet) + { + bRet = this->RunWiXCommand("CPACK_WIX_CNDL_COMMAND", toplevel); + } + + if (bRet) + { + bRet = this->RunWiXCommand("CPACK_WIX_LGHT_COMMAND", toplevel); + } + + return bRet ? 1 : 0; +} diff --git a/Source/CPack/cmCPackWIXGenerator.h b/Source/CPack/cmCPackWIXGenerator.h new file mode 100644 index 0000000..03b710b --- /dev/null +++ b/Source/CPack/cmCPackWIXGenerator.h @@ -0,0 +1,43 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include "cmCPackGenerator.h" + + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + + /** + * Construct generator + */ + cmCPackWIXGenerator(); + virtual ~cmCPackWIXGenerator(); + +protected: + virtual int InitializeInternal(); + int CompressFiles(const char* outFileName, const char* toplevel, + const std::vector<std::string>& files); + virtual const char* GetOutputExtension() { return ".msi"; } + + bool RunWiXCommand(const char * pszVar, const char* toplevel); + +}; + +#endif -- 1.7.3.1.msysgit.0 0001-alternate-WiX-cpack-implementation.patch [^] (15,552 bytes) 2012-09-03 13:42 [Show Content] [Hide Content] From 56bded37d520c49b9e14b7350a23952831482109 Mon Sep 17 00:00:00 2001 From: Nils Gladitz <gladitz@scivis.de> Date: Mon, 3 Sep 2012 10:57:46 +0200 Subject: [PATCH] alternate WiX cpack implementation --- Modules/CPack.cmake | 4 +- Modules/CPackWIX.cmake | 49 ++++++ Modules/WIX.template.in | 24 +++ Source/CMakeLists.txt | 1 + Source/CPack/cmCPackGeneratorFactory.cxx | 7 + Source/CPack/cmCPackWIXGenerator.cxx | 248 ++++++++++++++++++++++++++++++ Source/CPack/cmCPackWIXGenerator.h | 62 ++++++++ 7 files changed, 394 insertions(+), 1 deletions(-) create mode 100644 Modules/CPackWIX.cmake create mode 100644 Modules/WIX.template.in create mode 100644 Source/CPack/cmCPackWIXGenerator.cxx create mode 100644 Source/CPack/cmCPackWIXGenerator.h diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 6886ed9..b669bf4 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -438,6 +438,7 @@ if(NOT CPACK_GENERATOR) endif() else() option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) + option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) endif() @@ -453,6 +454,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) endif() @@ -483,7 +485,7 @@ endif() mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11 CPACK_BINARY_STGZ CPACK_BINARY_TGZ CPACK_BINARY_TBZ2 CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ - CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE + CPACK_BINARY_NSIS CPACK_BINARY_WIX CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake new file mode 100644 index 0000000..ae41474 --- /dev/null +++ b/Modules/CPackWIX.cmake @@ -0,0 +1,49 @@ +##section Variables specific to CPack WiX generator +##end +##module +# - CPack WiX generator specific options +# +# The following variables are specific to the installers built +# on Windows using WiX. +##end +# +#============================================================================= +# Copyright 2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(NOT CPACK_WIX_ROOT) + file(TO_CMAKE_PATH "$ENV{WIX}" CPACK_WIX_ROOT) +endif() + +if(NOT CPACK_WIX_CANDLE_COMMAND) + find_program(CPACK_WIX_CANDLE_EXECUTABLE candle + PATHS "${CPACK_WIX_ROOT}/bin") + + if(NOT CPACK_WIX_CANDLE_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX candle executable.") + endif() + + set(CPACK_WIX_CANDLE_COMMAND + "\"${CPACK_WIX_CANDLE_EXECUTABLE}\" -out <OUTPUT> <SOURCE>") +endif() + +if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + find_program(CPACK_WIX_LIGHT_EXECUTABLE light + PATHS "${CPACK_WIX_ROOT}/bin") + + if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX light executable.") + endif() + + set(CPACK_WIX_LIGHT_COMMAND + "\"${CPACK_WIX_LIGHT_EXECUTABLE}\" -out <OUTPUT> <OBJECT>") +endif() diff --git a/Modules/WIX.template.in b/Modules/WIX.template.in new file mode 100644 index 0000000..8bedb25 --- /dev/null +++ b/Modules/WIX.template.in @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Product Id="*" Name="@CPACK_PACKAGE_NAME@" + Language="1033" + Version="@CPACK_PACKAGE_VERSION_MAJOR@.@CPACK_PACKAGE_VERSION_MINOR@.@CPACK_PACKAGE_VERSION_PATCH@" + Manufacturer="@CPACK_PACKAGE_VENDOR@"> + + <Package InstallerVersion="301" Compressed="yes"/> + + <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/> + + <Directory Id="TARGETDIR" Name="SourceDir"> + <Directory Id="ProgramFilesFolder"> + @CPACK_WIX_DIRECTORY_DEFINITIONS@ + </Directory> + </Directory> + + @CPACK_WIX_FILE_DEFINITIONS@ + + <Feature Id="ProductFeature" Title="@CPACK_PACKAGE_NAME@" Level="1"> + @CPACK_WIX_FEATURE_DEFINITIONS@ + </Feature> + </Product> +</Wix> diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e79689b..5b725d6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -478,6 +478,7 @@ set(CPACK_SRCS CPack/cmCPackTGZGenerator.cxx CPack/cmCPackTarBZip2Generator.cxx CPack/cmCPackTarCompressGenerator.cxx + CPack/cmCPackWIXGenerator.cxx CPack/cmCPackZIPGenerator.cxx CPack/cmCPackDocumentVariables.cxx CPack/cmCPackDocumentMacros.cxx diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 37ff460..e2219fd 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,8 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" +#include "cmCPackWIXGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -80,6 +82,11 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); } + if (cmCPackWIXGenerator::CanGenerate()) + { + this->RegisterGenerator("WIX", "MSI file format via WiX tools", + cmCPackWIXGenerator::CreateGenerator); + } if (cmCPackTarBZip2Generator::CanGenerate()) { this->RegisterGenerator("TBZ2", "Tar BZip2 compression", diff --git a/Source/CPack/cmCPackWIXGenerator.cxx b/Source/CPack/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..246fc1f --- /dev/null +++ b/Source/CPack/cmCPackWIXGenerator.cxx @@ -0,0 +1,248 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include "cmSystemTools.h" +#include "cmGeneratedFileStream.h" +#include "cmCPackLog.h" +#include "cmCPackComponentGroup.h" + +#include <cmsys/SystemTools.hxx> +#include <cmsys/Directory.hxx> + +cmCPackWIXGenerator::cmCPackWIXGenerator() +{ +} + +cmCPackWIXGenerator::~cmCPackWIXGenerator() +{ +} + +int cmCPackWIXGenerator::InitializeInternal() +{ + return this->Superclass::InitializeInternal(); +} + +bool cmCPackWIXGenerator::RunWiXCommand( + const std::string& command, const std::string& logFileName) +{ + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Running WiX command: " << command << std::endl); + + std::string output; + + int returnValue = -1; + bool status =cmSystemTools::RunSingleCommand(command.c_str(), &output, + &returnValue, 0, cmSystemTools::OUTPUT_NONE); + + std::ofstream logFile(logFileName.c_str()); + logFile << output; + logFile.close(); + + if(!status || returnValue) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running WiX candle. " + "Please check '" << logFileName << "' for errors." << std::endl); + return false; + } + + return true; +} + +int cmCPackWIXGenerator::PackageFiles() +{ + if(!ReadListFile("CPackWIX.cmake")) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error while executing CPackWIX.cmake" << std::endl); + + return 0; + } + + std::string cpackTopLevel = GetOption("CPACK_TOPLEVEL_DIRECTORY"); + std::string wixSourceFile = cpackTopLevel + "/project.wxs"; + std::string wixObjectFile = cpackTopLevel + "/project.wixobj"; + std::string wixLogBase = cpackTopLevel + "/project-"; + + CreateWiXSourceFile(wixSourceFile); + + std::string candleCommand = GetOption("CPACK_WIX_CANDLE_COMMAND"); + + cmSystemTools::ReplaceString(candleCommand, "<OUTPUT>", + QuotePath(wixObjectFile).c_str()); + + cmSystemTools::ReplaceString(candleCommand, "<SOURCE>", + QuotePath(wixSourceFile).c_str()); + + if(!RunWiXCommand(candleCommand, wixLogBase + "candle.log")) return 0; + + std::string lightCommand = GetOption("CPACK_WIX_LIGHT_COMMAND"); + + std::string packageFilePath = packageFileNames.at(0); + + cmSystemTools::ReplaceString(lightCommand, "<OUTPUT>", + QuotePath(packageFilePath).c_str()); + + cmSystemTools::ReplaceString(lightCommand, "<OBJECT>", + QuotePath(wixObjectFile).c_str()); + + if(!RunWiXCommand(lightCommand, wixLogBase + "light.log")) return 0; + + return 1; +} + +bool cmCPackWIXGenerator::CreateWiXSourceFile( + const std::string& sourceFilePath) +{ + std::stringstream directoryDefintions; + std::stringstream fileDefinitions; + std::stringstream featureDefinitions; + + std::vector<std::string> install_root; + cmSystemTools::SplitPath(GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY"), + install_root); + + if(!install_root.empty() && install_root.back().empty()) + install_root.pop_back(); + + for(std::size_t i = 1; i < install_root.size(); ++i) + { + directoryDefintions << "<Directory Id='"; + if(i == install_root.size() - 1) + { + directoryDefintions << "INSTALL_ROOT"; + } + else + { + directoryDefintions << "INSTALL_PREFIX_" << i; + } + + directoryDefintions << "' Name='" << + XmlEscape(install_root[i]) << "'>"; + } + + std::size_t directoryCounter = 0; + std::size_t fileCounter = 0; + + AddDirectoryAndFileDefinitons( + toplevel, "INSTALL_ROOT", + directoryDefintions, fileDefinitions, featureDefinitions, + directoryCounter, fileCounter); + + for(std::size_t i = 1; i < install_root.size(); ++i) + { + directoryDefintions << "</Directory>" << std::endl; + } + + SetOption("CPACK_WIX_FILE_DEFINITIONS", + fileDefinitions.str().c_str()); + + SetOption("CPACK_WIX_DIRECTORY_DEFINITIONS", + directoryDefintions.str().c_str()); + + SetOption("CPACK_WIX_FEATURE_DEFINITIONS", + featureDefinitions.str().c_str()); + + std::string wixTemplate = FindTemplate("WIX.template.in"); + if(wixTemplate.empty()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Could not find CPack WiX template file WIX.template.in"); + return false; + } + + if(!ConfigureFile(wixTemplate.c_str(), sourceFilePath.c_str())) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed creating '" << sourceFilePath << "'' from template."); + return false; + } + + return true; +} + +void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( + const std::string& topdir, + const std::string& directoryId, + std::ostream& directoryDefinitions, + std::ostream& fileDefinitions, + std::ostream& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter) +{ + cmsys::Directory dir; + dir.Load(topdir.c_str()); + + for(std::size_t i = 0; i < dir.GetNumberOfFiles(); ++i) + { + std::string fileName = dir.GetFile(static_cast<unsigned long>(i)); + + if(fileName == "." || fileName == "..") continue; + + std::string fullPath = topdir + "/" + fileName; + + if(cmSystemTools::FileIsDirectory(fullPath.c_str())) + { + std::stringstream tmp; + tmp << "DIR_ID_" << ++directoryCounter; + std::string subDirectoryId = tmp.str(); + + directoryDefinitions << + "<Directory Id='" << subDirectoryId << + "' Name='" << XmlEscape(fileName) << "'>" << std::endl; + + AddDirectoryAndFileDefinitons( + fullPath, subDirectoryId, + directoryDefinitions, + fileDefinitions, + featureDefinitions, + directoryCounter, + fileCounter); + + directoryDefinitions << "</Directory>" << std::endl; + } + else + { + std::stringstream tmp; + tmp << "_ID_" << ++fileCounter; + std::string fileId = tmp.str(); + + fileDefinitions << + "<DirectoryRef Id='" << directoryId << "'>" << std::endl; + + fileDefinitions << + "<Component Id='CMP" << fileId << "' Guid='*'>" << std::endl; + + fileDefinitions << + "<File Id='FILE" << fileId << + "' Source='" << XmlEscape(fullPath) << "' KeyPath='yes'/>" + << std::endl; + + fileDefinitions << "</Component></DirectoryRef>" << std::endl; + + featureDefinitions << "<ComponentRef Id='CMP" << fileId << "'/>" << + std::endl; + } + } +} + +std::string cmCPackWIXGenerator::XmlEscape(const std::string& input) +{ + return input; // TODO: implement me +} + +std::string cmCPackWIXGenerator::QuotePath(const std::string& path) +{ + return std::string("\"") + path + '"'; +} diff --git a/Source/CPack/cmCPackWIXGenerator.h b/Source/CPack/cmCPackWIXGenerator.h new file mode 100644 index 0000000..b663359 --- /dev/null +++ b/Source/CPack/cmCPackWIXGenerator.h @@ -0,0 +1,62 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include "cmCPackGenerator.h" + +#include <string> +#include <map> + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + + /** + * Construct generator + */ + cmCPackWIXGenerator(); + virtual ~cmCPackWIXGenerator(); + +protected: + virtual int InitializeInternal(); + + virtual int PackageFiles(); + + virtual const char* GetOutputExtension() { return ".msi"; } + +private: + bool CreateWiXSourceFile(const std::string& sourceFilePath); + + bool RunWiXCommand( + const std::string& command, const std::string& logFileName); + + void AddDirectoryAndFileDefinitons(const std::string& topdir, + const std::string& directoryId, + std::ostream& directoryDefinitions, + std::ostream& fileDefinitions, + std::ostream& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter); + + static std::string XmlEscape(const std::string& input); + + static std::string QuotePath(const std::string& path); + +}; + +#endif -- 1.7.9.msysgit.0 0001-CPack-WiX-Generator.patch [^] (33,985 bytes) 2012-09-10 03:27 [Show Content] [Hide Content] From 5436b18b8f27a5a17fbef3a9d31c367c52cffeef Mon Sep 17 00:00:00 2001 From: Nils Gladitz <gladitz@scivis.de> Date: Mon, 10 Sep 2012 09:19:21 +0200 Subject: [PATCH] CPack WiX Generator --- Modules/CPack.cmake | 7 +- Modules/CPackWIX.cmake | 58 +++ Modules/WIX.template.in | 20 + Source/CMakeLists.txt | 7 + Source/CPack/WiX/cmCPackWIXGenerator.cxx | 407 ++++++++++++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.h | 80 ++++ Source/CPack/WiX/cmWIXSourceWriter.cxx | 140 +++++++ Source/CPack/WiX/cmWIXSourceWriter.h | 54 +++ Source/CPack/cmCPackGeneratorFactory.cxx | 11 + Tests/CMakeLists.txt | 22 + Tests/CPackWiXGenerator/CMakeLists.txt | 71 ++++ Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake | 67 ++++ Tests/CPackWiXGenerator/mylib.cpp | 7 + Tests/CPackWiXGenerator/mylib.h | 1 + Tests/CPackWiXGenerator/mylibapp.cpp | 6 + 15 files changed, 957 insertions(+), 1 deletions(-) create mode 100644 Modules/CPackWIX.cmake create mode 100644 Modules/WIX.template.in create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.cxx create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.h create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.cxx create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.h create mode 100644 Tests/CPackWiXGenerator/CMakeLists.txt create mode 100644 Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake create mode 100644 Tests/CPackWiXGenerator/mylib.cpp create mode 100644 Tests/CPackWiXGenerator/mylib.h create mode 100644 Tests/CPackWiXGenerator/mylibapp.cpp diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 6886ed9..42d3c0c 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -438,6 +438,7 @@ if(NOT CPACK_GENERATOR) endif() else() option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) + option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) endif() @@ -453,6 +454,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) endif() @@ -483,7 +485,7 @@ endif() mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11 CPACK_BINARY_STGZ CPACK_BINARY_TGZ CPACK_BINARY_TBZ2 CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ - CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE + CPACK_BINARY_NSIS CPACK_BINARY_WIX CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) @@ -522,6 +524,9 @@ cpack_set_if_not_set(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_ICON_CODE "") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") +# WiX specific variables +cpack_set_if_not_set(CPACK_WIX_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}") + if(DEFINED CPACK_COMPONENTS_ALL) if(CPACK_MONOLITHIC_INSTALL) message("CPack warning: both CPACK_COMPONENTS_ALL and CPACK_MONOLITHIC_INSTALL have been set.\nDefaulting to a monolithic installation.") diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake new file mode 100644 index 0000000..18ba013 --- /dev/null +++ b/Modules/CPackWIX.cmake @@ -0,0 +1,58 @@ +##section Variables specific to CPack WiX generator +##end +##module +# - CPack WiX generator specific options +# +# The following variables are specific to the installers built +# on Windows using WiX. +##end +##variable +# CPACK_WIX_UPGRADE_GUID - Upgrade GUID +# +# Will be automatically generated unless explicitly provided. +# +# It should be explicitly set to a constant generated +# gloabally unique identifier (GUID) to allow your installers +# to replace existing installations that use the same GUID. +# +# You may for example explicitly set this variable in +# your CMakeLists.txt to the value that has been generated per default. +# You should not use GUIDs that you did not generate yourself or which may +# belong to other projects. +# +# A GUID shall have the following fixed length syntax: +# XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX +# (each X represents an uppercase hexadecimal digit) +##end +# + +#============================================================================= +# Copyright 2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(NOT CPACK_WIX_ROOT) + file(TO_CMAKE_PATH "$ENV{WIX}" CPACK_WIX_ROOT) +endif() + +find_program(CPACK_WIX_CANDLE_EXECUTABLE candle + PATHS "${CPACK_WIX_ROOT}/bin") + +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}/bin") + +if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX light executable.") +endif() diff --git a/Modules/WIX.template.in b/Modules/WIX.template.in new file mode 100644 index 0000000..df0f307 --- /dev/null +++ b/Modules/WIX.template.in @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?include "cpack_variables.wxi"?> + +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> + <Product Id="*" Name="$(var.CPACK_PACKAGE_NAME)" + Language="1033" + Version="$(var.CPACK_PACKAGE_VERSION)" + Manufacturer="$(var.CPACK_PACKAGE_VENDOR)" + UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)"> + + <Package InstallerVersion="301" Compressed="yes"/> + + <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/> + + <Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/> + + <FeatureRef Id="ProductFeature"/> + </Product> +</Wix> diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e79689b..f50417d 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -497,6 +497,13 @@ if(UNIX) ) endif() +if(WIN32) + set(CPACK_SRCS ${CPACK_SRCS} + CPack/WiX/cmCPackWIXGenerator.cxx + CPack/WiX/cmWIXSourceWriter.cxx + ) +endif() + if(APPLE) set(CPACK_SRCS ${CPACK_SRCS} CPack/cmCPackBundleGenerator.cxx diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..6876dfa --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -0,0 +1,407 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include "../cmSystemTools.h" +#include "../cmGeneratedFileStream.h" +#include "../cmCPackLog.h" +#include "../cmCPackComponentGroup.h" + +#include "cmWIXSourceWriter.h" + +#include <cmsys/SystemTools.hxx> +#include <cmsys/Directory.hxx> + +#include <rpc.h> // for GUID generation + +int cmCPackWIXGenerator::InitializeInternal() +{ + return this->Superclass::InitializeInternal(); +} + +void cmCPackWIXGenerator::RunWiXCommand(const std::string& command) +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string logFileName = cpackTopLevel + "/wix.log"; + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Running WiX command: " << command << std::endl); + + std::string output; + + int returnValue = 0; + bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output, + &returnValue, 0, cmSystemTools::OUTPUT_NONE); + + std::ofstream logFile(logFileName.c_str(), std::ios::app); + logFile << command << std::endl; + logFile << output; + logFile.close(); + + if(!status || returnValue) + { + std::stringstream tmp; + tmp << "Problem running WiX candle. " + "Please check '" << logFileName << "' for errors."; + + throw std::runtime_error(tmp.str()); + } +} + +void cmCPackWIXGenerator::RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile) +{ + std::stringstream command; + command << QuotePath(RequireOption("CPACK_WIX_CANDLE_EXECUTABLE")); + command << " -nologo"; + command << " -arch " << GetArchitecture(); + command << " -out " << QuotePath(objectFile); + command << " " << QuotePath(sourceFile); + + RunWiXCommand(command.str()); +} + +void cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) +{ + std::stringstream command; + command << QuotePath(RequireOption("CPACK_WIX_LIGHT_EXECUTABLE")); + command << " -nologo"; + command << " -out " << QuotePath(packageFileNames.at(0)); + command << " -ext WixUIExtension"; + command << " " << objectFiles; + + RunWiXCommand(command.str()); +} + +int cmCPackWIXGenerator::PackageFiles() +{ + try + { + PackageFilesImpl(); + } + catch(std::exception& e) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Fatal WiX Generator Error: " << e.what() << std::endl); + + return false; + } + + return true; +} + +void cmCPackWIXGenerator::InitializeWiXConfiguration() +{ + if(!ReadListFile("CPackWIX.cmake")) + { + throw std::runtime_error("Error while executing CPackWIX.cmake"); + } + + if(GetOption("CPACK_WIX_UPGRADE_GUID") == 0) + { + std::string guid = GenerateGUID(); + SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str()); + + cmCPackLogger(cmCPackLog::LOG_WARNING, + "CPACK_WIX_UPGRADE_GUID implicitly set to " << guid << " . " + "Please refer to the documentation on how and why " + "you might want to set this explicitly." << std::endl); + } +} + +void cmCPackWIXGenerator::PackageFilesImpl() +{ + InitializeWiXConfiguration(); + + CreateWiXVariablesIncludeFile(); + CreateWiXSourceFiles(); + + std::stringstream objectFiles; + for(std::size_t i = 0; i < wixSources.size(); ++i) + { + const std::string& sourceFilename = wixSources[i]; + + std::string objectFilename = + cmSystemTools::GetFilenameWithoutExtension(sourceFilename) + ".wixobj"; + + RunCandleCommand(sourceFilename, objectFilename); + + objectFiles << " " << QuotePath(objectFilename); + } + + RunLightCommand(objectFiles.str()); +} + +void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string includeFilename = + cpackTopLevel + "/cpack_variables.wxi"; + + cmWIXSourceWriter includeFile(includeFilename, true); + CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR"); + CopyDefinition(includeFile, "CPACK_PACKAGE_NAME"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION"); + CopyDefinition(includeFile, "CPACK_RESOURCE_FILE_LICENSE"); +} + +void cmCPackWIXGenerator::CopyDefinition( + cmWIXSourceWriter &source, const std::string &name) +{ + const char* value = GetOption(name.c_str()); + if(value) AddDefinition(source, name, value); +} + +void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value) +{ + std::stringstream tmp; + tmp << name << "=\"" << value << '"'; + + source.AddProcessingInstruction("define", tmp.str()); +} + +void cmCPackWIXGenerator::CreateWiXSourceFiles() +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string directoryDefinitionsFilename = + cpackTopLevel + "/directories.wxs"; + + wixSources.push_back(directoryDefinitionsFilename); + + cmWIXSourceWriter directoryDefinitions(directoryDefinitionsFilename); + directoryDefinitions.BeginElement("Fragment"); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "TARGETDIR"); + directoryDefinitions.AddAttribute("Name", "SourceDir"); + + directoryDefinitions.BeginElement("Directory"); + if(GetArchitecture() == "x86") + { + directoryDefinitions.AddAttribute("Id", "ProgramFilesFolder"); + } + else + { + directoryDefinitions.AddAttribute("Id", "ProgramFiles64Folder"); + } + + std::vector<std::string> install_root; + cmSystemTools::SplitPath( + RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY").c_str(), + install_root); + + if(!install_root.empty() && install_root.back().empty()) + install_root.pop_back(); + + for(std::size_t i = 1; i < install_root.size(); ++i) + { + directoryDefinitions.BeginElement("Directory"); + + if(i == install_root.size() - 1) + { + directoryDefinitions.AddAttribute("Id", "INSTALL_ROOT"); + } + else + { + std::stringstream tmp; + tmp << "INSTALL_PREFIX_" << i; + directoryDefinitions.AddAttribute("Id", tmp.str()); + } + + directoryDefinitions.AddAttribute("Name", install_root[i]); + } + + std::size_t directoryCounter = 0; + std::size_t fileCounter = 0; + + std::string fileDefinitionsFilename = + cpackTopLevel + "/files.wxs"; + + wixSources.push_back(fileDefinitionsFilename); + + cmWIXSourceWriter fileDefinitions(fileDefinitionsFilename); + fileDefinitions.BeginElement("Fragment"); + + std::string featureDefinitionsFilename = + cpackTopLevel +"/features.wxs"; + + wixSources.push_back(featureDefinitionsFilename); + + cmWIXSourceWriter featureDefinitions(featureDefinitionsFilename); + featureDefinitions.BeginElement("Fragment"); + + featureDefinitions.BeginElement("Feature"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + featureDefinitions.AddAttribute("Title", Name); + featureDefinitions.AddAttribute("Level", "1"); + featureDefinitions.EndElement(); + + featureDefinitions.BeginElement("FeatureRef"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + + AddDirectoryAndFileDefinitons( + toplevel, "INSTALL_ROOT", + directoryDefinitions, fileDefinitions, featureDefinitions, + directoryCounter, fileCounter); + + featureDefinitions.EndElement(); + featureDefinitions.EndElement(); + fileDefinitions.EndElement(); + + for(std::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(wixTemplate.empty()) + { + throw std::runtime_error( + "Could not find CPack WiX template file WIX.template.in"); + } + + std::string mainSourceFilePath = cpackTopLevel + "/main.wxs"; + + if(!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath .c_str())) + { + std::stringstream tmp; + tmp << "Failed creating '" << + mainSourceFilePath << "'' from template."; + throw std::runtime_error(tmp.str()); + } + + wixSources.push_back(mainSourceFilePath); +} + +void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( + const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter) +{ + cmsys::Directory dir; + dir.Load(topdir.c_str()); + + for(std::size_t i = 0; i < dir.GetNumberOfFiles(); ++i) + { + std::string fileName = dir.GetFile(static_cast<unsigned long>(i)); + + if(fileName == "." || fileName == "..") continue; + + std::string fullPath = topdir + "/" + fileName; + + if(cmSystemTools::FileIsDirectory(fullPath.c_str())) + { + std::stringstream tmp; + tmp << "DIR_ID_" << ++directoryCounter; + std::string subDirectoryId = tmp.str(); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", subDirectoryId); + directoryDefinitions.AddAttribute("Name", fileName); + + AddDirectoryAndFileDefinitons( + fullPath, subDirectoryId, + directoryDefinitions, + fileDefinitions, + featureDefinitions, + directoryCounter, + fileCounter); + + directoryDefinitions.EndElement(); + } + else + { + std::stringstream tmp; + tmp << "_ID_" << ++fileCounter; + std::string idSuffix = tmp.str(); + + std::string componentId = std::string("CMP") + idSuffix; + std::string fileId = std::string("FILE") + idSuffix; + + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", directoryId); + + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", componentId); + fileDefinitions.AddAttribute("Guid", "*"); + + fileDefinitions.BeginElement("File"); + fileDefinitions.AddAttribute("Id", fileId); + fileDefinitions.AddAttribute("Source", fullPath); + fileDefinitions.AddAttribute("KeyPath", "yes"); + + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + + featureDefinitions.BeginElement("ComponentRef"); + featureDefinitions.AddAttribute("Id", componentId); + featureDefinitions.EndElement(); + } + } +} + +std::string cmCPackWIXGenerator::RequireOption(const std::string& name) const +{ + const char* value = GetOption(name.c_str()); + if(value) return value; + + std::stringstream tmp; + tmp << "Required variable " << name << " not set"; + throw std::runtime_error(tmp.str()); +} + +std::string cmCPackWIXGenerator::GenerateGUID() +{ + UUID guid; + UuidCreate(&guid); + + RPC_CSTR tmp = 0; + UuidToStringA(&guid, &tmp); + + std::string result(reinterpret_cast<char*>(tmp)); + RpcStringFree(&tmp); + + return cmSystemTools::UpperCase(result); +} + +std::string cmCPackWIXGenerator::QuotePath(const std::string& path) +{ + return std::string("\"") + path + '"'; +} + +std::string cmCPackWIXGenerator::GetArchitecture() const +{ + std::string void_p_size = RequireOption("CPACK_WIX_SIZEOF_VOID_P"); + if(void_p_size == "8") + { + return "x64"; + } + else + { + return "x86"; + } +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h new file mode 100644 index 0000000..481934e --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -0,0 +1,80 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include "../cmCPackGenerator.h" + +#include <string> +#include <map> + +class cmWIXSourceWriter; + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + +protected: + virtual int InitializeInternal(); + + virtual int PackageFiles(); + + virtual const char* GetOutputExtension() { return ".msi"; } + virtual bool SupportsComponentInstallation() const { return false; } + +private: + void InitializeWiXConfiguration(); + + void PackageFilesImpl(); + + void CreateWiXVariablesIncludeFile(); + + void CopyDefinition( + cmWIXSourceWriter &source, const std::string &name); + + void AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value); + + void CreateWiXSourceFiles(); + + void RunWiXCommand(const std::string& command); + + void RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile); + + void RunLightCommand(const std::string& objectFiles); + + void AddDirectoryAndFileDefinitons(const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter); + + std::string RequireOption(const std::string& name) const; + + static std::string GenerateGUID(); + + static std::string QuotePath(const std::string& path); + + std::string GetArchitecture() const; + + std::vector<std::string> wixSources; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx new file mode 100644 index 0000000..3667e9f --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx @@ -0,0 +1,140 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXSourceWriter.h" + +cmWIXSourceWriter::cmWIXSourceWriter(const std::string& filename, + bool isIncludeFile): + file(filename.c_str()), + state(DEFAULT) +{ + WriteXMLDeclaration(); + + if(isIncludeFile) + { + BeginElement("Include"); + } + else + { + BeginElement("Wix"); + } + + AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi"); +} + +cmWIXSourceWriter::~cmWIXSourceWriter() +{ + while(elements.size()) + { + EndElement(); + } +} + +void cmWIXSourceWriter::BeginElement(const std::string& name) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<" << name; + + elements.push_back(name); + state = BEGIN; +} + +void cmWIXSourceWriter::EndElement() +{ + if(elements.empty()) + { + throw std::runtime_error("can not end WiX element with no open elements"); + } + + if(state == DEFAULT) + { + file << "\n"; + Indent(elements.size()-1); + file << "</" << elements.back() << ">"; + } + else + { + file << "/>"; + } + + elements.pop_back(); + state = DEFAULT; +} + +void cmWIXSourceWriter::AddProcessingInstruction( + const std::string& target, const std::string& content) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<?" << target << " " << content << "?>"; + + state = DEFAULT; +} + +void cmWIXSourceWriter::AddAttribute( + const std::string& key, const std::string& value) +{ + file << " " << key << "=\"" << escapeAttributeValue(value) << '"'; +} + +void cmWIXSourceWriter::WriteXMLDeclaration() +{ + file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; +} + +void cmWIXSourceWriter::Indent(std::size_t count) +{ + for(std::size_t i = 0; i < count; ++i) + { + file << " "; + } +} + +std::string cmWIXSourceWriter::escapeAttributeValue( + const std::string& value) +{ + std::string result; + result.reserve(value.size()); + + char c = 0; + for(std::size_t i = 0 ; i < value.size(); ++i) + { + c = value[i]; + switch(c) + { + case '<': + result += "<"; + break; + case '&': + result +="&"; + break; + case '"': + result += """; + break; + default: + result += c; + } + } + + return result; +} diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h new file mode 100644 index 0000000..b875477 --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -0,0 +1,54 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXSourceWriter_h +#define cmWIXSourceWriter_h + +#include <vector> +#include <string> +#include <fstream> + +/** \class cmWIXSourceWriter + * \brief Helper class to generate XML WiX source files + */ +class cmWIXSourceWriter +{ +public: + cmWIXSourceWriter(const std::string& filename, bool isIncludeFile = false); + ~cmWIXSourceWriter(); + + void BeginElement(const std::string& name); + void EndElement(); + + void AddProcessingInstruction( + const std::string& target, const std::string& content); + + void AddAttribute(const std::string& key, const std::string& value); + +private: + enum State + { + DEFAULT, + BEGIN + }; + + void WriteXMLDeclaration(); + void Indent(std::size_t count); + static std::string escapeAttributeValue(const std::string& value); + + std::ofstream file; + std::vector<std::string> elements; + + State state; +}; + +#endif diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 37ff460..ded0cc9 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,7 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -37,6 +38,9 @@ # include "cmCPackRPMGenerator.h" #endif +#ifdef _WIN32 +# include "WiX/cmCPackWIXGenerator.h" +#endif #include "cmCPackLog.h" @@ -80,6 +84,13 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); } +#ifdef _WIN32 + if (cmCPackWIXGenerator::CanGenerate()) + { + this->RegisterGenerator("WIX", "MSI file format via WiX tools", + cmCPackWIXGenerator::CreateGenerator); + } +#endif if (cmCPackTarBZip2Generator::CanGenerate()) { this->RegisterGenerator("TBZ2", "Tar BZip2 compression", diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e03b926..8bbd8cb 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -692,6 +692,28 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ endif() endif() + # On Windows run the CPackWiXGenerator test + # if the WiX Toolset seems to be available + if(WIN32) + find_program(WIX_LIGHT_EXECUTABLE light + PATHS "${WIX}/bin" + DOC "WiX Toolset light.exe location") + + if(WIX_LIGHT_EXECUTABLE) + add_test(CPackWiXGenerator ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator" + "${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project CPackWiXGenerator + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --test-command ${CMAKE_CMAKE_COMMAND} + "-DCPackWiXGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + "-DCPackCommand=${CMAKE_CPACK_COMMAND}" + -P "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake") + endif() + endif() + if(CTEST_RUN_CPackComponents) set(CPackComponents_EXTRA_OPTIONS) if(APPLE) diff --git a/Tests/CPackWiXGenerator/CMakeLists.txt b/Tests/CPackWiXGenerator/CMakeLists.txt new file mode 100644 index 0000000..f4e42c2 --- /dev/null +++ b/Tests/CPackWiXGenerator/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 2.8) + +project(CPackWiXGenerator) + +add_library(mylib mylib.cpp) + +add_executable(mylibapp mylibapp.cpp) +target_link_libraries(mylibapp mylib) + +install(TARGETS mylib + ARCHIVE + DESTINATION lib + COMPONENT libraries) + +install(TARGETS mylibapp + RUNTIME + DESTINATION bin + COMPONENT applications) + +install(FILES mylib.h + DESTINATION include + COMPONENT headers) + +set(CPACK_GENERATOR "WIX") + +set(CPACK_PACKAGE_NAME "MyLib") +set(CPACK_PACKAGE_VENDOR "CMake.org") +set(CPACK_PACKAGE_CONTACT "somebody@cmake.org") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "MyLib - CPack Component Installation Example") +set(CPACK_PACKAGE_VERSION "1.0.0") +set(CPACK_PACKAGE_VERSION_MAJOR "1") +set(CPACK_PACKAGE_VERSION_MINOR "0") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example") + +include(CPack) + +cpack_add_install_type(Full DISPLAY_NAME "Everything") +cpack_add_install_type(Developer) + +cpack_add_component_group(Runtime) + +cpack_add_component_group(Development + EXPANDED + DESCRIPTION "All of the tools you'll ever need to develop software") + +cpack_add_component(applications + DISPLAY_NAME "MyLib Application" + DESCRIPTION "An extremely useful application that makes use of MyLib" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(documentation + DISPLAY_NAME "MyLib Documentation" + DESCRIPTION "The extensive suite of MyLib Application documentation files" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(libraries + DISPLAY_NAME "Libraries" + DESCRIPTION "Static libraries used to build programs with MyLib" + GROUP Development + INSTALL_TYPES Developer Full) + +cpack_add_component(headers + DISPLAY_NAME "C++ Headers" + DESCRIPTION "C/C++ header files for use with MyLib" + GROUP Development + DEPENDS libraries + INSTALL_TYPES Developer Full) diff --git a/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake new file mode 100644 index 0000000..8c91e3d --- /dev/null +++ b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake @@ -0,0 +1,67 @@ +message(STATUS "=============================================================") +message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") +message(STATUS "") + +if(NOT CPackWiXGenerator_BINARY_DIR) + message(FATAL_ERROR "CPackWiXGenerator_BINARY_DIR not set") +endif() + +message(STATUS "CPackCommand: ${CPackCommand}") + +execute_process(COMMAND "${CPackCommand}" + RESULT_VARIABLE CPack_result + OUTPUT_VARIABLE CPack_output + ERROR_VARIABLE CPack_error + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + +if(CPack_result) + message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}") +else () + message(STATUS "CPack_output=${CPack_output}") +endif() + +set(expected_file_mask "*.msi") +file(GLOB installer_file "${expected_file_mask}") + +message(STATUS "installer_file='${installer_file}'") +message(STATUS "expected_file_mask='${expected_file_mask}'") + +if(NOT installer_file) + message(FATAL_ERROR "installer_file does not exist.") +endif() + +function(run_wix_command command) + file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT) + set(WIX_PROGRAM "${WIX_ROOT}/bin/${command}.exe") + + if(NOT EXISTS "${WIX_PROGRAM}") + message(FATAL_ERROR "Failed to find WiX Tool: ${WIX_PROGRAM}") + endif() + + message(STATUS "Running WiX Tool: ${command} ${ARGN}") + + execute_process(COMMAND "${WIX_PROGRAM}" ${ARGN} + RESULT_VARIABLE WIX_result + OUTPUT_VARIABLE WIX_output + ERROR_VARIABLE WIX_output + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + + message(STATUS "${command} Output: \n${WIX_output}") + + if(WIX_result) + message(FATAL_ERROR "WiX ${command} failed: ${WIX_result}") + endif() +endfunction() + +file(GLOB WXS_SOURCE_FILES + "${CPackWiXGenerator_BINARY_DIR}/_CPack_Packages/*/WIX/*.wxs") + +if(NOT WXS_SOURCE_FILES) + message(FATAL_ERROR "Failed finding WiX source files to validate.") +endif() + +foreach(WXS_SOURCE_FILE IN LISTS WXS_SOURCE_FILES) + run_wix_command(wixcop "${WXS_SOURCE_FILE}") +endforeach() + +run_wix_command(smoke -nologo -wx "${installer_file}") diff --git a/Tests/CPackWiXGenerator/mylib.cpp b/Tests/CPackWiXGenerator/mylib.cpp new file mode 100644 index 0000000..8ddac19 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.cpp @@ -0,0 +1,7 @@ +#include "mylib.h" +#include "stdio.h" + +void mylib_function() +{ + printf("This is mylib"); +} diff --git a/Tests/CPackWiXGenerator/mylib.h b/Tests/CPackWiXGenerator/mylib.h new file mode 100644 index 0000000..5d0a822 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.h @@ -0,0 +1 @@ +void mylib_function(); diff --git a/Tests/CPackWiXGenerator/mylibapp.cpp b/Tests/CPackWiXGenerator/mylibapp.cpp new file mode 100644 index 0000000..a438ac7 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylibapp.cpp @@ -0,0 +1,6 @@ +#include "mylib.h" + +int main() +{ + mylib_function(); +} -- 1.7.9.msysgit.0 0001-CPack-WiX-Generator-2.patch [^] (43,943 bytes) 2012-09-12 10:27 [Show Content] [Hide Content] From 38b9f1cc04bb6e9cd181db4fd897a5db957ed52c Mon Sep 17 00:00:00 2001 From: Nils Gladitz <gladitz@scivis.de> Date: Wed, 12 Sep 2012 16:22:56 +0200 Subject: [PATCH] CPack WiX Generator --- Modules/CPack.cmake | 7 +- Modules/CPackWIX.cmake | 83 ++++ Modules/WIX.template.in | 30 ++ Source/CMakeLists.txt | 8 + Source/CPack/WiX/cmCPackWIXGenerator.cxx | 483 ++++++++++++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.h | 92 ++++ Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx | 137 ++++++ Source/CPack/WiX/cmWIXRichTextFormatWriter.h | 46 ++ Source/CPack/WiX/cmWIXSourceWriter.cxx | 172 +++++++ Source/CPack/WiX/cmWIXSourceWriter.h | 61 +++ Source/CPack/cmCPackGeneratorFactory.cxx | 11 + Tests/CMakeLists.txt | 22 + Tests/CPackWiXGenerator/CMakeLists.txt | 73 +++ Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake | 70 +++ Tests/CPackWiXGenerator/mylib.cpp | 7 + Tests/CPackWiXGenerator/mylib.h | 1 + Tests/CPackWiXGenerator/mylibapp.cpp | 6 + 17 files changed, 1308 insertions(+), 1 deletions(-) create mode 100644 Modules/CPackWIX.cmake create mode 100644 Modules/WIX.template.in create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.cxx create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.h create mode 100644 Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx create mode 100644 Source/CPack/WiX/cmWIXRichTextFormatWriter.h create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.cxx create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.h create mode 100644 Tests/CPackWiXGenerator/CMakeLists.txt create mode 100644 Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake create mode 100644 Tests/CPackWiXGenerator/file with spaces.h create mode 100644 Tests/CPackWiXGenerator/mylib.cpp create mode 100644 Tests/CPackWiXGenerator/mylib.h create mode 100644 Tests/CPackWiXGenerator/mylibapp.cpp diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 6886ed9..42d3c0c 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -438,6 +438,7 @@ if(NOT CPACK_GENERATOR) endif() else() option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) + option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) endif() @@ -453,6 +454,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) endif() @@ -483,7 +485,7 @@ endif() mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11 CPACK_BINARY_STGZ CPACK_BINARY_TGZ CPACK_BINARY_TBZ2 CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ - CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE + CPACK_BINARY_NSIS CPACK_BINARY_WIX CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) @@ -522,6 +524,9 @@ cpack_set_if_not_set(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_ICON_CODE "") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") +# WiX specific variables +cpack_set_if_not_set(CPACK_WIX_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}") + if(DEFINED CPACK_COMPONENTS_ALL) if(CPACK_MONOLITHIC_INSTALL) message("CPack warning: both CPACK_COMPONENTS_ALL and CPACK_MONOLITHIC_INSTALL have been set.\nDefaulting to a monolithic installation.") diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake new file mode 100644 index 0000000..f278953 --- /dev/null +++ b/Modules/CPackWIX.cmake @@ -0,0 +1,83 @@ +##section Variables specific to CPack WiX generator +##end +##module +# - CPack WiX generator specific options +# +# The following variables are specific to the installers built +# on Windows using WiX. +##end +##variable +# CPACK_WIX_UPGRADE_GUID - Upgrade GUID (Product/@UpgradeCode) +# +# Will be automatically generated unless explicitly provided. +# +# It should be explicitly set to a constant generated +# gloabally unique identifier (GUID) to allow your installers +# to replace existing installations that use the same GUID. +# +# You may for example explicitly set this variable in +# your CMakeLists.txt to the value that has been generated per default. +# You should not use GUIDs that you did not generate yourself or which may +# belong to other projects. +# +# A GUID shall have the following fixed length syntax: +# XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX +# (each X represents an uppercase hexadecimal digit) +##end +##variable +# CPACK_WIX_PRODUCT_GUID - Product GUID (Product/@Id) +# +# Will be automatically generated unless explicitly provided. +# +# If explicitly provided this will set the Product Id of your installer. +# +# The installer will abort if it detects a pre-existing installation that uses +# the same GUID. +# +# The GUID shall use the syntax described for CPACK_WIX_UPGRADE_GUID. +##end +##variable +# CPACK_WIX_LICENSE_RTF - RTF License File +# +# If CPACK_RESOURCE_FILE_LICENSE has an .rtf extension +# it is used as-is. +# +# If CPACK_RESOURCE_FILE_LICENSE has an .txt extension +# it is implicitly converted to RTF by the WiX Generator. +# +# With CPACK_WIX_LICENSE_RTF you can override the license file used +# by the WiX Generator in case CPACK_RESOURCE_FILE_LICENSE +# is in an unsupported format or the .txt -> .rtf +# conversion does not work as expected. +##end + +#============================================================================= +# Copyright 2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(NOT CPACK_WIX_ROOT) + file(TO_CMAKE_PATH "$ENV{WIX}" CPACK_WIX_ROOT) +endif() + +find_program(CPACK_WIX_CANDLE_EXECUTABLE candle + PATHS "${CPACK_WIX_ROOT}/bin") + +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}/bin") + +if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX light executable.") +endif() diff --git a/Modules/WIX.template.in b/Modules/WIX.template.in new file mode 100644 index 0000000..ec8fbba --- /dev/null +++ b/Modules/WIX.template.in @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?include "cpack_variables.wxi"?> + +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" + RequiredVersion="3.6.3303.0"> + + <Product Id="$(var.CPACK_WIX_PRODUCT_GUID)" + Name="$(var.CPACK_PACKAGE_NAME)" + Language="1033" + Version="$(var.CPACK_PACKAGE_VERSION)" + Manufacturer="$(var.CPACK_PACKAGE_VENDOR)" + UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)"> + + <Package InstallerVersion="301" Compressed="yes"/> + + <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/> + + <MajorUpgrade + AllowSameVersionUpgrades="yes" + DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit."/> + + <WixVariable Id="WixUILicenseRtf" Value="$(var.CPACK_WIX_LICENSE_RTF)"/> + <Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/> + + <FeatureRef Id="ProductFeature"/> + + <UIRef Id="WixUI_InstallDir" /> + </Product> +</Wix> diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e79689b..9400095 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -497,6 +497,14 @@ if(UNIX) ) endif() +if(WIN32) + set(CPACK_SRCS ${CPACK_SRCS} + CPack/WiX/cmCPackWIXGenerator.cxx + CPack/WiX/cmWIXSourceWriter.cxx + CPack/WiX/cmWIXRichTextFormatWriter.cxx + ) +endif() + if(APPLE) set(CPACK_SRCS ${CPACK_SRCS} CPack/cmCPackBundleGenerator.cxx diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..9a178a2 --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -0,0 +1,483 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include "../cmSystemTools.h" +#include "../cmGeneratedFileStream.h" +#include "../cmCPackLog.h" +#include "../cmCPackComponentGroup.h" + +#include "cmWIXSourceWriter.h" +#include "cmWIXRichTextFormatWriter.h" + +#include <cmsys/SystemTools.hxx> +#include <cmsys/Directory.hxx> + +#include <rpc.h> // for GUID generation + +int cmCPackWIXGenerator::InitializeInternal() +{ + componentPackageMethod = ONE_PACKAGE; + + return this->Superclass::InitializeInternal(); +} + +void cmCPackWIXGenerator::RunWiXCommand(const std::string& command) +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string logFileName = cpackTopLevel + "/wix.log"; + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Running WiX command: " << command << std::endl); + + std::string output; + + int returnValue = 0; + bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output, + &returnValue, 0, cmSystemTools::OUTPUT_NONE); + + std::ofstream logFile(logFileName.c_str(), std::ios::app); + logFile << command << std::endl; + logFile << output; + logFile.close(); + + if(!status || returnValue) + { + std::stringstream tmp; + tmp << "Problem running WiX candle. " + "Please check '" << logFileName << "' for errors."; + + throw std::runtime_error(tmp.str()); + } +} + +void cmCPackWIXGenerator::RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile) +{ + std::stringstream command; + command << QuotePath(RequireOption("CPACK_WIX_CANDLE_EXECUTABLE")); + command << " -nologo"; + command << " -arch " << GetArchitecture(); + command << " -out " << QuotePath(objectFile); + command << " " << QuotePath(sourceFile); + + RunWiXCommand(command.str()); +} + +void cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) +{ + std::stringstream command; + command << QuotePath(RequireOption("CPACK_WIX_LIGHT_EXECUTABLE")); + command << " -nologo"; + command << " -out " << QuotePath(packageFileNames.at(0)); + command << " -ext WixUIExtension"; + command << " " << objectFiles; + + RunWiXCommand(command.str()); +} + +int cmCPackWIXGenerator::PackageFiles() +{ + try + { + PackageFilesImpl(); + } + catch(std::exception& e) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Fatal WiX Generator Error: " << e.what() << std::endl); + + return false; + } + + return true; +} + +void cmCPackWIXGenerator::InitializeWiXConfiguration() +{ + if(!ReadListFile("CPackWIX.cmake")) + { + throw std::runtime_error("Error while executing CPackWIX.cmake"); + } + + if(GetOption("CPACK_WIX_PRODUCT_GUID") == 0) + { + std::string guid = GenerateGUID(); + SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str()); + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . " + << std::endl); + } + + if(GetOption("CPACK_WIX_UPGRADE_GUID") == 0) + { + std::string guid = GenerateGUID(); + SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str()); + + cmCPackLogger(cmCPackLog::LOG_WARNING, + "CPACK_WIX_UPGRADE_GUID implicitly set to " << guid << " . " + "Please refer to the documentation on how and why " + "you might want to set this explicitly." << std::endl); + } + + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + if(GetOption("CPACK_WIX_LICENSE_RTF") == 0) + { + std::string licenseFilename = cpackTopLevel + "/License.rtf"; + SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str()); + + CreateLicenseFile(); + } +} + +void cmCPackWIXGenerator::PackageFilesImpl() +{ + InitializeWiXConfiguration(); + + CreateWiXVariablesIncludeFile(); + CreateWiXSourceFiles(); + + std::stringstream objectFiles; + for(std::size_t i = 0; i < wixSources.size(); ++i) + { + const std::string& sourceFilename = wixSources[i]; + + std::string objectFilename = + cmSystemTools::GetFilenameWithoutExtension(sourceFilename) + ".wixobj"; + + RunCandleCommand(sourceFilename, objectFilename); + + objectFiles << " " << QuotePath(objectFilename); + } + + RunLightCommand(objectFiles.str()); +} + +void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string includeFilename = + cpackTopLevel + "/cpack_variables.wxi"; + + cmWIXSourceWriter includeFile(includeFilename, true); + CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID"); + CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR"); + CopyDefinition(includeFile, "CPACK_PACKAGE_NAME"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION"); + CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF"); +} + +void cmCPackWIXGenerator::CopyDefinition( + cmWIXSourceWriter &source, const std::string &name) +{ + const char* value = GetOption(name.c_str()); + if(value) AddDefinition(source, name, value); +} + +void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value) +{ + std::stringstream tmp; + tmp << name << "=\"" << value << '"'; + + source.AddProcessingInstruction("define", + cmWIXSourceWriter::WindowsCodepageToUtf8(tmp.str())); +} + +void cmCPackWIXGenerator::CreateWiXSourceFiles() +{ + std::string cpackTopLevel = RequireOption("CPACK_TOPLEVEL_DIRECTORY"); + + std::string directoryDefinitionsFilename = + cpackTopLevel + "/directories.wxs"; + + wixSources.push_back(directoryDefinitionsFilename); + + cmWIXSourceWriter directoryDefinitions(directoryDefinitionsFilename); + directoryDefinitions.BeginElement("Fragment"); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "TARGETDIR"); + directoryDefinitions.AddAttribute("Name", "SourceDir"); + + directoryDefinitions.BeginElement("Directory"); + if(GetArchitecture() == "x86") + { + directoryDefinitions.AddAttribute("Id", "ProgramFilesFolder"); + } + else + { + directoryDefinitions.AddAttribute("Id", "ProgramFiles64Folder"); + } + + std::vector<std::string> install_root; + cmSystemTools::SplitPath( + RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY").c_str(), + install_root); + + if(!install_root.empty() && install_root.back().empty()) + install_root.pop_back(); + + for(std::size_t i = 1; i < install_root.size(); ++i) + { + directoryDefinitions.BeginElement("Directory"); + + if(i == install_root.size() - 1) + { + directoryDefinitions.AddAttribute("Id", "INSTALL_ROOT"); + } + else + { + std::stringstream tmp; + tmp << "INSTALL_PREFIX_" << i; + directoryDefinitions.AddAttribute("Id", tmp.str()); + } + + directoryDefinitions.AddAttribute("Name", install_root[i]); + } + + std::size_t directoryCounter = 0; + std::size_t fileCounter = 0; + + std::string fileDefinitionsFilename = + cpackTopLevel + "/files.wxs"; + + wixSources.push_back(fileDefinitionsFilename); + + cmWIXSourceWriter fileDefinitions(fileDefinitionsFilename); + fileDefinitions.BeginElement("Fragment"); + + std::string featureDefinitionsFilename = + cpackTopLevel +"/features.wxs"; + + wixSources.push_back(featureDefinitionsFilename); + + cmWIXSourceWriter featureDefinitions(featureDefinitionsFilename); + featureDefinitions.BeginElement("Fragment"); + + featureDefinitions.BeginElement("Feature"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + featureDefinitions.AddAttribute("Title", Name); + featureDefinitions.AddAttribute("Level", "1"); + featureDefinitions.EndElement(); + + featureDefinitions.BeginElement("FeatureRef"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + + AddDirectoryAndFileDefinitons( + toplevel, "INSTALL_ROOT", + directoryDefinitions, fileDefinitions, featureDefinitions, + directoryCounter, fileCounter); + + featureDefinitions.EndElement(); + featureDefinitions.EndElement(); + fileDefinitions.EndElement(); + + for(std::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(wixTemplate.empty()) + { + throw std::runtime_error( + "Could not find CPack WiX template file WIX.template.in"); + } + + std::string mainSourceFilePath = cpackTopLevel + "/main.wxs"; + + if(!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath .c_str())) + { + std::stringstream tmp; + tmp << "Failed creating '" << + mainSourceFilePath << "'' from template."; + throw std::runtime_error(tmp.str()); + } + + wixSources.push_back(mainSourceFilePath); +} + +void cmCPackWIXGenerator::CreateLicenseFile() +{ + std::string licenseSourceFilename = + RequireOption("CPACK_RESOURCE_FILE_LICENSE"); + + std::string licenseDestinationFilename = + RequireOption("CPACK_WIX_LICENSE_RTF"); + + std::string extension = GetRightmostExtension(licenseSourceFilename); + + if(extension == ".rtf") + { + cmSystemTools::CopyAFile( + licenseSourceFilename.c_str(), + licenseDestinationFilename.c_str()); + } + else if(extension == ".txt") + { + cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename); + + std::ifstream licenseSource(licenseSourceFilename.c_str()); + + std::string line; + while(std::getline(licenseSource, line)) + { + rtfWriter.AddText(line); + rtfWriter.AddText("\n"); + } + } + else + { + std::stringstream tmp; + tmp << "unsupported WiX License file extension '" << extension << "'"; + throw std::runtime_error(tmp.str()); + } +} + +void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( + const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter) +{ + cmsys::Directory dir; + dir.Load(topdir.c_str()); + + for(std::size_t i = 0; i < dir.GetNumberOfFiles(); ++i) + { + std::string fileName = dir.GetFile(static_cast<unsigned long>(i)); + + if(fileName == "." || fileName == "..") continue; + + std::string fullPath = topdir + "/" + fileName; + + if(cmSystemTools::FileIsDirectory(fullPath.c_str())) + { + std::stringstream tmp; + tmp << "DIR_ID_" << ++directoryCounter; + std::string subDirectoryId = tmp.str(); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", subDirectoryId); + directoryDefinitions.AddAttribute("Name", fileName); + + AddDirectoryAndFileDefinitons( + fullPath, subDirectoryId, + directoryDefinitions, + fileDefinitions, + featureDefinitions, + directoryCounter, + fileCounter); + + directoryDefinitions.EndElement(); + } + else + { + std::stringstream tmp; + tmp << "_ID_" << ++fileCounter; + std::string idSuffix = tmp.str(); + + std::string componentId = std::string("CMP") + idSuffix; + std::string fileId = std::string("FILE") + idSuffix; + + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", directoryId); + + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", componentId); + fileDefinitions.AddAttribute("Guid", "*"); + + fileDefinitions.BeginElement("File"); + fileDefinitions.AddAttribute("Id", fileId); + fileDefinitions.AddAttribute("Source", fullPath); + fileDefinitions.AddAttribute("KeyPath", "yes"); + + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + + featureDefinitions.BeginElement("ComponentRef"); + featureDefinitions.AddAttribute("Id", componentId); + featureDefinitions.EndElement(); + } + } +} + +std::string cmCPackWIXGenerator::RequireOption(const std::string& name) const +{ + const char* value = GetOption(name.c_str()); + if(value) return value; + + std::stringstream tmp; + tmp << "Required variable " << name << " not set"; + throw std::runtime_error(tmp.str()); +} + +std::string cmCPackWIXGenerator::GetArchitecture() const +{ + std::string void_p_size = RequireOption("CPACK_WIX_SIZEOF_VOID_P"); + if(void_p_size == "8") + { + return "x64"; + } + else + { + return "x86"; + } +} + +std::string cmCPackWIXGenerator::GenerateGUID() +{ + UUID guid; + UuidCreate(&guid); + + RPC_CSTR tmp = 0; + UuidToStringA(&guid, &tmp); + + std::string result(reinterpret_cast<char*>(tmp)); + RpcStringFree(&tmp); + + return cmSystemTools::UpperCase(result); +} + +std::string cmCPackWIXGenerator::QuotePath(const std::string& path) +{ + return std::string("\"") + path + '"'; +} + +std::string cmCPackWIXGenerator::GetRightmostExtension( + const std::string& filename) +{ + std::string extension; + + std::string::size_type i = filename.rfind("."); + if(i != std::string::npos) + { + extension = filename.substr(i); + } + + return cmSystemTools::LowerCase(extension); +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h new file mode 100644 index 0000000..1103f6c --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -0,0 +1,92 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include "../cmCPackGenerator.h" + +#include <string> +#include <map> + +class cmWIXSourceWriter; + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + +protected: + virtual int InitializeInternal(); + + virtual int PackageFiles(); + + virtual const char* GetOutputExtension() { return ".msi"; } + + virtual enum CPackSetDestdirSupport SupportsSetDestdir() const + { + return SETDESTDIR_UNSUPPORTED; + } + + virtual bool SupportsAbsoluteDestination() const { return false; } + + virtual bool SupportsComponentInstallation() const { return false; } + +private: + void InitializeWiXConfiguration(); + + void PackageFilesImpl(); + + void CreateWiXVariablesIncludeFile(); + + void CopyDefinition( + cmWIXSourceWriter &source, const std::string &name); + + void AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value); + + void CreateWiXSourceFiles(); + + void CreateLicenseFile(); + + void RunWiXCommand(const std::string& command); + + void RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile); + + void RunLightCommand(const std::string& objectFiles); + + void AddDirectoryAndFileDefinitons(const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter); + + std::string RequireOption(const std::string& name) const; + + std::string GetArchitecture() const; + + static std::string GenerateGUID(); + + static std::string QuotePath(const std::string& path); + + static std::string GetRightmostExtension(const std::string& filename); + + std::vector<std::string> wixSources; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx new file mode 100644 index 0000000..638ab19 --- /dev/null +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx @@ -0,0 +1,137 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXRichTextFormatWriter.h" + +#include "../../cmVersion.h" + +cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter( + const std::string& filename): + file(filename.c_str(), std::ios::binary) +{ + StartGroup(); + WriteHeader(); + WriteDocumentPrefix(); +} + +cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter() +{ + EndGroup(); + + /* I haven't seen this in the RTF spec but + * wordpad terminates its RTF like this */ + file << "\r\n"; + file.put(0); +} + +void cmWIXRichTextFormatWriter::AddText(const std::string& text) +{ + typedef unsigned char rtf_byte_t; + + for(std::size_t i = 0; i < text.size(); ++i) + { + rtf_byte_t c = rtf_byte_t(text[i]); + + switch(c) + { + case '\\': + file << "\\\\"; + break; + case '{': + file << "\\{"; + break; + case '}': + file << "\\}"; + break; + case '\n': + file << "\\par\r\n"; + break; + case '\r': + continue; + default: + { + if(c <= 0x7F) + { + file << c; + } + else + { + file << "[NON-ASCII-" << int(c) << "]"; + } + } + break; + } + } +} + +void cmWIXRichTextFormatWriter::WriteHeader() +{ + ControlWord("rtf1"); + ControlWord("ansi"); + ControlWord("ansicpg1252"); + ControlWord("deff0"); + ControlWord("deflang1031"); + + WriteFontTable(); + WriteGenerator(); +} + +void cmWIXRichTextFormatWriter::WriteFontTable() +{ + StartGroup(); + ControlWord("fonttbl"); + + StartGroup(); + ControlWord("f0"); + ControlWord("fswiss"); + ControlWord("fcharset0 Arial;"); + EndGroup(); + + EndGroup(); +} + +void cmWIXRichTextFormatWriter::WriteGenerator() +{ + StartGroup(); + NewControlWord("generator"); + file << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");"; + EndGroup(); +} + +void cmWIXRichTextFormatWriter::WriteDocumentPrefix() +{ + ControlWord("viewkind4"); + ControlWord("uc1"); + ControlWord("pard"); + ControlWord("f0"); + ControlWord("fs20"); +} + +void cmWIXRichTextFormatWriter::ControlWord(const std::string& keyword) +{ + file << "\\" << keyword; +} + +void cmWIXRichTextFormatWriter::NewControlWord(const std::string& keyword) +{ + file << "\\*\\" << keyword; +} + +void cmWIXRichTextFormatWriter::StartGroup() +{ + file.put('{'); +} + +void cmWIXRichTextFormatWriter::EndGroup() +{ + file.put('}'); +} diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h new file mode 100644 index 0000000..10b67c3 --- /dev/null +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXRichTextFormatWriter_h +#define cmWIXRichTextFormatWriter_h + +#include <fstream> + +/** \class cmWIXRichtTextFormatWriter + * \brief Helper class to generate Rich Text Format (RTF) documents + * from plain text (e.g. for license and welcome text) + */ +class cmWIXRichTextFormatWriter +{ +public: + cmWIXRichTextFormatWriter(const std::string& filename); + ~cmWIXRichTextFormatWriter(); + + void AddText(const std::string& text); + +private: + void WriteHeader(); + void WriteFontTable(); + void WriteGenerator(); + + void WriteDocumentPrefix(); + + void ControlWord(const std::string& keyword); + void NewControlWord(const std::string& keyword); + + void StartGroup(); + void EndGroup(); + + std::ofstream file; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx new file mode 100644 index 0000000..a2ab822 --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx @@ -0,0 +1,172 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXSourceWriter.h" + +#include <windows.h> + +cmWIXSourceWriter::cmWIXSourceWriter(const std::string& filename, + bool isIncludeFile): + file(filename.c_str()), + state(DEFAULT) +{ + WriteXMLDeclaration(); + + if(isIncludeFile) + { + BeginElement("Include"); + } + else + { + BeginElement("Wix"); + } + + AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi"); +} + +cmWIXSourceWriter::~cmWIXSourceWriter() +{ + while(elements.size()) + { + EndElement(); + } +} + +void cmWIXSourceWriter::BeginElement(const std::string& name) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<" << name; + + elements.push_back(name); + state = BEGIN; +} + +void cmWIXSourceWriter::EndElement() +{ + if(elements.empty()) + { + throw std::runtime_error("can not end WiX element with no open elements"); + } + + if(state == DEFAULT) + { + file << "\n"; + Indent(elements.size()-1); + file << "</" << elements.back() << ">"; + } + else + { + file << "/>"; + } + + elements.pop_back(); + state = DEFAULT; +} + +void cmWIXSourceWriter::AddProcessingInstruction( + const std::string& target, const std::string& content) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<?" << target << " " << content << "?>"; + + state = DEFAULT; +} + +void cmWIXSourceWriter::AddAttribute( + const std::string& key, const std::string& value) +{ + std::string utf8 = WindowsCodepageToUtf8(value); + + file << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"'; +} + +std::string cmWIXSourceWriter::WindowsCodepageToUtf8(const std::string& value) +{ + if(value.empty()) return std::string(); + + int characterCount = MultiByteToWideChar( + CP_ACP, 0, value.c_str(), value.size(), 0, 0); + + if(characterCount == 0) return std::string(); + + std::vector<wchar_t> utf16(characterCount); + + MultiByteToWideChar( + CP_ACP, 0, value.c_str(), value.size(), &utf16[0], utf16.size()); + + int utf8ByteCount = + WideCharToMultiByte(CP_UTF8, 0, &utf16[0], utf16.size(), 0, 0, 0, 0); + + if(utf8ByteCount == 0) return std::string(); + + std::vector<char> utf8(utf8ByteCount); + + WideCharToMultiByte(CP_UTF8, 0, &utf16[0], utf16.size(), + &utf8[0], utf8.size(), 0, 0); + + return std::string(&utf8[0], utf8.size()); +} + + +void cmWIXSourceWriter::WriteXMLDeclaration() +{ + file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; +} + +void cmWIXSourceWriter::Indent(std::size_t count) +{ + for(std::size_t i = 0; i < count; ++i) + { + file << " "; + } +} + +std::string cmWIXSourceWriter::EscapeAttributeValue( + const std::string& value) +{ + std::string result; + result.reserve(value.size()); + + char c = 0; + for(std::size_t i = 0 ; i < value.size(); ++i) + { + c = value[i]; + switch(c) + { + case '<': + result += "<"; + break; + case '&': + result +="&"; + break; + case '"': + result += """; + break; + default: + result += c; + } + } + + return result; +} diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h new file mode 100644 index 0000000..b9c9d8b --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -0,0 +1,61 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXSourceWriter_h +#define cmWIXSourceWriter_h + +#include <vector> +#include <string> +#include <fstream> + +/** \class cmWIXSourceWriter + * \brief Helper class to generate XML WiX source files + */ +class cmWIXSourceWriter +{ +public: + cmWIXSourceWriter(const std::string& filename, bool isIncludeFile = false); + ~cmWIXSourceWriter(); + + void BeginElement(const std::string& name); + + void EndElement(); + + void AddProcessingInstruction( + const std::string& target, const std::string& content); + + void AddAttribute( + const std::string& key, const std::string& value); + + static std::string WindowsCodepageToUtf8(const std::string& value); + +private: + enum State + { + DEFAULT, + BEGIN + }; + + void WriteXMLDeclaration(); + + void Indent(std::size_t count); + + static std::string EscapeAttributeValue(const std::string& value); + + std::ofstream file; + + std::vector<std::string> elements; + + State state; +}; + +#endif diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 37ff460..ded0cc9 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,7 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -37,6 +38,9 @@ # include "cmCPackRPMGenerator.h" #endif +#ifdef _WIN32 +# include "WiX/cmCPackWIXGenerator.h" +#endif #include "cmCPackLog.h" @@ -80,6 +84,13 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); } +#ifdef _WIN32 + if (cmCPackWIXGenerator::CanGenerate()) + { + this->RegisterGenerator("WIX", "MSI file format via WiX tools", + cmCPackWIXGenerator::CreateGenerator); + } +#endif if (cmCPackTarBZip2Generator::CanGenerate()) { this->RegisterGenerator("TBZ2", "Tar BZip2 compression", diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e03b926..8bbd8cb 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -692,6 +692,28 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ endif() endif() + # On Windows run the CPackWiXGenerator test + # if the WiX Toolset seems to be available + if(WIN32) + find_program(WIX_LIGHT_EXECUTABLE light + PATHS "${WIX}/bin" + DOC "WiX Toolset light.exe location") + + if(WIX_LIGHT_EXECUTABLE) + add_test(CPackWiXGenerator ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator" + "${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project CPackWiXGenerator + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --test-command ${CMAKE_CMAKE_COMMAND} + "-DCPackWiXGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + "-DCPackCommand=${CMAKE_CPACK_COMMAND}" + -P "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake") + endif() + endif() + if(CTEST_RUN_CPackComponents) set(CPackComponents_EXTRA_OPTIONS) if(APPLE) diff --git a/Tests/CPackWiXGenerator/CMakeLists.txt b/Tests/CPackWiXGenerator/CMakeLists.txt new file mode 100644 index 0000000..ce02f11 --- /dev/null +++ b/Tests/CPackWiXGenerator/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 2.8) + +project(CPackWiXGenerator) + +add_library(mylib mylib.cpp) + +add_executable(mylibapp mylibapp.cpp) +target_link_libraries(mylibapp mylib) + +install(TARGETS mylib + ARCHIVE + DESTINATION lib + COMPONENT libraries) + +install(TARGETS mylibapp + RUNTIME + DESTINATION bin + COMPONENT applications) + +install(FILES mylib.h "file with spaces.h" + DESTINATION include + COMPONENT headers) + +set(CPACK_GENERATOR "WIX") + +set(CPACK_PACKAGE_NAME "MyLib") +set(CPACK_PACKAGE_VENDOR "CMake.org") +set(CPACK_PACKAGE_CONTACT "somebody@cmake.org") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "MyLib - CPack Component Installation Example") + +set(CPACK_PACKAGE_VERSION_MAJOR "1") +set(CPACK_PACKAGE_VERSION_MINOR "0") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example") + +set(CPACK_WIX_UPGRADE_GUID "BF20CE5E-7F7C-401D-8F7C-AB45E8D170E6") + +include(CPack) + +cpack_add_install_type(Full DISPLAY_NAME "Everything") +cpack_add_install_type(Developer) + +cpack_add_component_group(Runtime) + +cpack_add_component_group(Development + EXPANDED + DESCRIPTION "All of the tools you'll ever need to develop software") + +cpack_add_component(applications + DISPLAY_NAME "MyLib Application" + DESCRIPTION "An extremely useful application that makes use of MyLib" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(documentation + DISPLAY_NAME "MyLib Documentation" + DESCRIPTION "The extensive suite of MyLib Application documentation files" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(libraries + DISPLAY_NAME "Libraries" + DESCRIPTION "Static libraries used to build programs with MyLib" + GROUP Development + INSTALL_TYPES Developer Full) + +cpack_add_component(headers + DISPLAY_NAME "C++ Headers" + DESCRIPTION "C/C++ header files for use with MyLib" + GROUP Development + DEPENDS libraries + INSTALL_TYPES Developer Full) diff --git a/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake new file mode 100644 index 0000000..e6c8047 --- /dev/null +++ b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake @@ -0,0 +1,70 @@ +message(STATUS "=============================================================") +message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") +message(STATUS "") + +if(NOT CPackWiXGenerator_BINARY_DIR) + message(FATAL_ERROR "CPackWiXGenerator_BINARY_DIR not set") +endif() + +message(STATUS "CPackCommand: ${CPackCommand}") + +execute_process(COMMAND "${CPackCommand}" + RESULT_VARIABLE CPack_result + OUTPUT_VARIABLE CPack_output + ERROR_VARIABLE CPack_error + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + +if(CPack_result) + message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}") +else () + message(STATUS "CPack_output=${CPack_output}") +endif() + +set(expected_file_mask "*.msi") +file(GLOB installer_file "${expected_file_mask}") + +message(STATUS "installer_file='${installer_file}'") +message(STATUS "expected_file_mask='${expected_file_mask}'") + +if(NOT installer_file) + message(FATAL_ERROR "installer_file does not exist.") +endif() + +function(run_wix_command command) + file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT) + set(WIX_PROGRAM "${WIX_ROOT}/bin/${command}.exe") + + if(NOT EXISTS "${WIX_PROGRAM}") + message(FATAL_ERROR "Failed to find WiX Tool: ${WIX_PROGRAM}") + endif() + + message(STATUS "Running WiX Tool: ${command} ${ARGN}") + + execute_process(COMMAND "${WIX_PROGRAM}" ${ARGN} + RESULT_VARIABLE WIX_result + OUTPUT_VARIABLE WIX_output + ERROR_VARIABLE WIX_output + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + + message(STATUS "${command} Output: \n${WIX_output}") + + if(WIX_result) + message(FATAL_ERROR "WiX ${command} failed: ${WIX_result}") + endif() +endfunction() + +file(GLOB WXS_SOURCE_FILES + "${CPackWiXGenerator_BINARY_DIR}/_CPack_Packages/*/WIX/*.wxs") + +if(NOT WXS_SOURCE_FILES) + message(FATAL_ERROR "Failed finding WiX source files to validate.") +endif() + +foreach(WXS_SOURCE_FILE IN LISTS WXS_SOURCE_FILES) + run_wix_command(wixcop "${WXS_SOURCE_FILE}") +endforeach() + +# error SMOK1076 : ICE61: This product should remove only older +# versions of itself. The Maximum version is not less +# than the current product. (1.0.0 1.0.0) +run_wix_command(smoke -nologo -wx -sw1076 "${installer_file}") diff --git a/Tests/CPackWiXGenerator/file with spaces.h b/Tests/CPackWiXGenerator/file with spaces.h new file mode 100644 index 0000000..e69de29 diff --git a/Tests/CPackWiXGenerator/mylib.cpp b/Tests/CPackWiXGenerator/mylib.cpp new file mode 100644 index 0000000..8ddac19 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.cpp @@ -0,0 +1,7 @@ +#include "mylib.h" +#include "stdio.h" + +void mylib_function() +{ + printf("This is mylib"); +} diff --git a/Tests/CPackWiXGenerator/mylib.h b/Tests/CPackWiXGenerator/mylib.h new file mode 100644 index 0000000..5d0a822 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.h @@ -0,0 +1 @@ +void mylib_function(); diff --git a/Tests/CPackWiXGenerator/mylibapp.cpp b/Tests/CPackWiXGenerator/mylibapp.cpp new file mode 100644 index 0000000..a438ac7 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylibapp.cpp @@ -0,0 +1,6 @@ +#include "mylib.h" + +int main() +{ + mylib_function(); +} -- 1.7.9.msysgit.0 0001-CPack-WiX-Generator-3.patch [^] (45,927 bytes) 2012-10-03 10:11 [Show Content] [Hide Content] From ddb46e816568335044f5768654cf6647688fbf79 Mon Sep 17 00:00:00 2001 From: Nils Gladitz <gladitz@scivis.de> Date: Wed, 3 Oct 2012 16:08:49 +0200 Subject: [PATCH] CPack WiX Generator --- CMakeCPackOptions.cmake.in | 7 + Modules/CPack.cmake | 7 +- Modules/CPackWIX.cmake | 83 ++++ Modules/WIX.template.in | 31 ++ Source/CMakeLists.txt | 8 + Source/CPack/WiX/cmCPackWIXGenerator.cxx | 520 ++++++++++++++++++++ Source/CPack/WiX/cmCPackWIXGenerator.h | 92 ++++ Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx | 137 +++++ Source/CPack/WiX/cmWIXRichTextFormatWriter.h | 46 ++ Source/CPack/WiX/cmWIXSourceWriter.cxx | 178 +++++++ Source/CPack/WiX/cmWIXSourceWriter.h | 67 +++ Source/CPack/cmCPackGeneratorFactory.cxx | 11 + Tests/CMakeLists.txt | 24 + Tests/CPackWiXGenerator/CMakeLists.txt | 73 +++ Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake | 70 +++ Tests/CPackWiXGenerator/mylib.cpp | 7 + Tests/CPackWiXGenerator/mylib.h | 1 + Tests/CPackWiXGenerator/mylibapp.cpp | 6 + 18 files changed, 1367 insertions(+), 1 deletions(-) create mode 100644 Modules/CPackWIX.cmake create mode 100644 Modules/WIX.template.in create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.cxx create mode 100644 Source/CPack/WiX/cmCPackWIXGenerator.h create mode 100644 Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx create mode 100644 Source/CPack/WiX/cmWIXRichTextFormatWriter.h create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.cxx create mode 100644 Source/CPack/WiX/cmWIXSourceWriter.h create mode 100644 Tests/CPackWiXGenerator/CMakeLists.txt create mode 100644 Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake create mode 100644 Tests/CPackWiXGenerator/file with spaces.h create mode 100644 Tests/CPackWiXGenerator/mylib.cpp create mode 100644 Tests/CPackWiXGenerator/mylib.h create mode 100644 Tests/CPackWiXGenerator/mylibapp.cpp diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in index 3a72eaa..e21d7f8 100644 --- a/CMakeCPackOptions.cmake.in +++ b/CMakeCPackOptions.cmake.in @@ -51,3 +51,10 @@ if("${CPACK_GENERATOR}" STREQUAL "PackageMaker") set(CPACK_PACKAGE_DEFAULT_LOCATION "/usr") endif() endif() + +if("${CPACK_GENERATOR}" STREQUAL "WIX") + # WIX installers require at most a 4 component version number, where + # each component is an integer between 0 and 65534 inclusive + set(CPACK_PACKAGE_VERSION + "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@.@CMake_VERSION_PATCH@") +endif() diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 6886ed9..42d3c0c 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -438,6 +438,7 @@ if(NOT CPACK_GENERATOR) endif() else() option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON) + option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF) option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF) endif() @@ -453,6 +454,7 @@ if(NOT CPACK_GENERATOR) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TGZ TGZ) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TBZ2 TBZ2) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_TZ TZ) + cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_WIX WIX) cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_ZIP ZIP) endif() @@ -483,7 +485,7 @@ endif() mark_as_advanced(CPACK_BINARY_CYGWIN CPACK_BINARY_PACKAGEMAKER CPACK_BINARY_OSXX11 CPACK_BINARY_STGZ CPACK_BINARY_TGZ CPACK_BINARY_TBZ2 CPACK_BINARY_DEB CPACK_BINARY_RPM CPACK_BINARY_TZ - CPACK_BINARY_NSIS CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE + CPACK_BINARY_NSIS CPACK_BINARY_WIX CPACK_BINARY_ZIP CPACK_BINARY_BUNDLE CPACK_SOURCE_CYGWIN CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TZ CPACK_SOURCE_ZIP CPACK_BINARY_DRAGNDROP) @@ -522,6 +524,9 @@ cpack_set_if_not_set(CPACK_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_ICON_CODE "") cpack_set_if_not_set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE "") +# WiX specific variables +cpack_set_if_not_set(CPACK_WIX_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}") + if(DEFINED CPACK_COMPONENTS_ALL) if(CPACK_MONOLITHIC_INSTALL) message("CPack warning: both CPACK_COMPONENTS_ALL and CPACK_MONOLITHIC_INSTALL have been set.\nDefaulting to a monolithic installation.") diff --git a/Modules/CPackWIX.cmake b/Modules/CPackWIX.cmake new file mode 100644 index 0000000..f278953 --- /dev/null +++ b/Modules/CPackWIX.cmake @@ -0,0 +1,83 @@ +##section Variables specific to CPack WiX generator +##end +##module +# - CPack WiX generator specific options +# +# The following variables are specific to the installers built +# on Windows using WiX. +##end +##variable +# CPACK_WIX_UPGRADE_GUID - Upgrade GUID (Product/@UpgradeCode) +# +# Will be automatically generated unless explicitly provided. +# +# It should be explicitly set to a constant generated +# gloabally unique identifier (GUID) to allow your installers +# to replace existing installations that use the same GUID. +# +# You may for example explicitly set this variable in +# your CMakeLists.txt to the value that has been generated per default. +# You should not use GUIDs that you did not generate yourself or which may +# belong to other projects. +# +# A GUID shall have the following fixed length syntax: +# XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX +# (each X represents an uppercase hexadecimal digit) +##end +##variable +# CPACK_WIX_PRODUCT_GUID - Product GUID (Product/@Id) +# +# Will be automatically generated unless explicitly provided. +# +# If explicitly provided this will set the Product Id of your installer. +# +# The installer will abort if it detects a pre-existing installation that uses +# the same GUID. +# +# The GUID shall use the syntax described for CPACK_WIX_UPGRADE_GUID. +##end +##variable +# CPACK_WIX_LICENSE_RTF - RTF License File +# +# If CPACK_RESOURCE_FILE_LICENSE has an .rtf extension +# it is used as-is. +# +# If CPACK_RESOURCE_FILE_LICENSE has an .txt extension +# it is implicitly converted to RTF by the WiX Generator. +# +# With CPACK_WIX_LICENSE_RTF you can override the license file used +# by the WiX Generator in case CPACK_RESOURCE_FILE_LICENSE +# is in an unsupported format or the .txt -> .rtf +# conversion does not work as expected. +##end + +#============================================================================= +# Copyright 2012 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +if(NOT CPACK_WIX_ROOT) + file(TO_CMAKE_PATH "$ENV{WIX}" CPACK_WIX_ROOT) +endif() + +find_program(CPACK_WIX_CANDLE_EXECUTABLE candle + PATHS "${CPACK_WIX_ROOT}/bin") + +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}/bin") + +if(NOT CPACK_WIX_LIGHT_EXECUTABLE) + message(FATAL_ERROR "Could not find the WiX light executable.") +endif() diff --git a/Modules/WIX.template.in b/Modules/WIX.template.in new file mode 100644 index 0000000..63fad7c --- /dev/null +++ b/Modules/WIX.template.in @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?include "cpack_variables.wxi"?> + +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" + RequiredVersion="3.6.3303.0"> + + <Product Id="$(var.CPACK_WIX_PRODUCT_GUID)" + Name="$(var.CPACK_PACKAGE_NAME)" + Language="1033" + Version="$(var.CPACK_PACKAGE_VERSION)" + Manufacturer="$(var.CPACK_PACKAGE_VENDOR)" + UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)"> + + <Package InstallerVersion="301" Compressed="yes"/> + + <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/> + + <MajorUpgrade + Schedule="afterInstallInitialize" + AllowSameVersionUpgrades="yes" + DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit."/> + + <WixVariable Id="WixUILicenseRtf" Value="$(var.CPACK_WIX_LICENSE_RTF)"/> + <Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/> + + <FeatureRef Id="ProductFeature"/> + + <UIRef Id="WixUI_InstallDir" /> + </Product> +</Wix> diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 8bf6c40..7388922 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -510,6 +510,14 @@ if(UNIX) ) endif() +if(WIN32) + set(CPACK_SRCS ${CPACK_SRCS} + CPack/WiX/cmCPackWIXGenerator.cxx + CPack/WiX/cmWIXSourceWriter.cxx + CPack/WiX/cmWIXRichTextFormatWriter.cxx + ) +endif() + if(APPLE) set(CPACK_SRCS ${CPACK_SRCS} CPack/cmCPackBundleGenerator.cxx diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.cxx b/Source/CPack/WiX/cmCPackWIXGenerator.cxx new file mode 100644 index 0000000..c5f4a3d --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.cxx @@ -0,0 +1,520 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmCPackWIXGenerator.h" + +#include <cmSystemTools.h> +#include <cmGeneratedFileStream.h> +#include <CPack/cmCPackLog.h> +#include <CPack/cmCPackComponentGroup.h> + +#include "cmWIXSourceWriter.h" +#include "cmWIXRichTextFormatWriter.h" + +#include <cmsys/SystemTools.hxx> +#include <cmsys/Directory.hxx> + +#include <rpc.h> // for GUID generation + +int cmCPackWIXGenerator::InitializeInternal() +{ + componentPackageMethod = ONE_PACKAGE; + + return this->Superclass::InitializeInternal(); +} + +bool cmCPackWIXGenerator::RunWiXCommand(const std::string& command) +{ + std::string cpackTopLevel; + if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) return false; + + std::string logFileName = cpackTopLevel + "/wix.log"; + + cmCPackLogger(cmCPackLog::LOG_DEBUG, + "Running WiX command: " << command << std::endl); + + std::string output; + + int returnValue = 0; + bool status = cmSystemTools::RunSingleCommand(command.c_str(), &output, + &returnValue, 0, cmSystemTools::OUTPUT_NONE); + + std::ofstream logFile(logFileName.c_str(), std::ios::app); + logFile << command << std::endl; + logFile << output; + logFile.close(); + + if(!status || returnValue) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Problem running WiX candle. " + "Please check '" << logFileName << "' for errors." << std::endl); + + return false; + } + + return true; +} + +bool cmCPackWIXGenerator::RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile) +{ + std::string executable; + if(!RequireOption("CPACK_WIX_CANDLE_EXECUTABLE", executable)) return false; + + std::stringstream command; + command << QuotePath(executable); + command << " -nologo"; + command << " -arch " << GetArchitecture(); + command << " -out " << QuotePath(objectFile); + command << " " << QuotePath(sourceFile); + + return RunWiXCommand(command.str()); +} + +bool cmCPackWIXGenerator::RunLightCommand(const std::string& objectFiles) +{ + std::string executable; + if(!RequireOption("CPACK_WIX_LIGHT_EXECUTABLE", executable)) return false; + + std::stringstream command; + command << QuotePath(executable); + command << " -nologo"; + command << " -out " << QuotePath(packageFileNames.at(0)); + command << " -ext WixUIExtension"; + command << " " << objectFiles; + + return RunWiXCommand(command.str()); +} + +int cmCPackWIXGenerator::PackageFiles() +{ + if(!PackageFilesImpl() || cmSystemTools::GetErrorOccuredFlag()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Fatal WiX Generator Error" << std::endl); + return false; + } + + return true; +} + +bool cmCPackWIXGenerator::InitializeWiXConfiguration() +{ + if(!ReadListFile("CPackWIX.cmake")) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Error while executing CPackWIX.cmake" << std::endl); + return false; + } + + if(GetOption("CPACK_WIX_PRODUCT_GUID") == 0) + { + std::string guid = GenerateGUID(); + SetOption("CPACK_WIX_PRODUCT_GUID", guid.c_str()); + + cmCPackLogger(cmCPackLog::LOG_VERBOSE, + "CPACK_WIX_PRODUCT_GUID implicitly set to " << guid << " . " + << std::endl); + } + + if(GetOption("CPACK_WIX_UPGRADE_GUID") == 0) + { + std::string guid = GenerateGUID(); + SetOption("CPACK_WIX_UPGRADE_GUID", guid.c_str()); + + cmCPackLogger(cmCPackLog::LOG_WARNING, + "CPACK_WIX_UPGRADE_GUID implicitly set to " << guid << " . " + "Please refer to the documentation on how and why " + "you might want to set this explicitly." << std::endl); + } + + std::string cpackTopLevel; + if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) return false; + + if(GetOption("CPACK_WIX_LICENSE_RTF") == 0) + { + std::string licenseFilename = cpackTopLevel + "/License.rtf"; + SetOption("CPACK_WIX_LICENSE_RTF", licenseFilename.c_str()); + + if(!CreateLicenseFile()) return false; + } + + return true; +} + +bool cmCPackWIXGenerator::PackageFilesImpl() +{ + if(!InitializeWiXConfiguration()) return false; + + if(!CreateWiXVariablesIncludeFile()) return false; + if(!CreateWiXSourceFiles()) return false; + + std::stringstream objectFiles; + for(std::size_t i = 0; i < wixSources.size(); ++i) + { + const std::string& sourceFilename = wixSources[i]; + + std::string objectFilename = + cmSystemTools::GetFilenameWithoutExtension(sourceFilename) + ".wixobj"; + + if(!RunCandleCommand(sourceFilename, objectFilename)) + return false; + + objectFiles << " " << QuotePath(objectFilename); + } + + return RunLightCommand(objectFiles.str()); +} + +bool cmCPackWIXGenerator::CreateWiXVariablesIncludeFile() +{ + std::string cpackTopLevel; + if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) return false; + + std::string includeFilename = + cpackTopLevel + "/cpack_variables.wxi"; + + cmWIXSourceWriter includeFile(Logger, includeFilename, true); + CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_GUID"); + CopyDefinition(includeFile, "CPACK_WIX_UPGRADE_GUID"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR"); + CopyDefinition(includeFile, "CPACK_PACKAGE_NAME"); + CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION"); + CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF"); + + return true; +} + +void cmCPackWIXGenerator::CopyDefinition( + cmWIXSourceWriter &source, const std::string &name) +{ + const char* value = GetOption(name.c_str()); + if(value) AddDefinition(source, name, value); +} + +void cmCPackWIXGenerator::AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value) +{ + std::stringstream tmp; + tmp << name << "=\"" << value << '"'; + + source.AddProcessingInstruction("define", + cmWIXSourceWriter::WindowsCodepageToUtf8(tmp.str())); +} + +bool cmCPackWIXGenerator::CreateWiXSourceFiles() +{ + std::string cpackTopLevel; + if(!RequireOption("CPACK_TOPLEVEL_DIRECTORY", cpackTopLevel)) return false; + + std::string directoryDefinitionsFilename = + cpackTopLevel + "/directories.wxs"; + + wixSources.push_back(directoryDefinitionsFilename); + + cmWIXSourceWriter directoryDefinitions(Logger, directoryDefinitionsFilename); + directoryDefinitions.BeginElement("Fragment"); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", "TARGETDIR"); + directoryDefinitions.AddAttribute("Name", "SourceDir"); + + directoryDefinitions.BeginElement("Directory"); + if(GetArchitecture() == "x86") + { + directoryDefinitions.AddAttribute("Id", "ProgramFilesFolder"); + } + else + { + directoryDefinitions.AddAttribute("Id", "ProgramFiles64Folder"); + } + + std::vector<std::string> install_root; + + std::string tmp; + if(!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY", tmp)) return false; + + cmSystemTools::SplitPath(tmp.c_str(), install_root); + + if(!install_root.empty() && install_root.back().empty()) + install_root.pop_back(); + + for(std::size_t i = 1; i < install_root.size(); ++i) + { + directoryDefinitions.BeginElement("Directory"); + + if(i == install_root.size() - 1) + { + directoryDefinitions.AddAttribute("Id", "INSTALL_ROOT"); + } + else + { + std::stringstream tmp; + tmp << "INSTALL_PREFIX_" << i; + directoryDefinitions.AddAttribute("Id", tmp.str()); + } + + directoryDefinitions.AddAttribute("Name", install_root[i]); + } + + std::size_t directoryCounter = 0; + std::size_t fileCounter = 0; + + std::string fileDefinitionsFilename = + cpackTopLevel + "/files.wxs"; + + wixSources.push_back(fileDefinitionsFilename); + + cmWIXSourceWriter fileDefinitions(Logger, fileDefinitionsFilename); + fileDefinitions.BeginElement("Fragment"); + + std::string featureDefinitionsFilename = + cpackTopLevel +"/features.wxs"; + + wixSources.push_back(featureDefinitionsFilename); + + cmWIXSourceWriter featureDefinitions(Logger, featureDefinitionsFilename); + featureDefinitions.BeginElement("Fragment"); + + featureDefinitions.BeginElement("Feature"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + featureDefinitions.AddAttribute("Title", Name); + featureDefinitions.AddAttribute("Level", "1"); + featureDefinitions.EndElement(); + + featureDefinitions.BeginElement("FeatureRef"); + featureDefinitions.AddAttribute("Id", "ProductFeature"); + + AddDirectoryAndFileDefinitons( + toplevel, "INSTALL_ROOT", + directoryDefinitions, fileDefinitions, featureDefinitions, + directoryCounter, fileCounter); + + featureDefinitions.EndElement(); + featureDefinitions.EndElement(); + fileDefinitions.EndElement(); + + for(std::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(wixTemplate.empty()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Could not find CPack WiX template file WIX.template.in" << std::endl); + return false; + } + + std::string mainSourceFilePath = cpackTopLevel + "/main.wxs"; + + if(!ConfigureFile(wixTemplate.c_str(), mainSourceFilePath .c_str())) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Failed creating '" << mainSourceFilePath << + "'' from template." << std::endl); + + return false; + } + + wixSources.push_back(mainSourceFilePath); + + return true; +} + +bool cmCPackWIXGenerator::CreateLicenseFile() +{ + std::string licenseSourceFilename; + if(!RequireOption("CPACK_RESOURCE_FILE_LICENSE", licenseSourceFilename)) + return false; + + std::string licenseDestinationFilename; + if(!RequireOption("CPACK_WIX_LICENSE_RTF", licenseDestinationFilename)) + return false; + + std::string extension = GetRightmostExtension(licenseSourceFilename); + + if(extension == ".rtf") + { + cmSystemTools::CopyAFile( + licenseSourceFilename.c_str(), + licenseDestinationFilename.c_str()); + } + else if(extension == ".txt") + { + cmWIXRichTextFormatWriter rtfWriter(licenseDestinationFilename); + + std::ifstream licenseSource(licenseSourceFilename.c_str()); + + std::string line; + while(std::getline(licenseSource, line)) + { + rtfWriter.AddText(line); + rtfWriter.AddText("\n"); + } + } + else + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "unsupported WiX License file extension '" << + extension << "'" << std::endl); + + return false; + } + + return true; +} + +void cmCPackWIXGenerator::AddDirectoryAndFileDefinitons( + const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter) +{ + cmsys::Directory dir; + dir.Load(topdir.c_str()); + + for(std::size_t i = 0; i < dir.GetNumberOfFiles(); ++i) + { + std::string fileName = dir.GetFile(static_cast<unsigned long>(i)); + + if(fileName == "." || fileName == "..") continue; + + std::string fullPath = topdir + "/" + fileName; + + if(cmSystemTools::FileIsDirectory(fullPath.c_str())) + { + std::stringstream tmp; + tmp << "DIR_ID_" << ++directoryCounter; + std::string subDirectoryId = tmp.str(); + + directoryDefinitions.BeginElement("Directory"); + directoryDefinitions.AddAttribute("Id", subDirectoryId); + directoryDefinitions.AddAttribute("Name", fileName); + + AddDirectoryAndFileDefinitons( + fullPath, subDirectoryId, + directoryDefinitions, + fileDefinitions, + featureDefinitions, + directoryCounter, + fileCounter); + + directoryDefinitions.EndElement(); + } + else + { + std::stringstream tmp; + tmp << "_ID_" << ++fileCounter; + std::string idSuffix = tmp.str(); + + std::string componentId = std::string("CMP") + idSuffix; + std::string fileId = std::string("FILE") + idSuffix; + + fileDefinitions.BeginElement("DirectoryRef"); + fileDefinitions.AddAttribute("Id", directoryId); + + fileDefinitions.BeginElement("Component"); + fileDefinitions.AddAttribute("Id", componentId); + fileDefinitions.AddAttribute("Guid", "*"); + + fileDefinitions.BeginElement("File"); + fileDefinitions.AddAttribute("Id", fileId); + fileDefinitions.AddAttribute("Source", fullPath); + fileDefinitions.AddAttribute("KeyPath", "yes"); + + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + fileDefinitions.EndElement(); + + featureDefinitions.BeginElement("ComponentRef"); + featureDefinitions.AddAttribute("Id", componentId); + featureDefinitions.EndElement(); + } + } +} + +bool cmCPackWIXGenerator::RequireOption( + const std::string& name, std::string &value) const +{ + const char* tmp = GetOption(name.c_str()); + if(tmp) + { + value = tmp; + + return true; + } + else + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "Required variable " << name << " not set" << std::endl); + + return false; + } +} + +std::string cmCPackWIXGenerator::GetArchitecture() const +{ + std::string void_p_size; + RequireOption("CPACK_WIX_SIZEOF_VOID_P", void_p_size); + + if(void_p_size == "8") + { + return "x64"; + } + else + { + return "x86"; + } +} + +std::string cmCPackWIXGenerator::GenerateGUID() +{ + UUID guid; + UuidCreate(&guid); + + RPC_CSTR tmp = 0; + UuidToStringA(&guid, &tmp); + + std::string result(reinterpret_cast<char*>(tmp)); + RpcStringFree(&tmp); + + return cmSystemTools::UpperCase(result); +} + +std::string cmCPackWIXGenerator::QuotePath(const std::string& path) +{ + return std::string("\"") + path + '"'; +} + +std::string cmCPackWIXGenerator::GetRightmostExtension( + const std::string& filename) +{ + std::string extension; + + std::string::size_type i = filename.rfind("."); + if(i != std::string::npos) + { + extension = filename.substr(i); + } + + return cmSystemTools::LowerCase(extension); +} diff --git a/Source/CPack/WiX/cmCPackWIXGenerator.h b/Source/CPack/WiX/cmCPackWIXGenerator.h new file mode 100644 index 0000000..5874e00 --- /dev/null +++ b/Source/CPack/WiX/cmCPackWIXGenerator.h @@ -0,0 +1,92 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmCPackWIXGenerator_h +#define cmCPackWIXGenerator_h + +#include <CPack/cmCPackGenerator.h> + +#include <string> +#include <map> + +class cmWIXSourceWriter; + +/** \class cmCPackWIXGenerator + * \brief A generator for WIX files + */ +class cmCPackWIXGenerator : public cmCPackGenerator +{ +public: + cmCPackTypeMacro(cmCPackWIXGenerator, cmCPackGenerator); + +protected: + virtual int InitializeInternal(); + + virtual int PackageFiles(); + + virtual const char* GetOutputExtension() { return ".msi"; } + + virtual enum CPackSetDestdirSupport SupportsSetDestdir() const + { + return SETDESTDIR_UNSUPPORTED; + } + + virtual bool SupportsAbsoluteDestination() const { return false; } + + virtual bool SupportsComponentInstallation() const { return false; } + +private: + bool InitializeWiXConfiguration(); + + bool PackageFilesImpl(); + + bool CreateWiXVariablesIncludeFile(); + + void CopyDefinition( + cmWIXSourceWriter &source, const std::string &name); + + void AddDefinition(cmWIXSourceWriter& source, + const std::string& name, const std::string& value); + + bool CreateWiXSourceFiles(); + + bool CreateLicenseFile(); + + bool RunWiXCommand(const std::string& command); + + bool RunCandleCommand( + const std::string& sourceFile, const std::string& objectFile); + + bool RunLightCommand(const std::string& objectFiles); + + void AddDirectoryAndFileDefinitons(const std::string& topdir, + const std::string& directoryId, + cmWIXSourceWriter& directoryDefinitions, + cmWIXSourceWriter& fileDefinitions, + cmWIXSourceWriter& featureDefinitions, + std::size_t& directoryCounter, + std::size_t& fileCounter); + + bool RequireOption(const std::string& name, std::string& value) const; + + std::string GetArchitecture() const; + + static std::string GenerateGUID(); + + static std::string QuotePath(const std::string& path); + + static std::string GetRightmostExtension(const std::string& filename); + + std::vector<std::string> wixSources; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx new file mode 100644 index 0000000..0763344 --- /dev/null +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.cxx @@ -0,0 +1,137 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXRichTextFormatWriter.h" + +#include <cmVersion.h> + +cmWIXRichTextFormatWriter::cmWIXRichTextFormatWriter( + const std::string& filename): + file(filename.c_str(), std::ios::binary) +{ + StartGroup(); + WriteHeader(); + WriteDocumentPrefix(); +} + +cmWIXRichTextFormatWriter::~cmWIXRichTextFormatWriter() +{ + EndGroup(); + + /* I haven't seen this in the RTF spec but + * wordpad terminates its RTF like this */ + file << "\r\n"; + file.put(0); +} + +void cmWIXRichTextFormatWriter::AddText(const std::string& text) +{ + typedef unsigned char rtf_byte_t; + + for(std::size_t i = 0; i < text.size(); ++i) + { + rtf_byte_t c = rtf_byte_t(text[i]); + + switch(c) + { + case '\\': + file << "\\\\"; + break; + case '{': + file << "\\{"; + break; + case '}': + file << "\\}"; + break; + case '\n': + file << "\\par\r\n"; + break; + case '\r': + continue; + default: + { + if(c <= 0x7F) + { + file << c; + } + else + { + file << "[NON-ASCII-" << int(c) << "]"; + } + } + break; + } + } +} + +void cmWIXRichTextFormatWriter::WriteHeader() +{ + ControlWord("rtf1"); + ControlWord("ansi"); + ControlWord("ansicpg1252"); + ControlWord("deff0"); + ControlWord("deflang1031"); + + WriteFontTable(); + WriteGenerator(); +} + +void cmWIXRichTextFormatWriter::WriteFontTable() +{ + StartGroup(); + ControlWord("fonttbl"); + + StartGroup(); + ControlWord("f0"); + ControlWord("fswiss"); + ControlWord("fcharset0 Arial;"); + EndGroup(); + + EndGroup(); +} + +void cmWIXRichTextFormatWriter::WriteGenerator() +{ + StartGroup(); + NewControlWord("generator"); + file << " CPack WiX Generator (" << cmVersion::GetCMakeVersion() << ");"; + EndGroup(); +} + +void cmWIXRichTextFormatWriter::WriteDocumentPrefix() +{ + ControlWord("viewkind4"); + ControlWord("uc1"); + ControlWord("pard"); + ControlWord("f0"); + ControlWord("fs20"); +} + +void cmWIXRichTextFormatWriter::ControlWord(const std::string& keyword) +{ + file << "\\" << keyword; +} + +void cmWIXRichTextFormatWriter::NewControlWord(const std::string& keyword) +{ + file << "\\*\\" << keyword; +} + +void cmWIXRichTextFormatWriter::StartGroup() +{ + file.put('{'); +} + +void cmWIXRichTextFormatWriter::EndGroup() +{ + file.put('}'); +} diff --git a/Source/CPack/WiX/cmWIXRichTextFormatWriter.h b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h new file mode 100644 index 0000000..10b67c3 --- /dev/null +++ b/Source/CPack/WiX/cmWIXRichTextFormatWriter.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXRichTextFormatWriter_h +#define cmWIXRichTextFormatWriter_h + +#include <fstream> + +/** \class cmWIXRichtTextFormatWriter + * \brief Helper class to generate Rich Text Format (RTF) documents + * from plain text (e.g. for license and welcome text) + */ +class cmWIXRichTextFormatWriter +{ +public: + cmWIXRichTextFormatWriter(const std::string& filename); + ~cmWIXRichTextFormatWriter(); + + void AddText(const std::string& text); + +private: + void WriteHeader(); + void WriteFontTable(); + void WriteGenerator(); + + void WriteDocumentPrefix(); + + void ControlWord(const std::string& keyword); + void NewControlWord(const std::string& keyword); + + void StartGroup(); + void EndGroup(); + + std::ofstream file; +}; + +#endif diff --git a/Source/CPack/WiX/cmWIXSourceWriter.cxx b/Source/CPack/WiX/cmWIXSourceWriter.cxx new file mode 100644 index 0000000..b259bb1 --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.cxx @@ -0,0 +1,178 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmWIXSourceWriter.h" + +#include <CPack/cmCPackGenerator.h> + +#include <windows.h> + +cmWIXSourceWriter::cmWIXSourceWriter(cmCPackLog* logger, + const std::string& filename, + bool isIncludeFile): + Logger(logger), + file(filename.c_str()), + state(DEFAULT) +{ + WriteXMLDeclaration(); + + if(isIncludeFile) + { + BeginElement("Include"); + } + else + { + BeginElement("Wix"); + } + + AddAttribute("xmlns", "http://schemas.microsoft.com/wix/2006/wi"); +} + +cmWIXSourceWriter::~cmWIXSourceWriter() +{ + while(elements.size()) + { + EndElement(); + } +} + +void cmWIXSourceWriter::BeginElement(const std::string& name) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<" << name; + + elements.push_back(name); + state = BEGIN; +} + +void cmWIXSourceWriter::EndElement() +{ + if(elements.empty()) + { + cmCPackLogger(cmCPackLog::LOG_ERROR, + "can not end WiX element with no open elements" << std::endl); + return; + } + + if(state == DEFAULT) + { + file << "\n"; + Indent(elements.size()-1); + file << "</" << elements.back() << ">"; + } + else + { + file << "/>"; + } + + elements.pop_back(); + state = DEFAULT; +} + +void cmWIXSourceWriter::AddProcessingInstruction( + const std::string& target, const std::string& content) +{ + if(state == BEGIN) + { + file << ">"; + } + + file << "\n"; + Indent(elements.size()); + file << "<?" << target << " " << content << "?>"; + + state = DEFAULT; +} + +void cmWIXSourceWriter::AddAttribute( + const std::string& key, const std::string& value) +{ + std::string utf8 = WindowsCodepageToUtf8(value); + + file << " " << key << "=\"" << EscapeAttributeValue(utf8) << '"'; +} + +std::string cmWIXSourceWriter::WindowsCodepageToUtf8(const std::string& value) +{ + if(value.empty()) return std::string(); + + int characterCount = MultiByteToWideChar( + CP_ACP, 0, value.c_str(), value.size(), 0, 0); + + if(characterCount == 0) return std::string(); + + std::vector<wchar_t> utf16(characterCount); + + MultiByteToWideChar( + CP_ACP, 0, value.c_str(), value.size(), &utf16[0], utf16.size()); + + int utf8ByteCount = + WideCharToMultiByte(CP_UTF8, 0, &utf16[0], utf16.size(), 0, 0, 0, 0); + + if(utf8ByteCount == 0) return std::string(); + + std::vector<char> utf8(utf8ByteCount); + + WideCharToMultiByte(CP_UTF8, 0, &utf16[0], utf16.size(), + &utf8[0], utf8.size(), 0, 0); + + return std::string(&utf8[0], utf8.size()); +} + + +void cmWIXSourceWriter::WriteXMLDeclaration() +{ + file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; +} + +void cmWIXSourceWriter::Indent(std::size_t count) +{ + for(std::size_t i = 0; i < count; ++i) + { + file << " "; + } +} + +std::string cmWIXSourceWriter::EscapeAttributeValue( + const std::string& value) +{ + std::string result; + result.reserve(value.size()); + + char c = 0; + for(std::size_t i = 0 ; i < value.size(); ++i) + { + c = value[i]; + switch(c) + { + case '<': + result += "<"; + break; + case '&': + result +="&"; + break; + case '"': + result += """; + break; + default: + result += c; + } + } + + return result; +} diff --git a/Source/CPack/WiX/cmWIXSourceWriter.h b/Source/CPack/WiX/cmWIXSourceWriter.h new file mode 100644 index 0000000..582554d --- /dev/null +++ b/Source/CPack/WiX/cmWIXSourceWriter.h @@ -0,0 +1,67 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2012 Kitware, Inc. + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#ifndef cmWIXSourceWriter_h +#define cmWIXSourceWriter_h + +#include <vector> +#include <string> +#include <fstream> + +#include <CPack/cmCPackLog.h> + +/** \class cmWIXSourceWriter + * \brief Helper class to generate XML WiX source files + */ +class cmWIXSourceWriter +{ +public: + cmWIXSourceWriter(cmCPackLog* logger, + const std::string& filename, bool isIncludeFile = false); + + ~cmWIXSourceWriter(); + + void BeginElement(const std::string& name); + + void EndElement(); + + void AddProcessingInstruction( + const std::string& target, const std::string& content); + + void AddAttribute( + const std::string& key, const std::string& value); + + static std::string WindowsCodepageToUtf8(const std::string& value); + +private: + enum State + { + DEFAULT, + BEGIN + }; + + void WriteXMLDeclaration(); + + void Indent(std::size_t count); + + static std::string EscapeAttributeValue(const std::string& value); + + std::ofstream file; + + std::vector<std::string> elements; + + State state; + + cmCPackLog* Logger; +}; + +#endif diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx b/Source/CPack/cmCPackGeneratorFactory.cxx index 37ff460..ded0cc9 100644 --- a/Source/CPack/cmCPackGeneratorFactory.cxx +++ b/Source/CPack/cmCPackGeneratorFactory.cxx @@ -19,6 +19,7 @@ #include "cmCPackZIPGenerator.h" #include "cmCPackSTGZGenerator.h" #include "cmCPackNSISGenerator.h" + #ifdef __APPLE__ # include "cmCPackDragNDropGenerator.h" # include "cmCPackBundleGenerator.h" @@ -37,6 +38,9 @@ # include "cmCPackRPMGenerator.h" #endif +#ifdef _WIN32 +# include "WiX/cmCPackWIXGenerator.h" +#endif #include "cmCPackLog.h" @@ -80,6 +84,13 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory() this->RegisterGenerator("ZIP", "ZIP file format", cmCPackZIPGenerator::CreateGenerator); } +#ifdef _WIN32 + if (cmCPackWIXGenerator::CanGenerate()) + { + this->RegisterGenerator("WIX", "MSI file format via WiX tools", + cmCPackWIXGenerator::CreateGenerator); + } +#endif if (cmCPackTarBZip2Generator::CanGenerate()) { this->RegisterGenerator("TBZ2", "Tar BZip2 compression", diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index ae69ce8..8ce0579 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -692,6 +692,30 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ endif() endif() + # On Windows run the CPackWiXGenerator test + # if the WiX Toolset seems to be available + if(WIN32) + file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT) + + find_program(WIX_LIGHT_EXECUTABLE light + PATHS "${WIX_ROOT}/bin" + DOC "WiX Toolset light.exe location") + + if(WIX_LIGHT_EXECUTABLE) + add_test(CPackWiXGenerator ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator" + "${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project CPackWiXGenerator + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --test-command ${CMAKE_CMAKE_COMMAND} + "-DCPackWiXGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackWiXGenerator/build" + "-DCPackCommand=${CMAKE_CPACK_COMMAND}" + -P "${CMake_SOURCE_DIR}/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake") + endif() + endif() + if(CTEST_RUN_CPackComponents) set(CPackComponents_EXTRA_OPTIONS) if(APPLE) diff --git a/Tests/CPackWiXGenerator/CMakeLists.txt b/Tests/CPackWiXGenerator/CMakeLists.txt new file mode 100644 index 0000000..ce02f11 --- /dev/null +++ b/Tests/CPackWiXGenerator/CMakeLists.txt @@ -0,0 +1,73 @@ +cmake_minimum_required(VERSION 2.8) + +project(CPackWiXGenerator) + +add_library(mylib mylib.cpp) + +add_executable(mylibapp mylibapp.cpp) +target_link_libraries(mylibapp mylib) + +install(TARGETS mylib + ARCHIVE + DESTINATION lib + COMPONENT libraries) + +install(TARGETS mylibapp + RUNTIME + DESTINATION bin + COMPONENT applications) + +install(FILES mylib.h "file with spaces.h" + DESTINATION include + COMPONENT headers) + +set(CPACK_GENERATOR "WIX") + +set(CPACK_PACKAGE_NAME "MyLib") +set(CPACK_PACKAGE_VENDOR "CMake.org") +set(CPACK_PACKAGE_CONTACT "somebody@cmake.org") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "MyLib - CPack Component Installation Example") + +set(CPACK_PACKAGE_VERSION_MAJOR "1") +set(CPACK_PACKAGE_VERSION_MINOR "0") +set(CPACK_PACKAGE_VERSION_PATCH "0") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "CPack Component Example") + +set(CPACK_WIX_UPGRADE_GUID "BF20CE5E-7F7C-401D-8F7C-AB45E8D170E6") + +include(CPack) + +cpack_add_install_type(Full DISPLAY_NAME "Everything") +cpack_add_install_type(Developer) + +cpack_add_component_group(Runtime) + +cpack_add_component_group(Development + EXPANDED + DESCRIPTION "All of the tools you'll ever need to develop software") + +cpack_add_component(applications + DISPLAY_NAME "MyLib Application" + DESCRIPTION "An extremely useful application that makes use of MyLib" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(documentation + DISPLAY_NAME "MyLib Documentation" + DESCRIPTION "The extensive suite of MyLib Application documentation files" + GROUP Runtime + INSTALL_TYPES Full) + +cpack_add_component(libraries + DISPLAY_NAME "Libraries" + DESCRIPTION "Static libraries used to build programs with MyLib" + GROUP Development + INSTALL_TYPES Developer Full) + +cpack_add_component(headers + DISPLAY_NAME "C++ Headers" + DESCRIPTION "C/C++ header files for use with MyLib" + GROUP Development + DEPENDS libraries + INSTALL_TYPES Developer Full) diff --git a/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake new file mode 100644 index 0000000..e6c8047 --- /dev/null +++ b/Tests/CPackWiXGenerator/RunCPackVerifyResult.cmake @@ -0,0 +1,70 @@ +message(STATUS "=============================================================") +message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") +message(STATUS "") + +if(NOT CPackWiXGenerator_BINARY_DIR) + message(FATAL_ERROR "CPackWiXGenerator_BINARY_DIR not set") +endif() + +message(STATUS "CPackCommand: ${CPackCommand}") + +execute_process(COMMAND "${CPackCommand}" + RESULT_VARIABLE CPack_result + OUTPUT_VARIABLE CPack_output + ERROR_VARIABLE CPack_error + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + +if(CPack_result) + message(FATAL_ERROR "CPack execution went wrong!, CPack_output=${CPack_output}, CPack_error=${CPack_error}") +else () + message(STATUS "CPack_output=${CPack_output}") +endif() + +set(expected_file_mask "*.msi") +file(GLOB installer_file "${expected_file_mask}") + +message(STATUS "installer_file='${installer_file}'") +message(STATUS "expected_file_mask='${expected_file_mask}'") + +if(NOT installer_file) + message(FATAL_ERROR "installer_file does not exist.") +endif() + +function(run_wix_command command) + file(TO_CMAKE_PATH "$ENV{WIX}" WIX_ROOT) + set(WIX_PROGRAM "${WIX_ROOT}/bin/${command}.exe") + + if(NOT EXISTS "${WIX_PROGRAM}") + message(FATAL_ERROR "Failed to find WiX Tool: ${WIX_PROGRAM}") + endif() + + message(STATUS "Running WiX Tool: ${command} ${ARGN}") + + execute_process(COMMAND "${WIX_PROGRAM}" ${ARGN} + RESULT_VARIABLE WIX_result + OUTPUT_VARIABLE WIX_output + ERROR_VARIABLE WIX_output + WORKING_DIRECTORY "${CPackWiXGenerator_BINARY_DIR}") + + message(STATUS "${command} Output: \n${WIX_output}") + + if(WIX_result) + message(FATAL_ERROR "WiX ${command} failed: ${WIX_result}") + endif() +endfunction() + +file(GLOB WXS_SOURCE_FILES + "${CPackWiXGenerator_BINARY_DIR}/_CPack_Packages/*/WIX/*.wxs") + +if(NOT WXS_SOURCE_FILES) + message(FATAL_ERROR "Failed finding WiX source files to validate.") +endif() + +foreach(WXS_SOURCE_FILE IN LISTS WXS_SOURCE_FILES) + run_wix_command(wixcop "${WXS_SOURCE_FILE}") +endforeach() + +# error SMOK1076 : ICE61: This product should remove only older +# versions of itself. The Maximum version is not less +# than the current product. (1.0.0 1.0.0) +run_wix_command(smoke -nologo -wx -sw1076 "${installer_file}") diff --git a/Tests/CPackWiXGenerator/file with spaces.h b/Tests/CPackWiXGenerator/file with spaces.h new file mode 100644 index 0000000..e69de29 diff --git a/Tests/CPackWiXGenerator/mylib.cpp b/Tests/CPackWiXGenerator/mylib.cpp new file mode 100644 index 0000000..8ddac19 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.cpp @@ -0,0 +1,7 @@ +#include "mylib.h" +#include "stdio.h" + +void mylib_function() +{ + printf("This is mylib"); +} diff --git a/Tests/CPackWiXGenerator/mylib.h b/Tests/CPackWiXGenerator/mylib.h new file mode 100644 index 0000000..5d0a822 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylib.h @@ -0,0 +1 @@ +void mylib_function(); diff --git a/Tests/CPackWiXGenerator/mylibapp.cpp b/Tests/CPackWiXGenerator/mylibapp.cpp new file mode 100644 index 0000000..a438ac7 --- /dev/null +++ b/Tests/CPackWiXGenerator/mylibapp.cpp @@ -0,0 +1,6 @@ +#include "mylib.h" + +int main() +{ + mylib_function(); +} -- 1.7.9.msysgit.0 | ||||||||
Relationships | ||||||
|
Relationships |
Notes | |
(0023750) Timothy St. Clair (reporter) 2010-12-07 09:04 |
realized my patch was a reverse patch, whoops. |
(0023751) David Cole (manager) 2010-12-07 09:15 |
For one thing, it needs a test in the test suite that explicitly exercises the WiX generator... And then we would need to make sure we set up a dashboard machine with whatever tools are necessary to run that test. Looks like perhaps a little more documentation is in order as well. Also, all of your CPACK_WIX_* variables should be documented in CPack.cmake. See the CPACK_NSIS_* variables all listed out there. And a documentation comment in CPack.cmake that sort of gives you basic instructions about how to install/run WiX would be good. I don't have time to go into more detail at the moment, but I'll add more notes here later. Thanks. |
(0023777) Eric NOULARD (developer) 2010-12-07 16:56 |
I would suggest adding documentation in a separate CPackWIX.cmake. The CPack.cmake is becoming huge and it will become less and less easy to avoid overlapping changes. I'd rather create a CPackNSIS.cmake and put the documentation there in order to make CPack.cmake smaller that adding more thing in it, see some comments in CPack documentation enhancement bug: http://public.kitware.com/Bug/view.php?id=10067 [^] |
(0024767) David Cole (manager) 2011-01-17 12:06 |
One other thought I have here: Why should we support WiX, when it's really just an intermediary to get to an *.msi installer? Why don't we simply write a CPack generator that creates a Visual Studio deployment project directly? Then it could produce msi files without installing any other tools... Just having Visual Studio installed would be sufficient. |
(0024768) Timothy St. Clair (reporter) 2011-01-17 12:12 |
Because you would have to do it for * and it's not supported in express editions. This would allow you to use any generator on *windows and still create a .msi |
(0029326) Patrick Spendrin (reporter) 2012-04-24 17:01 |
Given that I need to produce MSI Installers and want to work on this bug, could you specify where the tests are for testing the cpack generators? I only found one for all generators in the Tests/ subdirectory in the git repository. Also, are there any other requirements besides moving the documentation to CPackWIX.cmake? |
(0029329) Eric NOULARD (developer) 2012-04-24 18:28 |
Hi Patrick, The CPack tests are in subdirectories of Tests/ directory namely Tests/CPackComponents Tests/CPackComponentsForAll Tests/CPackTestAllGenerators those test are driven by the Tests/CMakeLists.txt file (search for CPack in it). Concerning the documentation starting with 2.8.8 CPack has builtin basic documentation markup support which makes it easy to add documentation to cpack --help-variable and cpack --help-command. Have a look at CPackRPM.cmake or any other CPack*.cmake from 2.8.8 and you'll see examples. If you have any question about that just ask. Concerning the tests may be you can explain us what kind of tools is needed for this new generator. |
(0029335) David Cole (manager) 2012-04-25 08:53 |
When adding to the tests, you may need to modify the CMake/Tests/CMakeLists.txt file to include a chunk similar to this, but for WiX instead of NSIS: if(NSIS_MAKENSIS_EXECUTABLE) set(CPackComponents_EXTRA_OPTIONS ${CPackComponents_EXTRA_OPTIONS} -DCPACK_BINARY_NSIS:BOOL=ON) endif(NSIS_MAKENSIS_EXECUTABLE) That's for the CPackComponents test. Then we'll need to install whatever tools are necessary to test the WiX functionality on some of our dashboard machines, preferably several to cover 32 vs 64-bit, vs 8, 9, 10 and 11, or some combinatorial subset of those types of things. We should also have a good understanding of any version requirements of the WiX tool, and hopefully be able to detect that version from the CPack code so that we can enforce a minimum required version of WiX. Is it just one command line tool needed (in addition to a VS installation with msi builder capabilities)? My understanding is that it's just one tool that processes an xml file and produces an msi installer. Is that correct? |
(0029336) David Cole (manager) 2012-04-25 08:55 |
As you're working on this, I think all the CPack variables necessary (if any) should be ALL CAPS, even though WiX has a funky capitalization... (Just to be consistent and blend in with the pre-existing CPack variables.) |
(0029337) David Cole (manager) 2012-04-25 08:56 |
Sorry for the stupid questions in my earlier two notes. I just read through the patch and see that there are multiple tools, and that you are already blending in well with all caps variables. Thanks! |
(0030460) Patrick Spendrin (reporter) 2012-08-12 10:15 |
I will hopefully submit the patch in the coming days, I still have some doc issues. |
(0030759) David Cole (manager) 2012-08-25 12:00 edited on: 2012-08-25 12:01 |
I have uploaded a new patch "0001-CPack-Add-WiX-generator-for-building-.msi-installers.patch" that applies cleanly on top of today's 'master' branch of CMake. This patch still requires a few more additions before we can take it: (1) adding documentation of the WiX CPack variables, and (2) adding a test that covers the WiX generator, ... and possibly somebody helping me getting WiX set up on a dashboard machine so that we can guarantee that it's getting tested nightly. If somebody can add that stuff to the "0001-patch" file and upload a new version of it, I can get it tested. |
(0030822) Nils Gladitz (developer) 2012-09-03 13:42 |
I've tried using the patch but had some problems with it. - "CompressFiles" does not seem to be virtual or get called from the generator itself (the only reference I found was in bills-comments.txt) - Tool paths seem to have changed with the WiX version that I tried 3.6rc - ${CPACK_PACKAGE_INSTALL_DIRECTORY} is passed to heat (probably meant this->toplevel?) - I wasn't sure how the required schema file should look like I tried writing an alternate implementation (attached; I haven't done anything like this with git before so I hope this works). I've reused most of the skeleton setup provided by the initial patch but try to generate my own xml source file instead of having the heat tool generate it automatically. I'm hoping this will make component installations easier to implement. I've used this WiX version (3.6rc): http://wix.codeplex.com/releases/view/88566 [^] (final version is supposed to get released today). The WiX installer sets the WIX environment variable which points at the install location; I don't know if this is provided by earlier versions but it is what I use in the generator to locate the tools. There are currently no custom CPack variables for the generator (at least none a regular user should have to touch; do those have a special naming convention?). The test "CPackTestAllGenerators" seems to pick up the generator and an .msi is generated. CPackComponents and CPackComponentsForAll seem to be identical from their description but the former only seems to test one generator (though not the same on every platform) and the later seems to be for generators which implement "one-file-per-group"(?). I'm not sure where or how one would/should add the WiX generator but at the moment component installs are not implemented either way. There would still be a lot of work to do (component installations, proper gui for feature and install location selection, upgrade guid specification, start menu intergration etc.) to get it on the same level as the other available generators. Is anyone else still working on this or can I put some time into it? What would be the minimal feature set to get a first version of this included in a release? |
(0030908) Nils Gladitz (developer) 2012-09-04 08:20 |
I guess I should have also mentioned that the patch I attached is "0001-alternate-WiX-cpack-implementation.patch". Stable WiX 3.6 has been released now as well: http://wix.codeplex.com/releases/view/93929 [^] |
(0030919) David Cole (manager) 2012-09-04 16:11 |
Regarding your questions in 0011575:0030822 "Is anyone else still working on this or can I put some time into it?" If they are, they should be posting about it here. To the best of my knowledge, nobody else is actively working on this. (If you are monitoring this bug, and have conflicting information here, please add a note to say who's doing what...) "What would be the minimal feature set to get a first version of this included in a release?" Ideally, CPack should "just work" for the new generator and produce a working installer for "Tests/Tutorial/Step6" without changing the test code at all. If that's not possible, then documentation in CPackWiX.cmake saying what needs to be done to get it to work with a project. All the new CPack variables should be documented in CPackWiX.cmake, (use the NSIS or another one as a model). And finally, a test should be added in the CMake test suite that activates testing of the WiX CPack generator if the WiX tools are found on the machine. This way, the CMake test suite will automatically run the CPack WiX tests on any dashboard machine as long as the WiX tools are installed on it in their default location. (Or, second best, we can modify the script of some dashboards to explicitly point to the WiX tools, or put them in the PATH just for the script, on a given machine if necessary.) I will be happy to accept this patch into 'next' for testing on the dashboards as soon as it's fully documented and testable. |
(0030938) Nils Gladitz (developer) 2012-09-06 02:58 |
Thanks, then I call dibs :) |
(0030973) Nils Gladitz (developer) 2012-09-10 03:36 |
I uploaded 0001-CPack-WiX-Generator.patch. Things I added are: - a modified version of an existing test that verifies an installer has been created and runs WiX validation tools on generated source files and the installer. - new variable CPACK_WIX_UPGRADE_GUID with documentation. - 64 bit installers (x64; I'm not sure how to detect/distinguish it from ia64) I think the Tutorial Step6 code "just works" except for the license resouce file currently being ignored. The whole thing is still a bit minimalistic feature wise ... could someone take a look at it though and tell me if I'm on the right track? |
(0031009) Nils Gladitz (developer) 2012-09-12 10:32 |
I've uploaded 0001-CPack-WiX-Generator-2.patch which adds: - display of license file - custom install directory - non ASCII (windows codepage) filenames (I'd like to add this to the test case somehow but it would probably break as soon as it is run on a system with a different codepage) - upgrade logic - hard requirement for WiX 3.6 - new cpack variables CPACK_WIX_LICENSE_RTF and CPACK__PRODUCT_GUID + documentation |
(0031018) David Cole (manager) 2012-09-12 15:13 |
This looks good upon cursory inspection. We will probably re-write bits of it as we apply. For example, we don't have any calls to std::throw* in the CMake code base right now, so I'd rather not introduce them here. Also, we don't use any "../" style paths in #include directives to the best of my knowledge, so those things will change. Possibly others as I have time to more deeply dive into an analysis of this latest "-2" patch. Questions for you: - is there anything else left to do, or do you want us to consider the "-2" patch for merging to 'next' and testing on the dashboards...? - could you point me to the proper definitive URL for downloading and trying out WiX 3.6? Thanks for the patch -- looks pretty complete in terms of testing and documentation. Also, looks like projects will be able to override the default "WIX.template.in" file, which is fabulous. |
(0031021) Nils Gladitz (developer) 2012-09-12 15:59 |
Merge of the -2 patch into next sounds good! There is plenty more that could be done (components, start menu entries, user customizations, ...) but it would be good to have a first version out there that is tested and gets some feedback. Also I can incorporate your changes into future development before I drift apart too far. Could it be marked "experimental" in the first release (to hint at possible future breaking changes) or would something like that be frowned upon? You can get the WiX Toolset installer "WiX36.exe" here: http://wix.codeplex.com/releases/view/93929 [^] I use the WIX environment variable (set by the installer) so any running processes (e.g. ctest) may have to be restarted to pick it up. Thanks for putting time into this! |
(0031054) Nils Gladitz (developer) 2012-09-19 02:42 |
Is there anything I can/should do to make the merge easier? |
(0031071) David Cole (manager) 2012-09-20 17:11 |
Nope, thanks for offering, though. Unless...... can you submit a Nightly dashboard that tests the WiX CPack generator? I'm downloading the WiX36.exe now on my own machine. If I can it to work on my machine, I'll see if I can set it up on one of Kitware's dashboard machines, too, so we can get this merged into 'next'. |
(0031076) David Cole (manager) 2012-09-20 19:55 |
This worked ok on my machine, and can even build an installer for CMake itself with one minor extra patch to CMake's source code: $ git diff diff --git a/CMakeCPackOptions.cmake.in b/CMakeCPackOptions.cmake.in index 3a72eaa..c659d59 100644 --- a/CMakeCPackOptions.cmake.in +++ b/CMakeCPackOptions.cmake.in @@ -51,3 +51,9 @@ if("${CPACK_GENERATOR}" STREQUAL "PackageMaker") set(CPACK_PACKAGE_DEFAULT_LOCATION "/usr") endif() endif() + +if("${CPACK_GENERATOR}" STREQUAL "WIX") + # WIX installers require at most a 4 component version number, where + # each component is an integer between 0 and 65534 inclusive + set(CPACK_PACKAGE_VERSION "@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@.@CMake_VERSION_PATCH@") +endif() Hopefully, tomorrow I can find the time to install WiX on one of our Windows dashboard machines, and make sure the tests running there actually exercise the new code. Once I do that, I'll feel fairly comfortable merging this to 'next' and trying to get it into 'master' in time for 2.8.10. Thanks a ton for your work on this -- looks pretty nice so far. |
(0031081) Nils Gladitz (developer) 2012-09-21 12:05 |
Nice. And thanks! I'm glad this works for you as well. I've got permission to run a nightly dashboard at work and the experimental submission I tried seems to have worked (vista32tempo3.scivis). If all goes well the scheduler should trigger nightly builds at 01:15am UTC. Hope that is about right ... I get confused by all those timezones. Is there anything else I should configure or change to gear this towards exercising WiX? (different submission track or git branch or test filter?) |
(0031140) David Cole (manager) 2012-10-01 15:10 |
Unfortunately, we've run out of time for 2.8.10 on this one. I can't spend any more time on this over the next 2 weeks, but I can re-visit it at that point, and try to get it into 'next' so that it can be in 2.8.11 For now, folks interested in this can (and should) certainly apply the latest patch and see how it works for them. For the record, what remains to be done here is: style cleanup (no ".." in #include directives, follow CMake spacing and brace style), no use of std::throw until such time as we prove it's acceptable in all the compilers that CMake builds with on our dashboards, the test does not get activated automatically because the find_program call does not work because WIX is an empty variable in the context of Tests/CMakeLists.txt, and I need to add a dashboard on a machine at kitware where WiX is installed. I got to the point where I know this list of stuff that needs to be done, but unfortunately now, we're up against the CMake 2.8.10-rc1 deadline with not enough time to actually do the tasks. So. This is still alive, but it's moving to the CMake 2.8.11 release. |
(0031144) Nils Gladitz (developer) 2012-10-02 02:35 |
I understand. Thanks for the update! The thing with the WIX variable in Test/CMakeLists.txt certainly looks wrong. I'm not sure why or how this was working here ... it should be using $ENV{WIX}. |
(0031163) Nils Gladitz (developer) 2012-10-03 10:18 |
I've uploaded a new patch 0001-CPack-WiX-Generator-3.patch in which I: - replaced C++ exception handling with C style error reporting - fixed indentation (I hope I found them all) - replaced all ".." relative include paths - integrated your modification in 0011575:0031076 - modified the WiX template to rollback previous installations on failed upgrades - use $ENV{WIX} in Tests/CMakeLists.txt I hope this will make merging this a little easier. |
(0031818) David Cole (manager) 2012-12-03 11:07 |
Patch tested and pushed to the stage and merged to 'next': http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=85baac1503c638756211ba07c4c25128e6d3d845 [^] Will keep an eye on the dashboards today and tomorrow. Will be in 2.8.11 in January... Thanks for your persistence. |
(0031829) David Cole (manager) 2012-12-04 15:47 |
This commit and its two parents were also necessary to address issues that popped up on the Continuous and Nightly dashboards: http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=a74bd470a4d01cfa06710d039bb435b02682ac3f [^] Hopefully, tomorrow, it will be green and clean for our next merge-to-master session... |
(0032983) Robert Maynard (manager) 2013-05-06 09:32 |
Closing resolved issues that have not been updated in more than 4 months. |
Notes |
Issue History | |||
Date Modified | Username | Field | Change |
2010-12-07 08:55 | Timothy St. Clair | New Issue | |
2010-12-07 08:55 | Timothy St. Clair | File Added: cmake-2.8.3-wix.patch | |
2010-12-07 09:04 | Timothy St. Clair | Note Added: 0023750 | |
2010-12-07 09:06 | Timothy St. Clair | File Added: cmake-2.8.3-wix-forward.patch | |
2010-12-07 09:15 | David Cole | Note Added: 0023751 | |
2010-12-07 16:56 | Eric NOULARD | Note Added: 0023777 | |
2010-12-08 08:25 | David Cole | Relationship added | related to 0010939 |
2011-01-17 12:06 | David Cole | Note Added: 0024767 | |
2011-01-17 12:12 | Timothy St. Clair | Note Added: 0024768 | |
2011-01-17 17:00 | David Cole | Assigned To | => David Cole |
2011-01-17 17:00 | David Cole | Status | new => assigned |
2011-10-25 22:13 | David Cole | Assigned To | David Cole => |
2011-10-25 22:13 | David Cole | Status | assigned => backlog |
2012-04-24 17:01 | Patrick Spendrin | Note Added: 0029326 | |
2012-04-24 18:28 | Eric NOULARD | Note Added: 0029329 | |
2012-04-25 08:53 | David Cole | Note Added: 0029335 | |
2012-04-25 08:55 | David Cole | Note Added: 0029336 | |
2012-04-25 08:56 | David Cole | Note Added: 0029337 | |
2012-08-12 08:10 | David Cole | Assigned To | => David Cole |
2012-08-12 08:10 | David Cole | Status | backlog => assigned |
2012-08-12 08:10 | David Cole | Target Version | => CMake 2.8.10 |
2012-08-12 10:15 | Patrick Spendrin | Note Added: 0030460 | |
2012-08-25 11:53 | David Cole | File Added: 0001-CPack-Add-WiX-generator-for-building-.msi-installers.patch | |
2012-08-25 12:00 | David Cole | Note Added: 0030759 | |
2012-08-25 12:01 | David Cole | Note Edited: 0030759 | |
2012-09-03 13:42 | Nils Gladitz | File Added: 0001-alternate-WiX-cpack-implementation.patch | |
2012-09-03 13:42 | Nils Gladitz | Note Added: 0030822 | |
2012-09-04 08:20 | Nils Gladitz | Note Added: 0030908 | |
2012-09-04 16:11 | David Cole | Note Added: 0030919 | |
2012-09-06 02:58 | Nils Gladitz | Note Added: 0030938 | |
2012-09-10 03:27 | Nils Gladitz | File Added: 0001-CPack-WiX-Generator.patch | |
2012-09-10 03:36 | Nils Gladitz | Note Added: 0030973 | |
2012-09-12 10:27 | Nils Gladitz | File Added: 0001-CPack-WiX-Generator-2.patch | |
2012-09-12 10:32 | Nils Gladitz | Note Added: 0031009 | |
2012-09-12 15:13 | David Cole | Note Added: 0031018 | |
2012-09-12 15:59 | Nils Gladitz | Note Added: 0031021 | |
2012-09-19 02:42 | Nils Gladitz | Note Added: 0031054 | |
2012-09-20 17:11 | David Cole | Note Added: 0031071 | |
2012-09-20 19:55 | David Cole | Note Added: 0031076 | |
2012-09-21 12:05 | Nils Gladitz | Note Added: 0031081 | |
2012-10-01 15:10 | David Cole | Note Added: 0031140 | |
2012-10-01 15:13 | David Cole | Target Version | CMake 2.8.10 => CMake 2.8.11 |
2012-10-02 02:35 | Nils Gladitz | Note Added: 0031144 | |
2012-10-03 10:11 | Nils Gladitz | File Added: 0001-CPack-WiX-Generator-3.patch | |
2012-10-03 10:18 | Nils Gladitz | Note Added: 0031163 | |
2012-12-03 11:07 | David Cole | Note Added: 0031818 | |
2012-12-03 11:07 | David Cole | Status | assigned => resolved |
2012-12-03 11:07 | David Cole | Fixed in Version | => CMake 2.8.11 |
2012-12-03 11:07 | David Cole | Resolution | open => fixed |
2012-12-04 15:47 | David Cole | Note Added: 0031829 | |
2013-05-06 09:32 | Robert Maynard | Note Added: 0032983 | |
2013-05-06 09:32 | Robert Maynard | Status | resolved => closed |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |