浏览代码

cpack wix: support WiX generator on Cygwin

Cygwin-built CMake now converts paths from Cygwin to Windows form
(using cygpath -w) before they're passed to WiX.

The Wix generator on Cygwin requires the libuuid-dev package when
building CMake. However, the DLL it links to is installed by default
as part of Cygwin's core libs, so it does not need to be distributed.

If libuuid-dev isn't available, CMake is simply built without Wix
support on Cygwin.
Stephen Sorley 8 年之前
父节点
当前提交
e1409101c9

+ 12 - 2
Source/CMakeLists.txt

@@ -936,8 +936,13 @@ if(UNIX)
   endif()
 endif()
 
-if(WIN32)
+if(CYGWIN)
+  find_package(LibUUID)
+endif()
+if(WIN32 OR (CYGWIN AND LibUUID_FOUND))
   set(CPACK_SRCS ${CPACK_SRCS}
+    CPack/Wix/cmCMakeToWixPath.cxx
+    CPack/Wix/cmCMakeToWixPath.h
     CPack/WiX/cmCPackWIXGenerator.cxx
     CPack/WiX/cmCPackWIXGenerator.h
     CPack/WiX/cmWIXAccessControlList.cxx
@@ -958,7 +963,7 @@ if(WIN32)
     CPack/WiX/cmWIXShortcut.h
     CPack/WiX/cmWIXSourceWriter.cxx
     CPack/WiX/cmWIXSourceWriter.h
-  )
+    )
 endif()
 
 if(APPLE)
@@ -991,6 +996,11 @@ if(APPLE)
       "See CMakeFiles/CMakeError.log for details of the failure.")
   endif()
 endif()
+if(CYGWIN AND LibUUID_FOUND)
+  target_link_libraries(CPackLib ${LibUUID_LIBRARIES})
+  include_directories(CPackLib ${LibUUID_INCLUDE_DIRS})
+  set_property(SOURCE CPack/cmCPackGeneratorFactory.cxx PROPERTY COMPILE_DEFINITIONS HAVE_LIBUUID)
+endif()
 if(CPACK_ENABLE_FREEBSD_PKG AND FREEBSD_PKG_INCLUDE_DIRS AND FREEBSD_PKG_LIBRARIES)
   target_link_libraries(CPackLib ${FREEBSD_PKG_LIBRARIES})
   include_directories(${FREEBSD_PKG_INCLUDE_DIRS})

+ 39 - 0
Source/CPack/WiX/cmCMakeToWixPath.cxx

@@ -0,0 +1,39 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmCMakeToWixPath.h"
+
+#include "cmSystemTools.h"
+
+#include <string>
+#include <vector>
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+std::string CMakeToWixPath(const std::string& cygpath)
+{
+  std::vector<char> winpath_chars;
+  ssize_t winpath_size;
+
+  // Get the required buffer size.
+  winpath_size =
+    cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(), nullptr, 0);
+  if (winpath_size <= 0) {
+    return cygpath;
+  }
+
+  winpath_chars.assign(static_cast<size_t>(winpath_size) + 1, '\0');
+
+  winpath_size = cygwin_conv_path(CCP_POSIX_TO_WIN_A, cygpath.c_str(),
+                                  winpath_chars.data(), winpath_size);
+  if (winpath_size < 0) {
+    return cygpath;
+  }
+
+  return cmSystemTools::TrimWhitespace(winpath_chars.data());
+}
+#else
+std::string CMakeToWixPath(const std::string& path)
+{
+  return path;
+}
+#endif

+ 12 - 0
Source/CPack/WiX/cmCMakeToWixPath.h

@@ -0,0 +1,12 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmCMakeToWixPath_h
+#define cmCMakeToWixPath_h
+
+#include "cmConfigure.h" //IWYU pragma: keep
+
+#include <string>
+
+std::string CMakeToWixPath(const std::string& cygpath);
+
+#endif // cmCMakeToWixPath_h

+ 31 - 10
Source/CPack/WiX/cmCPackWIXGenerator.cxx

@@ -22,7 +22,13 @@
 #include "cmsys/FStream.hxx"
 #include "cmsys/SystemTools.hxx"
 
-#include <rpc.h> // for GUID generation
+#ifdef _WIN32
+#include <rpc.h> // for GUID generation (windows only)
+#else
+#include <uuid/uuid.h> // for GUID generation (libuuid)
+#endif
+
+#include "cmCMakeToWixPath.h"
 
 cmCPackWIXGenerator::cmCPackWIXGenerator()
   : Patch(0)
@@ -110,7 +116,7 @@ bool cmCPackWIXGenerator::RunLightCommand(std::string const& objectFiles)
   std::ostringstream command;
   command << QuotePath(executable);
   command << " -nologo";
-  command << " -out " << QuotePath(packageFileNames.at(0));
+  command << " -out " << QuotePath(CMakeToWixPath(packageFileNames.at(0)));
 
   for (std::string const& ext : this->LightExtensions) {
     command << " -ext " << QuotePath(ext);
@@ -270,11 +276,12 @@ bool cmCPackWIXGenerator::PackageFilesImpl()
     std::string objectFilename =
       this->CPackTopLevel + "/" + uniqueBaseName + ".wixobj";
 
-    if (!RunCandleCommand(sourceFilename, objectFilename)) {
+    if (!RunCandleCommand(CMakeToWixPath(sourceFilename),
+                          CMakeToWixPath(objectFilename))) {
       return false;
     }
 
-    objectFiles << " " << QuotePath(objectFilename);
+    objectFiles << " " << QuotePath(CMakeToWixPath(objectFilename));
   }
 
   AppendUserSuppliedExtraObjects(objectFiles);
@@ -320,10 +327,10 @@ void cmCPackWIXGenerator::CreateWiXVariablesIncludeFile()
   CopyDefinition(includeFile, "CPACK_PACKAGE_VENDOR");
   CopyDefinition(includeFile, "CPACK_PACKAGE_NAME");
   CopyDefinition(includeFile, "CPACK_PACKAGE_VERSION");
-  CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF");
-  CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON");
-  CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER");
-  CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG");
+  CopyDefinition(includeFile, "CPACK_WIX_LICENSE_RTF", DefinitionType::PATH);
+  CopyDefinition(includeFile, "CPACK_WIX_PRODUCT_ICON", DefinitionType::PATH);
+  CopyDefinition(includeFile, "CPACK_WIX_UI_BANNER", DefinitionType::PATH);
+  CopyDefinition(includeFile, "CPACK_WIX_UI_DIALOG", DefinitionType::PATH);
   SetOptionIfNotSet("CPACK_WIX_PROGRAM_MENU_FOLDER",
                     GetOption("CPACK_PACKAGE_NAME"));
   CopyDefinition(includeFile, "CPACK_WIX_PROGRAM_MENU_FOLDER");
@@ -390,11 +397,16 @@ void cmCPackWIXGenerator::CreateWiXProductFragmentIncludeFile()
 }
 
 void cmCPackWIXGenerator::CopyDefinition(cmWIXSourceWriter& source,
-                                         std::string const& name)
+                                         std::string const& name,
+                                         DefinitionType type)
 {
   const char* value = GetOption(name.c_str());
   if (value) {
-    AddDefinition(source, name, value);
+    if (type == DefinitionType::PATH) {
+      AddDefinition(source, name, CMakeToWixPath(value));
+    } else {
+      AddDefinition(source, name, value);
+    }
   }
 }
 
@@ -966,6 +978,7 @@ std::string cmCPackWIXGenerator::GetArchitecture() const
 
 std::string cmCPackWIXGenerator::GenerateGUID()
 {
+#ifdef _WIN32
   UUID guid;
   UuidCreate(&guid);
 
@@ -975,6 +988,14 @@ std::string cmCPackWIXGenerator::GenerateGUID()
   std::string result =
     cmsys::Encoding::ToNarrow(reinterpret_cast<wchar_t*>(tmp));
   RpcStringFreeW(&tmp);
+#else
+  uuid_t guid;
+  char guid_ch[37] = { 0 };
+
+  uuid_generate(guid);
+  uuid_unparse(guid, guid_ch);
+  std::string result = guid_ch;
+#endif
 
   return cmSystemTools::UpperCase(result);
 }

+ 8 - 1
Source/CPack/WiX/cmCPackWIXGenerator.h

@@ -48,6 +48,12 @@ private:
   typedef std::map<std::string, size_t> ambiguity_map_t;
   typedef std::set<std::string> extension_set_t;
 
+  enum class DefinitionType
+  {
+    STRING,
+    PATH
+  };
+
   bool InitializeWiXConfiguration();
 
   bool PackageFilesImpl();
@@ -58,7 +64,8 @@ private:
 
   void CreateWiXProductFragmentIncludeFile();
 
-  void CopyDefinition(cmWIXSourceWriter& source, std::string const& name);
+  void CopyDefinition(cmWIXSourceWriter& source, std::string const& name,
+                      DefinitionType type = DefinitionType::STRING);
 
   void AddDefinition(cmWIXSourceWriter& source, std::string const& name,
                      std::string const& value);

+ 3 - 1
Source/CPack/WiX/cmWIXFilesSourceWriter.cxx

@@ -11,6 +11,8 @@
 
 #include "cm_sys_stat.h"
 
+#include "cmCMakeToWixPath.h"
+
 cmWIXFilesSourceWriter::cmWIXFilesSourceWriter(cmCPackLog* logger,
                                                std::string const& filename,
                                                GuidType componentGuidType)
@@ -139,7 +141,7 @@ std::string cmWIXFilesSourceWriter::EmitComponentFile(
   patch.ApplyFragment(componentId, *this);
   BeginElement("File");
   AddAttribute("Id", fileId);
-  AddAttribute("Source", filePath);
+  AddAttribute("Source", CMakeToWixPath(filePath));
   AddAttribute("KeyPath", "yes");
 
   mode_t fileMode = 0;

+ 2 - 2
Source/CPack/cmCPackGeneratorFactory.cxx

@@ -40,7 +40,7 @@
 #include "cmCPackRPMGenerator.h"
 #endif
 
-#ifdef _WIN32
+#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
 #include "WiX/cmCPackWIXGenerator.h"
 #endif
 
@@ -87,7 +87,7 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
     this->RegisterGenerator("7Z", "7-Zip file format",
                             cmCPack7zGenerator::CreateGenerator);
   }
-#ifdef _WIN32
+#if defined(_WIN32) || (defined(__CYGWIN__) && defined(HAVE_LIBUUID))
   if (cmCPackWIXGenerator::CanGenerate()) {
     this->RegisterGenerator("WIX", "MSI file format via WiX tools",
                             cmCPackWIXGenerator::CreateGenerator);

+ 85 - 0
Source/Modules/FindLibUUID.cmake

@@ -0,0 +1,85 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#[=======================================================================[.rst:
+FindLibUUID
+------------
+
+Find LibUUID include directory and library.
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+An :ref:`imported target <Imported targets>` named
+``LibUUID::LibUUID`` is provided if LibUUID has been found.
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+This module defines the following variables:
+
+``LibUUID_FOUND``
+  True if LibUUID was found, false otherwise.
+``LibUUID_INCLUDE_DIRS``
+  Include directories needed to include LibUUID headers.
+``LibUUID_LIBRARIES``
+  Libraries needed to link to LibUUID.
+
+Cache Variables
+^^^^^^^^^^^^^^^
+
+This module uses the following cache variables:
+
+``LibUUID_LIBRARY``
+  The location of the LibUUID library file.
+``LibUUID_INCLUDE_DIR``
+  The location of the LibUUID include directory containing ``uuid/uuid.h``.
+
+The cache variables should not be used by project code.
+They may be set by end users to point at LibUUID components.
+#]=======================================================================]
+
+#-----------------------------------------------------------------------------
+if(CYGWIN)
+  # Note: on current version of Cygwin, linking to libuuid.dll.a doesn't
+  #       import the right symbols sometimes. Fix this by linking directly
+  #       to the DLL that provides the symbols, instead.
+  set(old_suffixes ${CMAKE_FIND_LIBRARY_SUFFIXES})
+  set(CMAKE_FIND_LIBRARY_SUFFIXES .dll)
+  find_library(LibUUID_LIBRARY
+    NAMES cyguuid-1.dll
+    )
+  set(CMAKE_FIND_LIBRARY_SUFFIXES ${old_suffixes})
+else()
+  find_library(LibUUID_LIBRARY
+    NAMES uuid
+    )
+endif()
+mark_as_advanced(LibUUID_LIBRARY)
+
+find_path(LibUUID_INCLUDE_DIR
+  NAMES uuid/uuid.h
+  )
+mark_as_advanced(LibUUID_INCLUDE_DIR)
+
+#-----------------------------------------------------------------------------
+include(${CMAKE_CURRENT_LIST_DIR}/../../Modules/FindPackageHandleStandardArgs.cmake)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUUID
+  FOUND_VAR LibUUID_FOUND
+  REQUIRED_VARS LibUUID_LIBRARY LibUUID_INCLUDE_DIR
+  )
+set(LIBUUID_FOUND ${LibUUID_FOUND})
+
+#-----------------------------------------------------------------------------
+# Provide documented result variables and targets.
+if(LibUUID_FOUND)
+  set(LibUUID_INCLUDE_DIRS ${LibUUID_INCLUDE_DIR})
+  set(LibUUID_LIBRARIES ${LibUUID_LIBRARY})
+  if(NOT TARGET LibUUID::LibUUID)
+    add_library(LibUUID::LibUUID UNKNOWN IMPORTED)
+    set_target_properties(LibUUID::LibUUID PROPERTIES
+      IMPORTED_LOCATION "${LibUUID_LIBRARY}"
+      INTERFACE_INCLUDE_DIRECTORIES "${LibUUID_INCLUDE_DIRS}"
+      )
+  endif()
+endif()