# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2.0, # as published by the Free Software Foundation. # # This program is also distributed with certain software (including # but not limited to OpenSSL) that is licensed under separate terms, # as designated in a particular file or component or in included license # documentation. The authors of MySQL hereby grant you an additional # permission to link the program and your derivative works with the # separately licensed software that they have included with MySQL. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License, version 2.0, for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # This is a reimplementation of parts of packaging/WiX/create_msi.cmake to make it # work with a MySQL Cluster install. # Directories and files which are part of the install, but which should be # ignored when creating the wxs. # Make it failfast # CMP0010 - Bad variable reference syntax is an error. CMAKE_POLICY(SET CMP0010 NEW) SET(EXCLUDE_DIRS bin/debug data/test lib/plugin/debug mysql-test scripts sql-bench) # Files installed by the selected components, but which nevertheless must # be exluded from the wxs. Used through get_include() macro below SET(EXCLUDE_FILES bin/echo.exe bin/mysqld-debug.exe bin/replace.exe lib/debug/mysqlserver.lib lib/mysqlserver.lib lib/mysqlservices.lib ) # Debug tracing enabled by setting DEBUG_ variable # Cannot be a macro because of http://public.kitware.com/Bug/view.php?id=5389 SET(DEBUG_ $ENV{WIX_DEBUG}) FUNCTION(DBG s) IF(DEBUG_) MESSAGE(STATUS "DBG: ${s}") ENDIF(DEBUG_) ENDFUNCTION(DBG) # Provide rm -f -like functionality # Note that because of http://public.kitware.com/Bug/view.php?id=5389 ${f} must be # a CMake path. A native Windows path will not work. MACRO(RMF f) IF(EXISTS ${f}) FILE(REMOVE ${f}) ENDIF() ENDMACRO(RMF) # Simplify test for exclusion # Note that because of http://public.kitware.com/Bug/view.php?id=5389 ${path} must be # a CMake path. A native Windows path will not work. MACRO(GET_INCLUDE var path) SET(${var} YES) FILE(RELATIVE_PATH rel ${CGRP_ABS} ${path}) IF(IS_DIRECTORY ${path}) LIST(FIND EXCLUDE_DIRS ${rel} res) IF(NOT res EQUAL -1) DBG("gi: excluding directory: ${rel}") SET(${var} NO) ENDIF() ELSE() LIST(FIND EXCLUDE_FILES ${rel} res) IF(NOT res EQUAL -1 OR rel MATCHES "\\.pdb") DBG("gi: excluding file: ${rel}") SET(${var} NO) ENDIF() ENDIF() ENDMACRO(GET_INCLUDE) # Provide ++-like functionality for numeric variables MACRO(INCR var) MATH(EXPR ${var} "${${var}} + 1") ENDMACRO(INCR) # Export a local variable to the parent scope MACRO(TO_PARENT var) SET(${var} ${${var}} PARENT_SCOPE) ENDMACRO(TO_PARENT) # First argument is variable. Appends all follwing arguments to that variable. # Cannot be a macro because of http://public.kitware.com/Bug/view.php?id=5389 FUNCTION(SAPPEND_VA var) SET(acc ${${var}}) FOREACH(a ${ARGN}) SET(acc "${acc}${a}") ENDFOREACH() SET(${var} ${acc} PARENT_SCOPE) ENDFUNCTION(SAPPEND_VA) # FUNCTION WIX_DESCRIBE_DIRS: Traverse empty dummy directory structure to create wxs-xml describing the desired install-layout. # # Describing the directory structure is made a bit tricky by the fact that a component-based # install, as done by _create_cmake.msi, will (and needs to) create a separate directory for each # component. Inside each component directory there is a normal bin, lib, share, ... hierarchy for # that component. But when creating the wxs-xml description all the subdirs # found in the various component directories must merged into one tree. Describing this merged virtual # tree in xml is difficult, e.g. when encountering the share directory for the first component an # xml tag for this directory is created. But before the end-tag can be insterted all of the # subdirectories of share must be added. But other components may add other directories under share, # so no end tags can be inserted until the entire installation has been traversed. In create_msi.cmake # this was handled by creating the merged directory tree with empty directories while traversing the # component-based installation, and then create the wxs-xml for the directories from this tree of # empty directories. Since _create_msi.cmake also leaves behind this directory tree it can be used to # simplify the logic of the WIX_DESCRIBE_DIRS function. # Args: # dir - directory to describe the members of # prefix - indentation space # Globals: # DIR_LIST - list of relative directories encountered. Index in list is the directorys wxs xml id # CPACK_WIX_DIRECTORIES - aggregated wxs xml describing the directory structure FUNCTION(WIX_DESCRIBE_DIRS dir prefix) SET(DIR_LIST ${DIR_LIST}) # Bring into local scope SET(CPACK_WIX_DIRECTORIES ${CPACK_WIX_DIRECTORIES}) FILE(GLOB dlist ${dir}/*) FOREACH(d ${dlist}) FILE(RELATIVE_PATH rpd ${DIRS_TREE} ${d}) DBG("WIX_DESCRIBE_DIRS: Processing ${rpd}") LIST(LENGTH DIR_LIST id) LIST(APPEND DIR_LIST ${rpd}) GET_FILENAME_COMPONENT(name ${d} NAME) SAPPEND_VA(CPACK_WIX_DIRECTORIES "${prefix}\n") WIX_DESCRIBE_DIRS(${d} " ${prefix}") SAPPEND_VA(CPACK_WIX_DIRECTORIES "${prefix} \n") ENDFOREACH() TO_PARENT(CPACK_WIX_DIRECTORIES) TO_PARENT(DIR_LIST) ENDFUNCTION(WIX_DESCRIBE_DIRS) # FUNCTION WIX_DESCRIBE_COMPONENTS: Traverse files in each cpack install component directory and # create wxs-xml descriptions for each wix-component, (a wix-component is a file or group of files, # which is not the same as a cpack install component. The latter is a wix component group). # # This is essentially a re-implementation of the same functionality in create_msi.cmake, # but with one crucial difference: Where create_msi.cmake tries to create a 1-to-1 mapping between the # (relative) file/directory name and its wxs-xml id, this function uses numeric ids. Trying to convert # filenames into ids causes a number of problems: # 1) Not all characters that are legal in filenames are legal in wxs-xml identifiers # 2) The old solution of mapping all illegal characters to '_' can (and does for some files in # the Python installation) yield non-unique ids. This is illegal. # 3) wxs-xml ids can only be 72 characters long. The old solution of # truncating is error-prone as fewer characters are permitted as the first character of an id. # (create_msi.cmake also has bugs where a truncated id is combined with additional character to # produce an id that is still longer than 72 characters. # Using numeric ids elliminates these problems but the fact that the id cannot be obtained from the # file/directory name creates additional challenges. E.g. the id of a file's parent directory could previously be # obtained from the directory portion of the filename. Now this id is not known until the wxs-xml # for the directories have been created, and even then the ids are buried in the generated xml. # The solution is to store the directorry name (relative to the component directory) in a list, # and use the directory's index in this list as the id. The directories must be traversed first # to populate the list. FUNCTION(WIX_DESCRIBE_COMPONENTS dir prefix) SET(CPACK_WIX_COMPONENT_GROUPS ${CPACK_WIX_COMPONENT_GROUPS}) # Bring into local scope FILE(RELATIVE_PATH rpdname ${CGRP_ABS} ${dir}) IF(NOT rpdname) SET(rpdname INSTALLDIR) ENDIF() SET(exe_list) SET(non_dir_list) FILE(GLOB all_files ${dir}/*) FOREACH(f ${all_files}) GET_INCLUDE(inc ${f}) IF(inc) IF(IS_DIRECTORY ${f}) WIX_DESCRIBE_COMPONENTS(${f} " ${prefix}") ELSE() GET_FILENAME_COMPONENT(f_ext "${f}" EXT) IF(f_ext MATCHES ".exe" OR f_ext MATCHES ".dll") LIST(APPEND exe_list ${f}) ELSE() LIST(APPEND non_dir_list ${f}) ENDIF() ENDIF() ENDIF(inc) ENDFOREACH() IF(non_dir_list OR exe_list) LIST(FIND DIR_LIST ${rpdname} dix) IF(dix EQUAL -1) MESSAGE(FATAL_ERROR "Unable to locate ${rpdname} (${dir}) in DIR_LIST") ENDIF() IF(dix EQUAL 0) SET(d_id INSTALLDIR) ELSE() SET(d_id "D${dix}") ENDIF() SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix}\n") FOREACH(exe ${exe_list}) INCR(id) SET(cid "${CGRP_NAME}.F${id}") FILE(RELATIVE_PATH rpexename ${CGRP_ABS} ${exe}) DBG("F${id}: ${rpexename}") FILE(TO_NATIVE_PATH ${exe} exe_native) SAPPEND_VA(CPACK_WIX_COMPONENT_GROUPS " \n") SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix} \n" "${prefix} \n" "${prefix} \n") ENDFOREACH() IF(non_dir_list) EXECUTE_PROCESS(COMMAND uuidgen -c OUTPUT_VARIABLE guid OUTPUT_STRIP_TRAILING_WHITESPACE) SET(cid "${CGRP_NAME}.${d_id}.files") SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix} \n") FOREACH(non_dir ${non_dir_list}) INCR(id) FILE(RELATIVE_PATH rpnondirname ${CGRP_ABS} ${non_dir}) FILE(TO_NATIVE_PATH ${non_dir} non_dir_native) DBG("F${id}: ${rpnondirname}") SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix} \n") ENDFOREACH() SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix} \n") SAPPEND_VA(CPACK_WIX_COMPONENT_GROUPS " \n") ENDIF(non_dir_list) SAPPEND_VA(CPACK_WIX_COMPONENTS "${prefix} \n") ENDIF(non_dir_list OR exe_list) TO_PARENT(id) TO_PARENT(CPACK_WIX_COMPONENT_GROUPS) TO_PARENT(CPACK_WIX_COMPONENTS) ENDFUNCTION(WIX_DESCRIBE_COMPONENTS) # Main script # Describe directories by traversing empty directory tree left by _create_msi.cmake. # Populate DIR_LIST with directory names relatvie to component group directory SET(CPACK_WIX_DIRECTORIES "\n") SET(DIR_LIST INSTALLDIR) GET_FILENAME_COMPONENT(DIRS_TREE ./dirs ABSOLUTE) DBG("DIRS_TREE: ${DIRS_TREE}") WIX_DESCRIBE_DIRS(${DIRS_TREE} " ") IF(NOT DIR_LIST) MESSAGE(FATAL_ERROR "DIR_LIST is empty!") ENDIF() SAPPEND_VA(CPACK_WIX_DIRECTORIES " \n") # Describe the files of the installation. Top-level directories are the component groups # (which confusingly enough correspond to the COMPONENT argument of the cmake INSTALL command), so # WIX_DESCRIBE_COMPONENTS() is called for each group SET(id 0) SET(CPACK_WIX_COMPONENTS "\n") # To get indentation right SET(CPACK_WIX_COMPONENT_GROUPS "\n") # To get indentation right FILE(GLOB COMPGRP_LIST testinstall/*) FOREACH(cgrp ${COMPGRP_LIST}) GET_FILENAME_COMPONENT(CGRP_NAME ${cgrp} NAME) GET_FILENAME_COMPONENT(CGRP_ABS ${cgrp} ABSOLUTE) SAPPEND_VA(CPACK_WIX_COMPONENT_GROUPS " \n") WIX_DESCRIBE_COMPONENTS(${CGRP_ABS} " ") SAPPEND_VA(CPACK_WIX_COMPONENT_GROUPS " \n") ENDFOREACH() # Expand the remaining variables in the intermediate wxs.in to create the wxs CONFIGURE_FILE("${WXS_BASENAME}.wxs.in" "${WXS_BASENAME}.wxs" @ONLY)