This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  4330f10186e994b3a7b64729f8b4e64e10a30896 (commit)
       via  c4b1c0751d48c1c3b7ccf92f1306a0a162cd249e (commit)
       via  4c7154876622b7639c7f0907adfed52a980985f6 (commit)
       via  47c87cdd1ff61abb153b2b5e081532fa7f7465eb (commit)
       via  2ef966bc77e9efd036747ee9d6977e2f2c7e024d (commit)
       via  80914d88da3e5c997158fd3cc703a39b6673f780 (commit)
       via  3ced881db63a97eb402bd68be5e45298371f4519 (commit)
       via  4938abb6002cb60501a0da651059ca0aefeed24f (commit)
       via  42cc0644d5cc7a50ea2f65aa29b49f629ff17384 (commit)
       via  127094f2f0e444b78d224d933a28a8313e487d36 (commit)
      from  f4d4d5df5bb408bdfc4c572d801d24eae7f2016e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4330f10186e994b3a7b64729f8b4e64e10a30896
commit 4330f10186e994b3a7b64729f8b4e64e10a30896
Merge: c4b1c07 42cc064
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Tue Jul 3 14:56:25 2018 +0000
Commit:     Kitware Robot <kwro...@kitware.com>
CommitDate: Tue Jul 3 10:56:31 2018 -0400

    Merge topic 'safe_property'
    
    42cc0644d5 Autogen: Use default and remove custom GetSafeProperty functions
    127094f2f0 Add GetSafeProperty method to cmTarget, cmGeneratorTarget and 
cmSourceFile
    
    Acked-by: Kitware Robot <kwro...@kitware.com>
    Merge-request: !2185


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=c4b1c0751d48c1c3b7ccf92f1306a0a162cd249e
commit c4b1c0751d48c1c3b7ccf92f1306a0a162cd249e
Merge: f4d4d5d 4c71548
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Tue Jul 3 14:54:57 2018 +0000
Commit:     Kitware Robot <kwro...@kitware.com>
CommitDate: Tue Jul 3 10:55:06 2018 -0400

    Merge topic 'cpack-external'
    
    4c71548766 Help: Add release notes for CPack External generator
    47c87cdd1f Help: Add documentation for CPack External generator
    2ef966bc77 Testing: Add test for CPack External generator
    80914d88da CPack: Add "CPack External" generator
    3ced881db6 cmCPackGenerator: Store CPACK_INSTALL_CMAKE_PROJECTS in an 
internal field
    4938abb600 cmCPackGenerator: Refactor 
InstallProjectViaInstallCMakeProjects()
    
    Acked-by: Kitware Robot <kwro...@kitware.com>
    Merge-request: !2142


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4c7154876622b7639c7f0907adfed52a980985f6
commit 4c7154876622b7639c7f0907adfed52a980985f6
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Thu Jun 14 15:32:27 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    Help: Add release notes for CPack External generator

diff --git a/Help/release/dev/cpack-external.rst 
b/Help/release/dev/cpack-external.rst
new file mode 100644
index 0000000..fb9a061
--- /dev/null
+++ b/Help/release/dev/cpack-external.rst
@@ -0,0 +1,8 @@
+cpack-external
+--------------
+
+* CPack gained a new :cpack_gen:`CPack External Generator` which is used to
+  export the CPack metadata in a format that other software can understand. The
+  intention of this generator is to allow external packaging software to take
+  advantage of CPack's features when it may not be possible to use CPack for
+  the entire packaging process.

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=47c87cdd1ff61abb153b2b5e081532fa7f7465eb
commit 47c87cdd1ff61abb153b2b5e081532fa7f7465eb
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Fri Jun 22 13:16:41 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    Help: Add documentation for CPack External generator

diff --git a/Help/cpack_gen/external.rst b/Help/cpack_gen/external.rst
new file mode 100644
index 0000000..a69866d
--- /dev/null
+++ b/Help/cpack_gen/external.rst
@@ -0,0 +1,249 @@
+CPack External Generator
+------------------------
+
+CPack provides many generators to create packages for a variety of platforms
+and packaging systems. The intention is for CMake/CPack to be a complete
+end-to-end solution for building and packaging a software project. However, it
+may not always be possible to use CPack for the entire packaging process, due
+to either technical limitations or policies that require the use of certain
+tools. For this reason, CPack provides the "External" generator, which allows
+external packaging software to take advantage of some of the functionality
+provided by CPack, such as component installation and the dependency graph.
+
+The CPack External generator doesn't actually package any files. Instead, it
+generates a .json file containing the CPack internal metadata, which gives
+external software information on how to package the software. This metadata
+file contains a list of CPack components and component groups, the various
+options passed to :command:`cpack_add_component` and
+:command:`cpack_add_component_group`, the dependencies between the components
+and component groups, and various other options passed to CPack.
+
+Format
+^^^^^^
+
+The file produced by the CPack External generator is a .json file with an
+object as its root. This root object will always provide two fields:
+``formatVersionMajor`` and ``formatVersionMinor``, which are always integers
+that describe the output format of the generator. Backwards-compatible changes
+to the output format (for example, adding a new field that didn't exist before)
+cause the minor version to be incremented, and backwards-incompatible changes
+(for example, deleting a field or changing its meaning) cause the major version
+to be incremented and the minor version reset to 0. The format version is
+always of the format ``major.minor``. In other words, it always has exactly two
+parts, separated by a period.
+
+You can request one or more specific versions of the output format as described
+below with :variable:`CPACK_EXT_REQUESTED_VERSIONS`. The output format will
+have a major version that exactly matches the requested major version, and a
+minor version that is greater than or equal to the requested minor version. If
+no version is requested with :variable:`CPACK_EXT_REQUESTED_VERSIONS`, the
+latest known major version is used by default. Currently, the only supported
+format is 1.0, which is described below.
+
+Version 1.0
+***********
+
+In addition to the standard format fields, format version 1.0 provides the
+following fields in the root:
+
+``components``
+  The ``components`` field is an object with component names as the keys and
+  objects describing the components as the values. The component objects have
+  the following fields:
+
+  ``name``
+    The name of the component. This is always the same as the key in the
+    ``components`` object.
+
+  ``displayName``
+    The value of the ``DISPLAY_NAME`` field passed to
+    :command:`cpack_add_component`.
+
+  ``description``
+    The value of the ``DESCRIPTION`` field passed to
+    :command:`cpack_add_component`.
+
+  ``isHidden``
+    True if ``HIDDEN`` was passed to :command:`cpack_add_component`, false if
+    it was not.
+
+  ``isRequired``
+    True if ``REQUIRED`` was passed to :command:`cpack_add_component`, false if
+    it was not.
+
+  ``isDisabledByDefault``
+    True if ``DISABLED`` was passed to :command:`cpack_add_component`, false if
+    it was not.
+
+  ``group``
+    Only present if ``GROUP`` was passed to :command:`cpack_add_component`. If
+    so, this field is a string value containing the component's group.
+
+  ``dependencies``
+    An array of components the component depends on. This contains the values
+    in the ``DEPENDS`` argument passed to :command:`cpack_add_component`. If no
+    ``DEPENDS`` argument was passed, this is an empty list.
+
+  ``installationTypes``
+    An array of installation types the component is part of. This contains the
+    values in the ``INSTALL_TYPES`` argument passed to
+    :command:`cpack_add_component`. If no ``INSTALL_TYPES`` argument was
+    passed, this is an empty list.
+
+  ``isDownloaded``
+    True if ``DOWNLOADED`` was passed to :command:`cpack_add_component`, false
+    if it was not.
+
+  ``archiveFile``
+    The name of the archive file passed with the ``ARCHIVE_FILE`` argument to
+    :command:`cpack_add_component`. If no ``ARCHIVE_FILE`` argument was passed,
+    this is an empty string.
+
+``componentGroups``
+  The ``componentGroups`` field is an object with component group names as the
+  keys and objects describing the component groups as the values. The component
+  group objects have the following fields:
+
+  ``name``
+    The name of the component group. This is always the same as the key in the
+    ``componentGroups`` object.
+
+  ``displayName``
+    The value of the ``DISPLAY_NAME`` field passed to
+    :command:`cpack_add_component_group`.
+
+  ``description``
+    The value of the ``DESCRIPTION`` field passed to
+    :command:`cpack_add_component_group`.
+
+  ``parentGroup``
+    Only present if ``PARENT_GROUP`` was passed to
+    :command:`cpack_add_component_group`. If so, this field is a string value
+    containing the component group's parent group.
+
+  ``isExpandedByDefault``
+    True if ``EXPANDED`` was passed to :command:`cpack_add_component_group`,
+    false if it was not.
+
+  ``isBold``
+    True if ``BOLD_TITLE`` was passed to :command:`cpack_add_component_group`,
+    false if it was not.
+
+  ``components``
+    An array of names of components that are direct members of the group
+    (components that have this group as their ``GROUP``). Components of
+    subgroups are not included.
+
+  ``subgroups``
+    An array of names of component groups that are subgroups of the group
+    (groups that have this group as their ``PARENT_GROUP``).
+
+``installationTypes``
+  The ``installationTypes`` field is an object with installation type names as
+  the keys and objects describing the installation types as the values. The
+  installation type objects have the following fields:
+
+  ``name``
+    The name of the installation type. This is always the same as the key in
+    the ``installationTypes`` object.
+
+  ``displayName``
+    The value of the ``DISPLAY_NAME`` field passed to
+    :command:`cpack_add_install_type`.
+
+  ``index``
+    The integer index of the installation type in the list.
+
+``projects``
+  The ``projects`` field is an array of objects describing CMake projects which
+  comprise the CPack project. The values in this field are derived from
+  :variable:`CPACK_INSTALL_CMAKE_PROJECTS`. In most cases, this will be only a
+  single project. The project objects have the following fields:
+
+  ``projectName``
+    The project name passed to :variable:`CPACK_INSTALL_CMAKE_PROJECTS`.
+
+  ``component``
+    The name of the component or component set which comprises the project.
+
+  ``directory``
+    The build directory of the CMake project. This is the directory which
+    contains the ``cmake_install.cmake`` script.
+
+  ``subDirectory``
+    The subdirectory to install the project into inside the CPack package.
+
+``packageName``
+  The package name given in :variable:`CPACK_PACKAGE_NAME`. Only present if
+  this option is set.
+
+``packageVersion``
+  The package version given in :variable:`CPACK_PACKAGE_VERSION`. Only present
+  if this option is set.
+
+``packageDescriptionFile``
+  The package description file given in
+  :variable:`CPACK_PACKAGE_DESCRIPTION_FILE`. Only present if this option is
+  set.
+
+``packageDescriptionSummary``
+  The package description summary given in
+  :variable:`CPACK_PACKAGE_DESCRIPTION_SUMMARY`. Only present if this option is
+  set.
+
+``buildConfig``
+  The build configuration given to CPack with the ``-C`` option. Only present
+  if this option is set.
+
+``defaultDirectoryPermissions``
+  The default directory permissions given in
+  :variable:`CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS`. Only present if this
+  option is set.
+
+``setDestdir``
+  True if :variable:`CPACK_SET_DESTDIR` is true, false if it is not.
+
+``packagingInstallPrefix``
+  The install prefix given in :variable:`CPACK_PACKAGING_INSTALL_PREFIX`. Only
+  present if :variable:`CPACK_SET_DESTDIR` is true.
+
+``stripFiles``
+  True if :variable:`CPACK_STRIP_FILES` is true, false if it is not.
+
+``warnOnAbsoluteInstallDestination``
+  True if :variable:`CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION` is true, false
+  if it is not.
+
+``errorOnAbsoluteInstallDestination``
+  True if :variable:`CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION` is true,
+  false if it is not.
+
+Variables specific to CPack External generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. variable:: CPACK_EXT_REQUESTED_VERSIONS
+
+  This variable is used to request a specific version of the CPack External
+  generator. It is a list of ``major.minor`` values, separated by semicolons.
+
+  If this variable is set to a non-empty value, the CPack External generator
+  will iterate through each item in the list to search for a version that it
+  knows how to generate. Requested versions should be listed in order of
+  descending preference by the client software, as the first matching version
+  in the list will be generated.
+
+  The generator knows how to generate the version if it has a versioned
+  generator whose major version exactly matches the requested major version,
+  and whose minor version is greater than or equal to the requested minor
+  version. For example, if ``CPACK_EXT_REQUESTED_VERSIONS`` contains 1.0, and
+  the CPack External generator knows how to generate 1.1, it will generate 1.1.
+  If the generator doesn't know how to generate a version in the list, it skips
+  the version and looks at the next one. If it doesn't know how to generate any
+  of the requested versions, an error is thrown.
+
+  If this variable is not set, or is empty, the CPack External generator will
+  generate the highest major and minor version that it knows how to generate.
+
+  If an invalid version is encountered in ``CPACK_EXT_REQUESTED_VERSIONS`` (one
+  that doesn't match ``major.minor``, where ``major`` and ``minor`` are
+  integers), it is ignored.
diff --git a/Help/manual/cpack-generators.7.rst 
b/Help/manual/cpack-generators.7.rst
index 4614b1c..ade9149 100644
--- a/Help/manual/cpack-generators.7.rst
+++ b/Help/manual/cpack-generators.7.rst
@@ -18,6 +18,7 @@ Generators
    /cpack_gen/cygwin
    /cpack_gen/deb
    /cpack_gen/dmg
+   /cpack_gen/external
    /cpack_gen/freebsd
    /cpack_gen/ifw
    /cpack_gen/nsis

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=2ef966bc77e9efd036747ee9d6977e2f2c7e024d
commit 2ef966bc77e9efd036747ee9d6977e2f2c7e024d
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Mon Jun 11 15:33:23 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    Testing: Add test for CPack External generator
    
    This test case ensures that the CPack External generator produces
    the proper .json file, and also ensures that the version negotation
    with CPACK_EXT_REQUESTED_VERSIONS works properly.

diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index daf3940..dcc7c98 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -422,7 +422,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
   add_RunCMake_test(ctest_labels_for_subprojects)
 endif()
 
-add_RunCMake_test_group(CPack "DEB;RPM;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ")
+add_RunCMake_test_group(CPack "DEB;RPM;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;Ext")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
 add_RunCMake_test(AutoExportDll)
diff --git a/Tests/RunCMake/CPack/Ext/Helpers.cmake 
b/Tests/RunCMake/CPack/Ext/Helpers.cmake
new file mode 100644
index 0000000..2c67e06
--- /dev/null
+++ b/Tests/RunCMake/CPack/Ext/Helpers.cmake
@@ -0,0 +1,31 @@
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO 
RESULT_VAR)
+  set(${RESULT_VAR} "${NAME}-${VERSION}-*.json" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+  set("${RESULT_VAR}" "" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+  set("${CONTENT_VAR}" "" PARENT_SCOPE)
+endfunction()
+
+set(ALL_FILES_GLOB "*.json")
+
+function(check_ext_json EXPECTED_FILE ACTUAL_FILE)
+  file(READ "${EXPECTED_FILE}" _expected_regex)
+  file(READ "${ACTUAL_FILE}" _actual_contents)
+
+  string(REGEX REPLACE "\n+$" "" _expected_regex "${_expected_regex}")
+  string(REGEX REPLACE "\n+$" "" _actual_contents "${_actual_contents}")
+
+  if(NOT "${_actual_contents}" MATCHES "${_expected_regex}")
+    message(FATAL_ERROR
+      "Output JSON does not match expected regex.\n"
+      "Expected regex:\n"
+      "${_expected_regex}\n"
+      "Actual output:\n"
+      "${_actual_contents}\n"
+    )
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/Ext/Prerequirements.cmake 
b/Tests/RunCMake/CPack/Ext/Prerequirements.cmake
new file mode 100644
index 0000000..e69de29
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake 
b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 4b7f146..bc25b12 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -18,7 +18,7 @@ run_cpack_test(GENERATE_SHLIBS_LDCONFIG "DEB" true 
"COMPONENT")
 run_cpack_test(INSTALL_SCRIPTS "RPM" false "COMPONENT")
 run_cpack_test(LONG_FILENAMES "DEB" false "MONOLITHIC")
 run_cpack_test_subtests(MAIN_COMPONENT "invalid;found" "RPM" false "COMPONENT")
-run_cpack_test(MINIMAL "RPM;DEB;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ" false 
"MONOLITHIC;COMPONENT")
+run_cpack_test(MINIMAL "RPM;DEB;7Z;TBZ2;TGZ;TXZ;TZ;ZIP;STGZ;Ext" false 
"MONOLITHIC;COMPONENT")
 run_cpack_test_subtests(PACKAGE_CHECKSUM 
"invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false "MONOLITHIC")
 run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM" false "COMPONENT")
 run_cpack_test(PER_COMPONENT_FIELDS "RPM;DEB" false "COMPONENT")
@@ -31,3 +31,4 @@ run_cpack_test(USER_FILELIST "RPM" false "MONOLITHIC")
 run_cpack_test(MD5SUMS "DEB" false "MONOLITHIC;COMPONENT")
 run_cpack_test(CPACK_INSTALL_SCRIPT "ZIP" false "MONOLITHIC")
 run_cpack_test(DEB_PACKAGE_VERSION_BACK_COMPATIBILITY "DEB" false 
"MONOLITHIC;COMPONENT")
+run_cpack_test_subtests(EXT 
"none;good;good_multi;bad_major;bad_minor;invalid_good;invalid_bad" "Ext" false 
"MONOLITHIC;COMPONENT")
diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake 
b/Tests/RunCMake/CPack/VerifyResult.cmake
index 1f5ab87..af12d37 100644
--- a/Tests/RunCMake/CPack/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/VerifyResult.cmake
@@ -56,8 +56,12 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
         set(EXPECTED_FILE_CONTENT_${file_no_} 
"${EXPECTED_FILE_CONTENT_${file_no_}_LIST}")
         toExpectedContentList("${file_no_}" 
"EXPECTED_FILE_CONTENT_${file_no_}")
 
-        list(SORT PACKAGE_CONTENT)
-        list(SORT EXPECTED_FILE_CONTENT_${file_no_})
+        if(NOT PACKAGE_CONTENT STREQUAL "")
+          list(SORT PACKAGE_CONTENT)
+        endif()
+        if(NOT EXPECTED_FILE_CONTENT_${file_no_} STREQUAL "")
+          list(SORT EXPECTED_FILE_CONTENT_${file_no_})
+        endif()
 
         if(PACKAGE_CONTENT STREQUAL EXPECTED_FILE_CONTENT_${file_no_})
           set(expected_content_list TRUE)
diff --git a/Tests/RunCMake/CPack/tests/EXT/ExpectedFiles.cmake 
b/Tests/RunCMake/CPack/tests/EXT/ExpectedFiles.cmake
new file mode 100644
index 0000000..2634111
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/ExpectedFiles.cmake
@@ -0,0 +1,6 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)$")
+  set(EXPECTED_FILES_COUNT "1")
+  set(EXPECTED_FILE_CONTENT_1_LIST 
"/share;/share/cpack-test;/share/cpack-test/f1.txt;/share/cpack-test/f2.txt;/share/cpack-test/f3.txt;/share/cpack-test/f4.txt")
+else()
+  set(EXPECTED_FILES_COUNT "0")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXT/VerifyResult.cmake 
b/Tests/RunCMake/CPack/tests/EXT/VerifyResult.cmake
new file mode 100644
index 0000000..97b74f7
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/VerifyResult.cmake
@@ -0,0 +1,3 @@
+if(RunCMake_SUBTEST_SUFFIX MATCHES "^(none|good(_multi)?|invalid_good)")
+  check_ext_json("${src_dir}/tests/EXT/expected-json-1.0.txt" 
"${FOUND_FILE_1}")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/EXT/bad_major-stderr.txt 
b/Tests/RunCMake/CPack/tests/EXT/bad_major-stderr.txt
new file mode 100644
index 0000000..372c5e4
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/bad_major-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
+  Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExt\.cmake
+CPack Error: Cannot initialize the generator Ext
diff --git a/Tests/RunCMake/CPack/tests/EXT/bad_minor-stderr.txt 
b/Tests/RunCMake/CPack/tests/EXT/bad_minor-stderr.txt
new file mode 100644
index 0000000..372c5e4
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/bad_minor-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
+  Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExt\.cmake
+CPack Error: Cannot initialize the generator Ext
diff --git a/Tests/RunCMake/CPack/tests/EXT/expected-json-1.0.txt 
b/Tests/RunCMake/CPack/tests/EXT/expected-json-1.0.txt
new file mode 100644
index 0000000..b96cf0b
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/expected-json-1.0.txt
@@ -0,0 +1,176 @@
+^\{
+  "componentGroups" :[ ]
+  \{
+    "f12" :[ ]
+    \{
+      "components" :[ ]
+      \[
+        "f1",
+        "f2"
+      \],
+      "description" : "Component group for files 1 and 2",
+      "displayName" : "Files 1 and 2",
+      "isBold" : false,
+      "isExpandedByDefault" : false,
+      "name" : "f12",
+      "parentGroup" : "f1234",
+      "subgroups" : \[\]
+    \},
+    "f1234" :[ ]
+    \{
+      "components" : \[\],
+      "description" : "Component group for all files",
+      "displayName" : "Files 1-4",
+      "isBold" : false,
+      "isExpandedByDefault" : false,
+      "name" : "f1234",
+      "subgroups" :[ ]
+      \[
+        "f12",
+        "f34"
+      \]
+    \},
+    "f34" :[ ]
+    \{
+      "components" :[ ]
+      \[
+        "f3",
+        "f4"
+      \],
+      "description" : "Component group for files 3 and 4",
+      "displayName" : "Files 3 and 4",
+      "isBold" : false,
+      "isExpandedByDefault" : false,
+      "name" : "f34",
+      "parentGroup" : "f1234",
+      "subgroups" : \[\]
+    \}
+  \},
+  "components" :[ ]
+  \{
+    "f1" :[ ]
+    \{
+      "archiveFile" : "",
+      "dependencies" : \[\],
+      "description" : "Component for file 1",
+      "displayName" : "File 1",
+      "group" : "f12",
+      "installationTypes" :[ ]
+      \[
+        "full",
+        "f12"
+      \],
+      "isDisabledByDefault" : false,
+      "isDownloaded" : false,
+      "isHidden" : false,
+      "isRequired" : false,
+      "name" : "f1"
+    \},
+    "f2" :[ ]
+    \{
+      "archiveFile" : "",
+      "dependencies" :[ ]
+      \[
+        "f1"
+      \],
+      "description" : "Component for file 2",
+      "displayName" : "File 2",
+      "group" : "f12",
+      "installationTypes" :[ ]
+      \[
+        "full",
+        "f12"
+      \],
+      "isDisabledByDefault" : false,
+      "isDownloaded" : false,
+      "isHidden" : false,
+      "isRequired" : false,
+      "name" : "f2"
+    \},
+    "f3" :[ ]
+    \{
+      "archiveFile" : "",
+      "dependencies" :[ ]
+      \[
+        "f1",
+        "f2"
+      \],
+      "description" : "Component for file 3",
+      "displayName" : "File 3",
+      "group" : "f34",
+      "installationTypes" :[ ]
+      \[
+        "full"
+      \],
+      "isDisabledByDefault" : false,
+      "isDownloaded" : false,
+      "isHidden" : false,
+      "isRequired" : false,
+      "name" : "f3"
+    \},
+    "f4" :[ ]
+    \{
+      "archiveFile" : "",
+      "dependencies" :[ ]
+      \[
+        "f2",
+        "f3",
+        "f1"
+      \],
+      "description" : "Component for file 4",
+      "displayName" : "File 4",
+      "group" : "f34",
+      "installationTypes" :[ ]
+      \[
+        "full"
+      \],
+      "isDisabledByDefault" : false,
+      "isDownloaded" : false,
+      "isHidden" : false,
+      "isRequired" : false,
+      "name" : "f4"
+    \}
+  \},
+  "errorOnAbsoluteInstallDestination" : false,
+  "formatVersionMajor" : 1,
+  "formatVersionMinor" : 0,
+  "installationTypes" :[ ]
+  \{
+    "f12" :[ ]
+    \{
+      "displayName" : "Only files 1 and 2",
+      "index" : 2,
+      "name" : "f12"
+    \},
+    "full" :[ ]
+    \{
+      "displayName" : "Full installation",
+      "index" : 1,
+      "name" : "full"
+    \}
+  \},
+  "packageDescriptionFile" : ".*/Templates/CPack\.GenericDescription\.txt",
+  "packageDescriptionSummary" : 
"EXT-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type 
built using CMake",
+  "packageName" : "ext",
+  "packageVersion" : "0\.1\.1",
+  "projects" :[ ]
+  \[
+    \{
+      "component" : "ALL",
+      "components" :[ ]
+      \[
+        "f1",
+        "f2",
+        "f3",
+        "f4"
+      \],
+      "directory" : 
".*/Tests/RunCMake/Ext/CPack/EXT-build-(none|good(_multi)?|invalid_good)-subtest",
+      "installationTypes" : \[\],
+      "projectName" : 
"EXT-(none|good(_multi)?|invalid_good)-subtest-(MONOLITHIC|COMPONENT)-type",
+      "subDirectory" : "/"
+    \}
+  \],
+  "setDestdir" : false,
+  "stripFiles" : false,
+  "warnOnAbsoluteInstallDestination" : false
+\}$
diff --git a/Tests/RunCMake/CPack/tests/EXT/invalid_bad-stderr.txt 
b/Tests/RunCMake/CPack/tests/EXT/invalid_bad-stderr.txt
new file mode 100644
index 0000000..372c5e4
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/invalid_bad-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at .*/Modules/Internal/CPack/CPackExt\.cmake:[0-9]+ \(message\):
+  Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS
+
+
+CPack Error: Error while executing CPackExt\.cmake
+CPack Error: Cannot initialize the generator Ext
diff --git a/Tests/RunCMake/CPack/tests/EXT/test.cmake 
b/Tests/RunCMake/CPack/tests/EXT/test.cmake
new file mode 100644
index 0000000..6bd3cb8
--- /dev/null
+++ b/Tests/RunCMake/CPack/tests/EXT/test.cmake
@@ -0,0 +1,83 @@
+include(CPackComponent)
+
+if(RunCMake_SUBTEST_SUFFIX STREQUAL "none")
+  unset(CPACK_EXT_REQUESTED_VERSIONS)
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good")
+  set(CPACK_EXT_REQUESTED_VERSIONS "1.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "good_multi")
+  set(CPACK_EXT_REQUESTED_VERSIONS "1.0;2.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_major")
+  set(CPACK_EXT_REQUESTED_VERSIONS "2.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "bad_minor")
+  set(CPACK_EXT_REQUESTED_VERSIONS "1.1")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_good")
+  set(CPACK_EXT_REQUESTED_VERSIONS "1;1.0")
+elseif(RunCMake_SUBTEST_SUFFIX STREQUAL "invalid_bad")
+  set(CPACK_EXT_REQUESTED_VERSIONS "1")
+endif()
+
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" test1)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" test2)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" test3)
+file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" test4)
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f1.txt" DESTINATION 
share/cpack-test COMPONENT f1)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f2.txt" DESTINATION 
share/cpack-test COMPONENT f2)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f3.txt" DESTINATION 
share/cpack-test COMPONENT f3)
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/f4.txt" DESTINATION 
share/cpack-test COMPONENT f4)
+
+cpack_add_component(f1
+  DISPLAY_NAME "File 1"
+  DESCRIPTION "Component for file 1"
+  GROUP f12
+  INSTALL_TYPES full f12
+)
+
+cpack_add_component(f2
+  DISPLAY_NAME "File 2"
+  DESCRIPTION "Component for file 2"
+  GROUP f12
+  DEPENDS f1
+  INSTALL_TYPES full f12
+)
+
+cpack_add_component(f3
+  DISPLAY_NAME "File 3"
+  DESCRIPTION "Component for file 3"
+  GROUP f34
+  DEPENDS f1 f2
+  INSTALL_TYPES full
+)
+
+cpack_add_component(f4
+  DISPLAY_NAME "File 4"
+  DESCRIPTION "Component for file 4"
+  GROUP f34
+  DEPENDS f2 f3 f1
+  INSTALL_TYPES full
+)
+
+cpack_add_component_group(f12
+  DISPLAY_NAME "Files 1 and 2"
+  DESCRIPTION "Component group for files 1 and 2"
+  PARENT_GROUP f1234
+)
+
+cpack_add_component_group(f34
+  DISPLAY_NAME "Files 3 and 4"
+  DESCRIPTION "Component group for files 3 and 4"
+  PARENT_GROUP f1234
+)
+
+cpack_add_component_group(f1234
+  DISPLAY_NAME "Files 1-4"
+  DESCRIPTION "Component group for all files"
+)
+
+cpack_add_install_type(full
+  DISPLAY_NAME "Full installation"
+)
+
+cpack_add_install_type(f12
+  DISPLAY_NAME "Only files 1 and 2"
+)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=80914d88da3e5c997158fd3cc703a39b6673f780
commit 80914d88da3e5c997158fd3cc703a39b6673f780
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Fri Jun 8 15:14:10 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    CPack: Add "CPack External" generator
    
    This generator doesn't actually package the files. Instead, it
    provides a metadata JSON file that can be used by external packaging
    software to do its own packaging. This JSON file provides information
    about the components, component groups, installation types, and CMake
    projects.

diff --git a/Modules/Internal/CPack/CPackExt.cmake 
b/Modules/Internal/CPack/CPackExt.cmake
new file mode 100644
index 0000000..e52d978
--- /dev/null
+++ b/Modules/Internal/CPack/CPackExt.cmake
@@ -0,0 +1,53 @@
+# Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT "${CPACK_EXT_REQUESTED_VERSIONS}" STREQUAL "")
+  unset(_found_major)
+
+  foreach(_req_version IN LISTS CPACK_EXT_REQUESTED_VERSIONS)
+    if(_req_version MATCHES "^([0-9]+)\\.([0-9]+)$")
+      set(_req_major "${CMAKE_MATCH_1}")
+      set(_req_minor "${CMAKE_MATCH_2}")
+
+      foreach(_known_version IN LISTS CPACK_EXT_KNOWN_VERSIONS)
+        string(REGEX MATCH
+          "^([0-9]+)\\.([0-9]+)$"
+          _known_version_dummy
+          "${_known_version}"
+        )
+
+        set(_known_major "${CMAKE_MATCH_1}")
+        set(_known_minor "${CMAKE_MATCH_2}")
+
+        if(_req_major EQUAL _known_major AND NOT _known_minor LESS _req_minor)
+          set(_found_major "${_known_major}")
+          set(_found_minor "${_known_minor}")
+          break()
+        endif()
+      endforeach()
+
+      if(DEFINED _found_major)
+        break()
+      endif()
+    endif()
+  endforeach()
+
+  if(DEFINED _found_major)
+    set(CPACK_EXT_SELECTED_MAJOR "${_found_major}")
+    set(CPACK_EXT_SELECTED_MINOR "${_found_minor}")
+    set(CPACK_EXT_SELECTED_VERSION "${_found_major}.${_found_minor}")
+  else()
+    message(FATAL_ERROR
+      "Could not find a suitable version in CPACK_EXT_REQUESTED_VERSIONS"
+    )
+  endif()
+else()
+  list(GET CPACK_EXT_KNOWN_VERSIONS 0 CPACK_EXT_SELECTED_VERSION)
+  string(REGEX MATCH
+    "^([0-9]+)\\.([0-9]+)$"
+    _dummy
+    "${CPACK_EXT_SELECTED_VERSION}"
+  )
+  set(CPACK_EXT_SELECTED_MAJOR "${CMAKE_MATCH_1}")
+  set(CPACK_EXT_SELECTED_MINOR "${CMAKE_MATCH_2}")
+endif()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 6623ba4..0457984 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -886,6 +886,8 @@ include_directories(
 set(CPACK_SRCS
   CPack/cmCPackArchiveGenerator.cxx
   CPack/cmCPackComponentGroup.cxx
+  CPack/cmCPackDebGenerator.cxx
+  CPack/cmCPackExtGenerator.cxx
   CPack/cmCPackGeneratorFactory.cxx
   CPack/cmCPackGenerator.cxx
   CPack/cmCPackLog.cxx
@@ -898,7 +900,6 @@ set(CPACK_SRCS
   CPack/cmCPackTarCompressGenerator.cxx
   CPack/cmCPackZIPGenerator.cxx
   CPack/cmCPack7zGenerator.cxx
-  CPack/cmCPackDebGenerator.cxx
   )
 # CPack IFW generator
 set(CPACK_SRCS ${CPACK_SRCS}
diff --git a/Source/CPack/cmCPackExtGenerator.cxx 
b/Source/CPack/cmCPackExtGenerator.cxx
new file mode 100644
index 0000000..c36b098
--- /dev/null
+++ b/Source/CPack/cmCPackExtGenerator.cxx
@@ -0,0 +1,291 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmCPackExtGenerator.h"
+
+#include "cmAlgorithms.h"
+#include "cmCPackComponentGroup.h"
+#include "cmCPackLog.h"
+#include "cmSystemTools.h"
+
+#include "cm_jsoncpp_value.h"
+#include "cm_jsoncpp_writer.h"
+
+#include "cmsys/FStream.hxx"
+
+#include <utility>
+#include <vector>
+
+int cmCPackExtGenerator::InitializeInternal()
+{
+  this->SetOption("CPACK_EXT_KNOWN_VERSIONS", "1.0");
+
+  if (!this->ReadListFile("Internal/CPack/CPackExt.cmake")) {
+    cmCPackLogger(cmCPackLog::LOG_ERROR,
+                  "Error while executing CPackExt.cmake" << std::endl);
+    return 0;
+  }
+
+  std::string major = this->GetOption("CPACK_EXT_SELECTED_MAJOR");
+  if (major == "1") {
+    this->Generator = cm::make_unique<cmCPackExtVersion1Generator>(this);
+  }
+
+  return this->Superclass::InitializeInternal();
+}
+
+int cmCPackExtGenerator::PackageFiles()
+{
+  Json::StreamWriterBuilder builder;
+  builder["indentation"] = "  ";
+
+  std::string filename = "package.json";
+  if (!this->packageFileNames.empty()) {
+    filename = this->packageFileNames[0];
+  }
+
+  cmsys::ofstream fout(filename.c_str());
+  std::unique_ptr<Json::StreamWriter> jout(builder.newStreamWriter());
+
+  Json::Value root(Json::objectValue);
+
+  if (!this->Generator->WriteToJSON(root)) {
+    return 0;
+  }
+
+  if (jout->write(root, &fout)) {
+    return 0;
+  }
+
+  return 1;
+}
+
+bool cmCPackExtGenerator::SupportsComponentInstallation() const
+{
+  return true;
+}
+
+int cmCPackExtGenerator::InstallProjectViaInstallCommands(
+  bool setDestDir, const std::string& tempInstallDirectory)
+{
+  (void)setDestDir;
+  (void)tempInstallDirectory;
+  return 1;
+}
+
+int cmCPackExtGenerator::InstallProjectViaInstallScript(
+  bool setDestDir, const std::string& tempInstallDirectory)
+{
+  (void)setDestDir;
+  (void)tempInstallDirectory;
+  return 1;
+}
+
+int cmCPackExtGenerator::InstallProjectViaInstalledDirectories(
+  bool setDestDir, const std::string& tempInstallDirectory,
+  const mode_t* default_dir_mode)
+{
+  (void)setDestDir;
+  (void)tempInstallDirectory;
+  (void)default_dir_mode;
+  return 1;
+}
+
+int cmCPackExtGenerator::RunPreinstallTarget(
+  const std::string& installProjectName, const std::string& installDirectory,
+  cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
+{
+  (void)installProjectName;
+  (void)installDirectory;
+  (void)globalGenerator;
+  (void)buildConfig;
+  return 1;
+}
+
+int cmCPackExtGenerator::InstallCMakeProject(
+  bool setDestDir, const std::string& installDirectory,
+  const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
+  const std::string& component, bool componentInstall,
+  const std::string& installSubDirectory, const std::string& buildConfig,
+  std::string& absoluteDestFiles)
+{
+  (void)setDestDir;
+  (void)installDirectory;
+  (void)baseTempInstallDirectory;
+  (void)default_dir_mode;
+  (void)component;
+  (void)componentInstall;
+  (void)installSubDirectory;
+  (void)buildConfig;
+  (void)absoluteDestFiles;
+  return 1;
+}
+
+cmCPackExtGenerator::cmCPackExtVersionGenerator::cmCPackExtVersionGenerator(
+  cmCPackExtGenerator* parent)
+  : Parent(parent)
+{
+}
+
+int cmCPackExtGenerator::cmCPackExtVersionGenerator::WriteVersion(
+  Json::Value& root)
+{
+  root["formatVersionMajor"] = this->GetVersionMajor();
+  root["formatVersionMinor"] = this->GetVersionMinor();
+
+  return 1;
+}
+
+int cmCPackExtGenerator::cmCPackExtVersionGenerator::WriteToJSON(
+  Json::Value& root)
+{
+  if (!this->WriteVersion(root)) {
+    return 0;
+  }
+
+  const char* packageName = this->Parent->GetOption("CPACK_PACKAGE_NAME");
+  if (packageName) {
+    root["packageName"] = packageName;
+  }
+
+  const char* packageVersion =
+    this->Parent->GetOption("CPACK_PACKAGE_VERSION");
+  if (packageVersion) {
+    root["packageVersion"] = packageVersion;
+  }
+
+  const char* packageDescriptionFile =
+    this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_FILE");
+  if (packageDescriptionFile) {
+    root["packageDescriptionFile"] = packageDescriptionFile;
+  }
+
+  const char* packageDescriptionSummary =
+    this->Parent->GetOption("CPACK_PACKAGE_DESCRIPTION_SUMMARY");
+  if (packageDescriptionSummary) {
+    root["packageDescriptionSummary"] = packageDescriptionSummary;
+  }
+
+  const char* buildConfigCstr = this->Parent->GetOption("CPACK_BUILD_CONFIG");
+  if (buildConfigCstr) {
+    root["buildConfig"] = buildConfigCstr;
+  }
+
+  const char* defaultDirectoryPermissions =
+    this->Parent->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+  if (defaultDirectoryPermissions && *defaultDirectoryPermissions) {
+    root["defaultDirectoryPermissions"] = defaultDirectoryPermissions;
+  }
+  if (cmSystemTools::IsInternallyOn(
+        this->Parent->GetOption("CPACK_SET_DESTDIR"))) {
+    root["setDestdir"] = true;
+    root["packagingInstallPrefix"] =
+      this->Parent->GetOption("CPACK_PACKAGING_INSTALL_PREFIX");
+  } else {
+    root["setDestdir"] = false;
+  }
+
+  root["stripFiles"] =
+    !cmSystemTools::IsOff(this->Parent->GetOption("CPACK_STRIP_FILES"));
+  root["warnOnAbsoluteInstallDestination"] =
+    this->Parent->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION");
+  root["errorOnAbsoluteInstallDestination"] =
+    this->Parent->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION");
+
+  Json::Value& projects = root["projects"] = Json::Value(Json::arrayValue);
+  for (auto& project : this->Parent->CMakeProjects) {
+    Json::Value jsonProject(Json::objectValue);
+
+    jsonProject["projectName"] = project.ProjectName;
+    jsonProject["component"] = project.Component;
+    jsonProject["directory"] = project.Directory;
+    jsonProject["subDirectory"] = project.SubDirectory;
+
+    Json::Value& installationTypes = jsonProject["installationTypes"] =
+      Json::Value(Json::arrayValue);
+    for (auto& installationType : project.InstallationTypes) {
+      installationTypes.append(installationType->Name);
+    }
+
+    Json::Value& components = jsonProject["components"] =
+      Json::Value(Json::arrayValue);
+    for (auto& component : project.Components) {
+      components.append(component->Name);
+    }
+
+    projects.append(jsonProject);
+  }
+
+  Json::Value& installationTypes = root["installationTypes"] =
+    Json::Value(Json::objectValue);
+  for (auto& installationType : this->Parent->InstallationTypes) {
+    Json::Value& jsonInstallationType =
+      installationTypes[installationType.first] =
+        Json::Value(Json::objectValue);
+
+    jsonInstallationType["name"] = installationType.second.Name;
+    jsonInstallationType["displayName"] = installationType.second.DisplayName;
+    jsonInstallationType["index"] = installationType.second.Index;
+  }
+
+  Json::Value& components = root["components"] =
+    Json::Value(Json::objectValue);
+  for (auto& component : this->Parent->Components) {
+    Json::Value& jsonComponent = components[component.first] =
+      Json::Value(Json::objectValue);
+
+    jsonComponent["name"] = component.second.Name;
+    jsonComponent["displayName"] = component.second.DisplayName;
+    if (component.second.Group) {
+      jsonComponent["group"] = component.second.Group->Name;
+    }
+    jsonComponent["isRequired"] = component.second.IsRequired;
+    jsonComponent["isHidden"] = component.second.IsHidden;
+    jsonComponent["isDisabledByDefault"] =
+      component.second.IsDisabledByDefault;
+    jsonComponent["isDownloaded"] = component.second.IsDownloaded;
+    jsonComponent["description"] = component.second.Description;
+    jsonComponent["archiveFile"] = component.second.ArchiveFile;
+
+    Json::Value& cmpInstallationTypes = jsonComponent["installationTypes"] =
+      Json::Value(Json::arrayValue);
+    for (auto& installationType : component.second.InstallationTypes) {
+      cmpInstallationTypes.append(installationType->Name);
+    }
+
+    Json::Value& dependencies = jsonComponent["dependencies"] =
+      Json::Value(Json::arrayValue);
+    for (auto& dep : component.second.Dependencies) {
+      dependencies.append(dep->Name);
+    }
+  }
+
+  Json::Value& groups = root["componentGroups"] =
+    Json::Value(Json::objectValue);
+  for (auto& group : this->Parent->ComponentGroups) {
+    Json::Value& jsonGroup = groups[group.first] =
+      Json::Value(Json::objectValue);
+
+    jsonGroup["name"] = group.second.Name;
+    jsonGroup["displayName"] = group.second.DisplayName;
+    jsonGroup["description"] = group.second.Description;
+    jsonGroup["isBold"] = group.second.IsBold;
+    jsonGroup["isExpandedByDefault"] = group.second.IsExpandedByDefault;
+    if (group.second.ParentGroup) {
+      jsonGroup["parentGroup"] = group.second.ParentGroup->Name;
+    }
+
+    Json::Value& subgroups = jsonGroup["subgroups"] =
+      Json::Value(Json::arrayValue);
+    for (auto& subgroup : group.second.Subgroups) {
+      subgroups.append(subgroup->Name);
+    }
+
+    Json::Value& groupComponents = jsonGroup["components"] =
+      Json::Value(Json::arrayValue);
+    for (auto& component : group.second.Components) {
+      groupComponents.append(component->Name);
+    }
+  }
+
+  return 1;
+}
diff --git a/Source/CPack/cmCPackExtGenerator.h 
b/Source/CPack/cmCPackExtGenerator.h
new file mode 100644
index 0000000..fa12d7f
--- /dev/null
+++ b/Source/CPack/cmCPackExtGenerator.h
@@ -0,0 +1,86 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmCPackExtGenerator_h
+#define cmCPackExtGenerator_h
+
+#include "cmCPackGenerator.h"
+#include "cm_sys_stat.h"
+
+#include <memory>
+#include <string>
+
+class cmGlobalGenerator;
+namespace Json {
+class Value;
+}
+
+/** \class cmCPackExtGenerator
+ * \brief A generator for CPack External packaging tools
+ */
+class cmCPackExtGenerator : public cmCPackGenerator
+{
+public:
+  cmCPackTypeMacro(cmCPackExtGenerator, cmCPackGenerator);
+
+  const char* GetOutputExtension() override { return ".json"; }
+
+protected:
+  int InitializeInternal() override;
+
+  int PackageFiles() override;
+
+  bool SupportsComponentInstallation() const override;
+
+  int InstallProjectViaInstallCommands(
+    bool setDestDir, const std::string& tempInstallDirectory) override;
+  int InstallProjectViaInstallScript(
+    bool setDestDir, const std::string& tempInstallDirectory) override;
+  int InstallProjectViaInstalledDirectories(
+    bool setDestDir, const std::string& tempInstallDirectory,
+    const mode_t* default_dir_mode) override;
+
+  int RunPreinstallTarget(const std::string& installProjectName,
+                          const std::string& installDirectory,
+                          cmGlobalGenerator* globalGenerator,
+                          const std::string& buildConfig) override;
+  int InstallCMakeProject(bool setDestDir, const std::string& installDirectory,
+                          const std::string& baseTempInstallDirectory,
+                          const mode_t* default_dir_mode,
+                          const std::string& component, bool componentInstall,
+                          const std::string& installSubDirectory,
+                          const std::string& buildConfig,
+                          std::string& absoluteDestFiles) override;
+
+private:
+  class cmCPackExtVersionGenerator
+  {
+  public:
+    cmCPackExtVersionGenerator(cmCPackExtGenerator* parent);
+
+    virtual ~cmCPackExtVersionGenerator() = default;
+
+    virtual int WriteToJSON(Json::Value& root);
+
+  protected:
+    virtual int GetVersionMajor() = 0;
+    virtual int GetVersionMinor() = 0;
+
+    int WriteVersion(Json::Value& root);
+
+    cmCPackExtGenerator* Parent;
+  };
+
+  class cmCPackExtVersion1Generator : public cmCPackExtVersionGenerator
+  {
+  public:
+    using cmCPackExtVersionGenerator::cmCPackExtVersionGenerator;
+
+  protected:
+    int GetVersionMajor() override { return 1; }
+    int GetVersionMinor() override { return 0; }
+  };
+
+  std::unique_ptr<cmCPackExtVersionGenerator> Generator;
+};
+
+#endif
diff --git a/Source/CPack/cmCPackGeneratorFactory.cxx 
b/Source/CPack/cmCPackGeneratorFactory.cxx
index d47e5ed..8ef24f7 100644
--- a/Source/CPack/cmCPackGeneratorFactory.cxx
+++ b/Source/CPack/cmCPackGeneratorFactory.cxx
@@ -12,6 +12,7 @@
 #  include "cmCPackFreeBSDGenerator.h"
 #endif
 #include "cmCPackDebGenerator.h"
+#include "cmCPackExtGenerator.h"
 #include "cmCPackGenerator.h"
 #include "cmCPackLog.h"
 #include "cmCPackNSISGenerator.h"
@@ -110,6 +111,10 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
     this->RegisterGenerator("NuGet", "NuGet packages",
                             cmCPackNuGetGenerator::CreateGenerator);
   }
+  if (cmCPackExtGenerator::CanGenerate()) {
+    this->RegisterGenerator("Ext", "CPack External packages",
+                            cmCPackExtGenerator::CreateGenerator);
+  }
 #ifdef __APPLE__
   if (cmCPackDragNDropGenerator::CanGenerate()) {
     this->RegisterGenerator("DragNDrop", "Mac OSX Drag And Drop",

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=3ced881db63a97eb402bd68be5e45298371f4519
commit 3ced881db63a97eb402bd68be5e45298371f4519
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Fri Jun 8 15:08:36 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    cmCPackGenerator: Store CPACK_INSTALL_CMAKE_PROJECTS in an internal field
    
    By storing this information in an internal field in the class, it
    can be used later on by generators that need it.

diff --git a/Source/CPack/cmCPackComponentGroup.h 
b/Source/CPack/cmCPackComponentGroup.h
index f2907db..bb980d7 100644
--- a/Source/CPack/cmCPackComponentGroup.h
+++ b/Source/CPack/cmCPackComponentGroup.h
@@ -143,4 +143,29 @@ public:
   std::vector<cmCPackComponentGroup*> Subgroups;
 };
 
+/** \class cmCPackInstallCMakeProject
+ * \brief A single quadruplet from the CPACK_INSTALL_CMAKE_PROJECTS variable.
+ */
+class cmCPackInstallCMakeProject
+{
+public:
+  /// The directory of the CMake project.
+  std::string Directory;
+
+  /// The name of the CMake project.
+  std::string ProjectName;
+
+  /// The name of the component (or component set) to install.
+  std::string Component;
+
+  /// The subdirectory to install into.
+  std::string SubDirectory;
+
+  /// The list of installation types.
+  std::vector<cmCPackInstallationType*> InstallationTypes;
+
+  /// The list of components.
+  std::vector<cmCPackComponent*> Components;
+};
+
 #endif
diff --git a/Source/CPack/cmCPackGenerator.cxx 
b/Source/CPack/cmCPackGenerator.cxx
index 6924873..7014676 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -545,9 +545,13 @@ int 
cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       ++it;
       std::string installProjectName = *it;
       ++it;
-      std::string installComponent = *it;
+      cmCPackInstallCMakeProject project;
+
+      project.Directory = installDirectory;
+      project.ProjectName = installProjectName;
+      project.Component = *it;
       ++it;
-      std::string installSubDirectory = *it;
+      project.SubDirectory = *it;
 
       std::vector<std::string> componentsVector;
 
@@ -562,30 +566,32 @@ int 
cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
           !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
         // Determine the installation types for this project (if provided).
         std::string installTypesVar = "CPACK_" +
-          cmSystemTools::UpperCase(installComponent) + "_INSTALL_TYPES";
+          cmSystemTools::UpperCase(project.Component) + "_INSTALL_TYPES";
         const char* installTypes = this->GetOption(installTypesVar);
         if (installTypes && *installTypes) {
           std::vector<std::string> installTypesVector;
           cmSystemTools::ExpandListArgument(installTypes, installTypesVector);
           for (std::string const& installType : installTypesVector) {
-            this->GetInstallationType(installProjectName, installType);
+            project.InstallationTypes.push_back(
+              this->GetInstallationType(project.ProjectName, installType));
           }
         }
 
         // Determine the set of components that will be used in this project
         std::string componentsVar =
-          "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(installComponent);
+          "CPACK_COMPONENTS_" + cmSystemTools::UpperCase(project.Component);
         const char* components = this->GetOption(componentsVar);
         if (components && *components) {
           cmSystemTools::ExpandListArgument(components, componentsVector);
           for (std::string const& comp : componentsVector) {
-            GetComponent(installProjectName, comp);
+            project.Components.push_back(
+              this->GetComponent(project.ProjectName, comp));
           }
           componentInstall = true;
         }
       }
       if (componentsVector.empty()) {
-        componentsVector.push_back(installComponent);
+        componentsVector.push_back(project.Component);
       }
 
       const char* buildConfigCstr = this->GetOption("CPACK_BUILD_CONFIG");
@@ -605,7 +611,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       // on windows.
       cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
 
-      if (!this->RunPreinstallTarget(installProjectName, installDirectory,
+      if (!this->RunPreinstallTarget(project.ProjectName, project.Directory,
                                      globalGenerator, buildConfig)) {
         return 0;
       }
@@ -613,17 +619,19 @@ int 
cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       delete globalGenerator;
 
       cmCPackLogger(cmCPackLog::LOG_OUTPUT,
-                    "- Install project: " << installProjectName << std::endl);
+                    "- Install project: " << project.ProjectName << std::endl);
 
       // Run the installation for each component
       for (std::string const& component : componentsVector) {
         if (!this->InstallCMakeProject(
-              setDestDir, installDirectory, baseTempInstallDirectory,
+              setDestDir, project.Directory, baseTempInstallDirectory,
               default_dir_mode, component, componentInstall,
-              installSubDirectory, buildConfig, absoluteDestFiles)) {
+              project.SubDirectory, buildConfig, absoluteDestFiles)) {
           return 0;
         }
       }
+
+      this->CMakeProjects.push_back(project);
     }
   }
   this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index 9128f36..c13c649 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -283,6 +283,7 @@ protected:
    */
   std::vector<std::string> files;
 
+  std::vector<cmCPackInstallCMakeProject> CMakeProjects;
   std::map<std::string, cmCPackInstallationType> InstallationTypes;
   /**
    * The set of components.

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=4938abb6002cb60501a0da651059ca0aefeed24f
commit 4938abb6002cb60501a0da651059ca0aefeed24f
Author:     Kyle Edwards <kyle.edwa...@kitware.com>
AuthorDate: Fri Jun 8 10:48:25 2018 -0400
Commit:     Kyle Edwards <kyle.edwa...@kitware.com>
CommitDate: Mon Jul 2 09:51:02 2018 -0400

    cmCPackGenerator: Refactor InstallProjectViaInstallCMakeProjects()
    
    This refactoring will allow cmCPackExtGenerator to skip the install
    step while still gathering up information about the CPack components
    and groups. Besides, this function was too long, and needed to be
    broken up anyway.

diff --git a/Source/CPack/cmCPackGenerator.cxx 
b/Source/CPack/cmCPackGenerator.cxx
index f15445b..6924873 100644
--- a/Source/CPack/cmCPackGenerator.cxx
+++ b/Source/CPack/cmCPackGenerator.cxx
@@ -548,7 +548,6 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       std::string installComponent = *it;
       ++it;
       std::string installSubDirectory = *it;
-      std::string installFile = installDirectory + "/cmake_install.cmake";
 
       std::vector<std::string> componentsVector;
 
@@ -559,7 +558,7 @@ int cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
        *    - the user did not request Monolithic install
        *      (this works at CPack time too)
        */
-      if (this->SupportsComponentInstallation() &
+      if (this->SupportsComponentInstallation() &&
           !(this->IsOn("CPACK_MONOLITHIC_INSTALL"))) {
         // Determine the installation types for this project (if provided).
         std::string installTypesVar = "CPACK_" +
@@ -606,38 +605,11 @@ int 
cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
       // on windows.
       cmSystemTools::SetForceUnixPaths(globalGenerator->GetForceUnixPaths());
 
-      // Does this generator require pre-install?
-      if (const char* preinstall =
-            globalGenerator->GetPreinstallTargetName()) {
-        std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
-          preinstall, buildConfig, "", false);
-        cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                      "- Install command: " << buildCommand << std::endl);
-        cmCPackLogger(cmCPackLog::LOG_OUTPUT,
-                      "- Run preinstall target for: " << installProjectName
-                                                      << std::endl);
-        std::string output;
-        int retVal = 1;
-        bool resB = cmSystemTools::RunSingleCommand(
-          buildCommand.c_str(), &output, &output, &retVal,
-          installDirectory.c_str(), this->GeneratorVerbose,
-          cmDuration::zero());
-        if (!resB || retVal) {
-          std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
-          tmpFile += "/PreinstallOutput.log";
-          cmGeneratedFileStream ofs(tmpFile.c_str());
-          ofs << "# Run command: " << buildCommand << std::endl
-              << "# Directory: " << installDirectory << std::endl
-              << "# Output:" << std::endl
-              << output << std::endl;
-          cmCPackLogger(cmCPackLog::LOG_ERROR,
-                        "Problem running install command: "
-                          << buildCommand << std::endl
-                          << "Please check " << tmpFile << " for errors"
-                          << std::endl);
-          return 0;
-        }
+      if (!this->RunPreinstallTarget(installProjectName, installDirectory,
+                                     globalGenerator, buildConfig)) {
+        return 0;
       }
+
       delete globalGenerator;
 
       cmCPackLogger(cmCPackLog::LOG_OUTPUT,
@@ -645,258 +617,302 @@ int 
cmCPackGenerator::InstallProjectViaInstallCMakeProjects(
 
       // Run the installation for each component
       for (std::string const& component : componentsVector) {
-        std::string tempInstallDirectory = baseTempInstallDirectory;
-        installComponent = component;
-        if (componentInstall) {
-          cmCPackLogger(cmCPackLog::LOG_OUTPUT,
-                        "-   Install component: " << installComponent
-                                                  << std::endl);
+        if (!this->InstallCMakeProject(
+              setDestDir, installDirectory, baseTempInstallDirectory,
+              default_dir_mode, component, componentInstall,
+              installSubDirectory, buildConfig, absoluteDestFiles)) {
+          return 0;
         }
+      }
+    }
+  }
+  this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
+                  absoluteDestFiles.c_str());
+  return 1;
+}
 
-        cmake cm(cmake::RoleScript);
-        cm.SetHomeDirectory("");
-        cm.SetHomeOutputDirectory("");
-        cm.GetCurrentSnapshot().SetDefaultDefinitions();
-        cm.AddCMakePaths();
-        cm.SetProgressCallback(cmCPackGeneratorProgress, this);
-        cm.SetTrace(this->Trace);
-        cm.SetTraceExpand(this->TraceExpand);
-        cmGlobalGenerator gg(&cm);
-        cmMakefile mf(&gg, cm.GetCurrentSnapshot());
-        if (!installSubDirectory.empty() && installSubDirectory != "/" &&
-            installSubDirectory != ".") {
-          tempInstallDirectory += installSubDirectory;
-        }
-        if (componentInstall) {
-          tempInstallDirectory += "/";
-          // Some CPack generators would rather chose
-          // the local installation directory suffix.
-          // Some (e.g. RPM) use
-          //  one install directory for each component **GROUP**
-          // instead of the default
-          //  one install directory for each component.
-          tempInstallDirectory +=
-            GetComponentInstallDirNameSuffix(installComponent);
-          if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
-            tempInstallDirectory += "/";
-            tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
-          }
-        }
+int cmCPackGenerator::RunPreinstallTarget(
+  const std::string& installProjectName, const std::string& installDirectory,
+  cmGlobalGenerator* globalGenerator, const std::string& buildConfig)
+{
+  // Does this generator require pre-install?
+  if (const char* preinstall = globalGenerator->GetPreinstallTargetName()) {
+    std::string buildCommand = globalGenerator->GenerateCMakeBuildCommand(
+      preinstall, buildConfig, "", false);
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "- Install command: " << buildCommand << std::endl);
+    cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+                  "- Run preinstall target for: " << installProjectName
+                                                  << std::endl);
+    std::string output;
+    int retVal = 1;
+    bool resB = cmSystemTools::RunSingleCommand(
+      buildCommand.c_str(), &output, &output, &retVal,
+      installDirectory.c_str(), this->GeneratorVerbose, cmDuration::zero());
+    if (!resB || retVal) {
+      std::string tmpFile = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+      tmpFile += "/PreinstallOutput.log";
+      cmGeneratedFileStream ofs(tmpFile.c_str());
+      ofs << "# Run command: " << buildCommand << std::endl
+          << "# Directory: " << installDirectory << std::endl
+          << "# Output:" << std::endl
+          << output << std::endl;
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Problem running install command: "
+                      << buildCommand << std::endl
+                      << "Please check " << tmpFile << " for errors"
+                      << std::endl);
+      return 0;
+    }
+  }
 
-        const char* default_dir_inst_permissions =
-          this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
-        if (default_dir_inst_permissions && *default_dir_inst_permissions) {
-          mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
-                           default_dir_inst_permissions);
-        }
+  return 1;
+}
 
-        if (!setDestDir) {
-          tempInstallDirectory += this->GetPackagingInstallPrefix();
-        }
+int cmCPackGenerator::InstallCMakeProject(
+  bool setDestDir, const std::string& installDirectory,
+  const std::string& baseTempInstallDirectory, const mode_t* default_dir_mode,
+  const std::string& component, bool componentInstall,
+  const std::string& installSubDirectory, const std::string& buildConfig,
+  std::string& absoluteDestFiles)
+{
+  std::string tempInstallDirectory = baseTempInstallDirectory;
+  std::string installFile = installDirectory + "/cmake_install.cmake";
 
-        if (setDestDir) {
-          // For DESTDIR based packaging, use the *project*
-          // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
-          // value of the project's CMAKE_INSTALL_PREFIX is sent in here as
-          // the value of the CPACK_INSTALL_PREFIX variable.
-          //
-          // If DESTDIR has been 'internally set ON' this means that
-          // the underlying CPack specific generator did ask for that
-          // In this case we may override CPACK_INSTALL_PREFIX with
-          // CPACK_PACKAGING_INSTALL_PREFIX
-          // I know this is tricky and awkward but it's the price for
-          // CPACK_SET_DESTDIR backward compatibility.
-          if (cmSystemTools::IsInternallyOn(
-                this->GetOption("CPACK_SET_DESTDIR"))) {
-            this->SetOption("CPACK_INSTALL_PREFIX",
-                            this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
-          }
-          std::string dir;
-          if (this->GetOption("CPACK_INSTALL_PREFIX")) {
-            dir += this->GetOption("CPACK_INSTALL_PREFIX");
-          }
-          mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
+  if (componentInstall) {
+    cmCPackLogger(cmCPackLog::LOG_OUTPUT,
+                  "-   Install component: " << component << std::endl);
+  }
 
-          cmCPackLogger(
-            cmCPackLog::LOG_DEBUG,
-            "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
-              << std::endl);
-          cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                        "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
-                                                              << std::endl);
-
-          // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
-          // exists:
-          //
-          if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) {
-            dir = tempInstallDirectory + dir;
-          } else {
-            dir = tempInstallDirectory + "/" + dir;
-          }
-          /*
-           *  We must re-set DESTDIR for each component
-           *  We must not add the CPACK_INSTALL_PREFIX part because
-           *  it will be added using the override of CMAKE_INSTALL_PREFIX
-           *  The main reason for this awkward trick is that
-           *  are using DESTDIR for 2 different reasons:
-           *     - Because it was asked by the CPack Generator or the user
-           *       using CPACK_SET_DESTDIR
-           *     - Because it was already used for component install
-           *       in order to put things in subdirs...
-           */
-          cmSystemTools::PutEnv(std::string("DESTDIR=") +
-                                tempInstallDirectory);
-          cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                        "- Creating directory: '" << dir << "'" << std::endl);
+  cmake cm(cmake::RoleScript);
+  cm.SetHomeDirectory("");
+  cm.SetHomeOutputDirectory("");
+  cm.GetCurrentSnapshot().SetDefaultDefinitions();
+  cm.AddCMakePaths();
+  cm.SetProgressCallback(cmCPackGeneratorProgress, this);
+  cm.SetTrace(this->Trace);
+  cm.SetTraceExpand(this->TraceExpand);
+  cmGlobalGenerator gg(&cm);
+  cmMakefile mf(&gg, cm.GetCurrentSnapshot());
+  if (!installSubDirectory.empty() && installSubDirectory != "/" &&
+      installSubDirectory != ".") {
+    tempInstallDirectory += installSubDirectory;
+  }
+  if (componentInstall) {
+    tempInstallDirectory += "/";
+    // Some CPack generators would rather chose
+    // the local installation directory suffix.
+    // Some (e.g. RPM) use
+    //  one install directory for each component **GROUP**
+    // instead of the default
+    //  one install directory for each component.
+    tempInstallDirectory += GetComponentInstallDirNameSuffix(component);
+    if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) {
+      tempInstallDirectory += "/";
+      tempInstallDirectory += this->GetOption("CPACK_PACKAGE_FILE_NAME");
+    }
+  }
 
-          if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
-            cmCPackLogger(
-              cmCPackLog::LOG_ERROR,
-              "Problem creating temporary directory: " << dir << std::endl);
-            return 0;
-          }
-        } else {
-          mf.AddDefinition("CMAKE_INSTALL_PREFIX",
-                           tempInstallDirectory.c_str());
+  const char* default_dir_inst_permissions =
+    this->GetOption("CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS");
+  if (default_dir_inst_permissions && *default_dir_inst_permissions) {
+    mf.AddDefinition("CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS",
+                     default_dir_inst_permissions);
+  }
 
-          if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
-                                                 default_dir_mode)) {
-            cmCPackLogger(cmCPackLog::LOG_ERROR,
-                          "Problem creating temporary directory: "
-                            << tempInstallDirectory << std::endl);
-            return 0;
-          }
+  if (!setDestDir) {
+    tempInstallDirectory += this->GetPackagingInstallPrefix();
+  }
 
-          cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                        "- Using non-DESTDIR install... (mf.AddDefinition)"
-                          << std::endl);
-          cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                        "- Setting CMAKE_INSTALL_PREFIX to '"
-                          << tempInstallDirectory << "'" << std::endl);
-        }
+  if (setDestDir) {
+    // For DESTDIR based packaging, use the *project*
+    // CMAKE_INSTALL_PREFIX underneath the tempInstallDirectory. The
+    // value of the project's CMAKE_INSTALL_PREFIX is sent in here as
+    // the value of the CPACK_INSTALL_PREFIX variable.
+    //
+    // If DESTDIR has been 'internally set ON' this means that
+    // the underlying CPack specific generator did ask for that
+    // In this case we may override CPACK_INSTALL_PREFIX with
+    // CPACK_PACKAGING_INSTALL_PREFIX
+    // I know this is tricky and awkward but it's the price for
+    // CPACK_SET_DESTDIR backward compatibility.
+    if (cmSystemTools::IsInternallyOn(this->GetOption("CPACK_SET_DESTDIR"))) {
+      this->SetOption("CPACK_INSTALL_PREFIX",
+                      this->GetOption("CPACK_PACKAGING_INSTALL_PREFIX"));
+    }
+    std::string dir;
+    if (this->GetOption("CPACK_INSTALL_PREFIX")) {
+      dir += this->GetOption("CPACK_INSTALL_PREFIX");
+    }
+    mf.AddDefinition("CMAKE_INSTALL_PREFIX", dir.c_str());
 
-        if (!buildConfig.empty()) {
-          mf.AddDefinition("BUILD_TYPE", buildConfig.c_str());
-        }
-        std::string installComponentLowerCase =
-          cmSystemTools::LowerCase(installComponent);
-        if (installComponentLowerCase != "all") {
-          mf.AddDefinition("CMAKE_INSTALL_COMPONENT",
-                           installComponent.c_str());
-        }
+    cmCPackLogger(
+      cmCPackLog::LOG_DEBUG,
+      "- Using DESTDIR + CPACK_INSTALL_PREFIX... (mf.AddDefinition)"
+        << std::endl);
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "- Setting CMAKE_INSTALL_PREFIX to '" << dir << "'"
+                                                        << std::endl);
+
+    // Make sure that DESTDIR + CPACK_INSTALL_PREFIX directory
+    // exists:
+    //
+    if (cmSystemTools::StringStartsWith(dir.c_str(), "/")) {
+      dir = tempInstallDirectory + dir;
+    } else {
+      dir = tempInstallDirectory + "/" + dir;
+    }
+    /*
+     *  We must re-set DESTDIR for each component
+     *  We must not add the CPACK_INSTALL_PREFIX part because
+     *  it will be added using the override of CMAKE_INSTALL_PREFIX
+     *  The main reason for this awkward trick is that
+     *  are using DESTDIR for 2 different reasons:
+     *     - Because it was asked by the CPack Generator or the user
+     *       using CPACK_SET_DESTDIR
+     *     - Because it was already used for component install
+     *       in order to put things in subdirs...
+     */
+    cmSystemTools::PutEnv(std::string("DESTDIR=") + tempInstallDirectory);
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "- Creating directory: '" << dir << "'" << std::endl);
 
-        // strip on TRUE, ON, 1, one or several file names, but not on
-        // FALSE, OFF, 0 and an empty string
-        if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) {
-          mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
-        }
-        // Remember the list of files before installation
-        // of the current component (if we are in component install)
-        std::string const& InstallPrefix = tempInstallDirectory;
-        std::vector<std::string> filesBefore;
-        std::string findExpr = tempInstallDirectory;
-        if (componentInstall) {
-          cmsys::Glob glB;
-          findExpr += "/*";
-          glB.RecurseOn();
-          glB.SetRecurseListDirs(true);
-          glB.FindFiles(findExpr);
-          filesBefore = glB.GetFiles();
-          std::sort(filesBefore.begin(), filesBefore.end());
-        }
+    if (!cmsys::SystemTools::MakeDirectory(dir, default_dir_mode)) {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Problem creating temporary directory: " << dir
+                                                             << std::endl);
+      return 0;
+    }
+  } else {
+    mf.AddDefinition("CMAKE_INSTALL_PREFIX", tempInstallDirectory.c_str());
 
-        // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
-        // then forward request to cmake_install.cmake script
-        if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
-          mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
-        }
-        // If current CPack generator does support
-        // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
-        // then ask cmake_install.cmake script to error out
-        // as soon as it occurs (before installing file)
-        if (!SupportsAbsoluteDestination() ||
-            this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
-          mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
-        }
-        // do installation
-        int res = mf.ReadListFile(installFile.c_str());
-        // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
-        // to CPack (may be used by generators like CPack RPM or DEB)
-        // in order to transparently handle ABSOLUTE PATH
-        if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
-          mf.AddDefinition(
-            "CPACK_ABSOLUTE_DESTINATION_FILES",
-            mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
-        }
+    if (!cmsys::SystemTools::MakeDirectory(tempInstallDirectory,
+                                           default_dir_mode)) {
+      cmCPackLogger(cmCPackLog::LOG_ERROR,
+                    "Problem creating temporary directory: "
+                      << tempInstallDirectory << std::endl);
+      return 0;
+    }
 
-        // Now rebuild the list of files after installation
-        // of the current component (if we are in component install)
-        if (componentInstall) {
-          cmsys::Glob glA;
-          glA.RecurseOn();
-          glA.SetRecurseListDirs(true);
-          glA.SetRecurseThroughSymlinks(false);
-          glA.FindFiles(findExpr);
-          std::vector<std::string> filesAfter = glA.GetFiles();
-          std::sort(filesAfter.begin(), filesAfter.end());
-          std::vector<std::string>::iterator diff;
-          std::vector<std::string> result(filesAfter.size());
-          diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
-                                     filesBefore.begin(), filesBefore.end(),
-                                     result.begin());
-
-          std::vector<std::string>::iterator fit;
-          std::string localFileName;
-          // Populate the File field of each component
-          for (fit = result.begin(); fit != diff; ++fit) {
-            localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
-            localFileName =
-              localFileName.substr(localFileName.find_first_not_of('/'));
-            Components[installComponent].Files.push_back(localFileName);
-            cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                          "Adding file <"
-                            << localFileName << "> to component <"
-                            << installComponent << ">" << std::endl);
-          }
-        }
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "- Using non-DESTDIR install... (mf.AddDefinition)"
+                    << std::endl);
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "- Setting CMAKE_INSTALL_PREFIX to '" << tempInstallDirectory
+                                                        << "'" << std::endl);
+  }
 
-        if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
-          if (!absoluteDestFiles.empty()) {
-            absoluteDestFiles += ";";
-          }
-          absoluteDestFiles +=
-            mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
-          cmCPackLogger(cmCPackLog::LOG_DEBUG,
-                        "Got some ABSOLUTE DESTINATION FILES: "
-                          << absoluteDestFiles << std::endl);
-          // define component specific var
-          if (componentInstall) {
-            std::string absoluteDestFileComponent =
-              std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
-              GetComponentInstallDirNameSuffix(installComponent);
-            if (nullptr != this->GetOption(absoluteDestFileComponent)) {
-              std::string absoluteDestFilesListComponent =
-                this->GetOption(absoluteDestFileComponent);
-              absoluteDestFilesListComponent += ";";
-              absoluteDestFilesListComponent +=
-                mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
-              this->SetOption(absoluteDestFileComponent,
-                              absoluteDestFilesListComponent.c_str());
-            } else {
-              this->SetOption(
-                absoluteDestFileComponent,
-                mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
-            }
-          }
-        }
-        if (cmSystemTools::GetErrorOccuredFlag() || !res) {
-          return 0;
-        }
+  if (!buildConfig.empty()) {
+    mf.AddDefinition("BUILD_TYPE", buildConfig.c_str());
+  }
+  std::string installComponentLowerCase = cmSystemTools::LowerCase(component);
+  if (installComponentLowerCase != "all") {
+    mf.AddDefinition("CMAKE_INSTALL_COMPONENT", component.c_str());
+  }
+
+  // strip on TRUE, ON, 1, one or several file names, but not on
+  // FALSE, OFF, 0 and an empty string
+  if (!cmSystemTools::IsOff(this->GetOption("CPACK_STRIP_FILES"))) {
+    mf.AddDefinition("CMAKE_INSTALL_DO_STRIP", "1");
+  }
+  // Remember the list of files before installation
+  // of the current component (if we are in component install)
+  std::string const& InstallPrefix = tempInstallDirectory;
+  std::vector<std::string> filesBefore;
+  std::string findExpr = tempInstallDirectory;
+  if (componentInstall) {
+    cmsys::Glob glB;
+    findExpr += "/*";
+    glB.RecurseOn();
+    glB.SetRecurseListDirs(true);
+    glB.FindFiles(findExpr);
+    filesBefore = glB.GetFiles();
+    std::sort(filesBefore.begin(), filesBefore.end());
+  }
+
+  // If CPack was asked to warn on ABSOLUTE INSTALL DESTINATION
+  // then forward request to cmake_install.cmake script
+  if (this->IsOn("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+    mf.AddDefinition("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
+  }
+  // If current CPack generator does support
+  // ABSOLUTE INSTALL DESTINATION or CPack has been asked for
+  // then ask cmake_install.cmake script to error out
+  // as soon as it occurs (before installing file)
+  if (!SupportsAbsoluteDestination() ||
+      this->IsOn("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")) {
+    mf.AddDefinition("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION", "1");
+  }
+  // do installation
+  int res = mf.ReadListFile(installFile.c_str());
+  // forward definition of CMAKE_ABSOLUTE_DESTINATION_FILES
+  // to CPack (may be used by generators like CPack RPM or DEB)
+  // in order to transparently handle ABSOLUTE PATH
+  if (mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES")) {
+    mf.AddDefinition("CPACK_ABSOLUTE_DESTINATION_FILES",
+                     mf.GetDefinition("CMAKE_ABSOLUTE_DESTINATION_FILES"));
+  }
+
+  // Now rebuild the list of files after installation
+  // of the current component (if we are in component install)
+  if (componentInstall) {
+    cmsys::Glob glA;
+    glA.RecurseOn();
+    glA.SetRecurseListDirs(true);
+    glA.SetRecurseThroughSymlinks(false);
+    glA.FindFiles(findExpr);
+    std::vector<std::string> filesAfter = glA.GetFiles();
+    std::sort(filesAfter.begin(), filesAfter.end());
+    std::vector<std::string>::iterator diff;
+    std::vector<std::string> result(filesAfter.size());
+    diff = std::set_difference(filesAfter.begin(), filesAfter.end(),
+                               filesBefore.begin(), filesBefore.end(),
+                               result.begin());
+
+    std::vector<std::string>::iterator fit;
+    std::string localFileName;
+    // Populate the File field of each component
+    for (fit = result.begin(); fit != diff; ++fit) {
+      localFileName = cmSystemTools::RelativePath(InstallPrefix, *fit);
+      localFileName =
+        localFileName.substr(localFileName.find_first_not_of('/'));
+      Components[component].Files.push_back(localFileName);
+      cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                    "Adding file <" << localFileName << "> to component <"
+                                    << component << ">" << std::endl);
+    }
+  }
+
+  if (nullptr != mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES")) {
+    if (!absoluteDestFiles.empty()) {
+      absoluteDestFiles += ";";
+    }
+    absoluteDestFiles += mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
+    cmCPackLogger(cmCPackLog::LOG_DEBUG,
+                  "Got some ABSOLUTE DESTINATION FILES: " << absoluteDestFiles
+                                                          << std::endl);
+    // define component specific var
+    if (componentInstall) {
+      std::string absoluteDestFileComponent =
+        std::string("CPACK_ABSOLUTE_DESTINATION_FILES") + "_" +
+        GetComponentInstallDirNameSuffix(component);
+      if (nullptr != this->GetOption(absoluteDestFileComponent)) {
+        std::string absoluteDestFilesListComponent =
+          this->GetOption(absoluteDestFileComponent);
+        absoluteDestFilesListComponent += ";";
+        absoluteDestFilesListComponent +=
+          mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES");
+        this->SetOption(absoluteDestFileComponent,
+                        absoluteDestFilesListComponent.c_str());
+      } else {
+        this->SetOption(absoluteDestFileComponent,
+                        mf.GetDefinition("CPACK_ABSOLUTE_DESTINATION_FILES"));
       }
     }
   }
-  this->SetOption("CPACK_ABSOLUTE_DESTINATION_FILES",
-                  absoluteDestFiles.c_str());
+  if (cmSystemTools::GetErrorOccuredFlag() || !res) {
+    return 0;
+  }
   return 1;
 }
 
diff --git a/Source/CPack/cmCPackGenerator.h b/Source/CPack/cmCPackGenerator.h
index c22f36b..9128f36 100644
--- a/Source/CPack/cmCPackGenerator.h
+++ b/Source/CPack/cmCPackGenerator.h
@@ -15,6 +15,7 @@
 #include "cm_sys_stat.h"
 
 class cmCPackLog;
+class cmGlobalGenerator;
 class cmInstalledFile;
 class cmMakefile;
 
@@ -185,6 +186,17 @@ protected:
     bool setDestDir, const std::string& tempInstallDirectory,
     const mode_t* default_dir_mode);
 
+  virtual int RunPreinstallTarget(const std::string& installProjectName,
+                                  const std::string& installDirectory,
+                                  cmGlobalGenerator* globalGenerator,
+                                  const std::string& buildConfig);
+  virtual int InstallCMakeProject(
+    bool setDestDir, const std::string& installDirectory,
+    const std::string& baseTempInstallDirectory,
+    const mode_t* default_dir_mode, const std::string& component,
+    bool componentInstall, const std::string& installSubDirectory,
+    const std::string& buildConfig, std::string& absoluteDestFiles);
+
   /**
    * The various level of support of
    * CPACK_SET_DESTDIR used by the generator.

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=42cc0644d5cc7a50ea2f65aa29b49f629ff17384
commit 42cc0644d5cc7a50ea2f65aa29b49f629ff17384
Author:     Sebastian Holtermann <sebh...@xwmw.org>
AuthorDate: Mon Jul 2 12:53:44 2018 +0200
Commit:     Sebastian Holtermann <sebh...@xwmw.org>
CommitDate: Mon Jul 2 12:53:44 2018 +0200

    Autogen: Use default and remove custom GetSafeProperty functions

diff --git a/Source/cmQtAutoGenInitializer.cxx 
b/Source/cmQtAutoGenInitializer.cxx
index 37155fa..8ede960 100644
--- a/Source/cmQtAutoGenInitializer.cxx
+++ b/Source/cmQtAutoGenInitializer.cxx
@@ -42,18 +42,6 @@ inline static const char* SafeString(const char* value)
   return (value != nullptr) ? value : "";
 }
 
-inline static std::string GetSafeProperty(cmGeneratorTarget const* target,
-                                          const char* key)
-{
-  return std::string(SafeString(target->GetProperty(key)));
-}
-
-inline static std::string GetSafeProperty(cmSourceFile const* sf,
-                                          const char* key)
-{
-  return std::string(SafeString(sf->GetProperty(key)));
-}
-
 static std::size_t GetParallelCPUCount()
 {
   static std::size_t count = 0;
@@ -249,7 +237,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
     cmSystemTools::ConvertToUnixSlashes(this->DirInfo);
 
     // Autogen build dir
-    this->DirBuild = GetSafeProperty(this->Target, "AUTOGEN_BUILD_DIR");
+    this->DirBuild = this->Target->GetSafeProperty("AUTOGEN_BUILD_DIR");
     if (this->DirBuild.empty()) {
       this->DirBuild = cbd;
       this->DirBuild += '/';
@@ -281,7 +269,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
     }
     // Inherit FOLDER property from target (#13688)
     if (folder == nullptr) {
-      folder = SafeString(this->Target->Target->GetProperty("FOLDER"));
+      folder = this->Target->GetProperty("FOLDER");
     }
     if (folder != nullptr) {
       this->AutogenFolder = folder;
@@ -432,7 +420,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
           qrc.Generated = sf->GetPropertyAsBool("GENERATED");
           // RCC options
           {
-            std::string const opts = GetSafeProperty(sf, "AUTORCC_OPTIONS");
+            std::string const opts = sf->GetSafeProperty("AUTORCC_OPTIONS");
             if (!opts.empty()) {
               cmSystemTools::ExpandListArgument(opts, qrc.Options);
             }
@@ -568,7 +556,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
     // Target rcc options
     std::vector<std::string> optionsTarget;
     cmSystemTools::ExpandListArgument(
-      GetSafeProperty(this->Target, "AUTORCC_OPTIONS"), optionsTarget);
+      this->Target->GetSafeProperty("AUTORCC_OPTIONS"), optionsTarget);
 
     // Check if file name is unique
     for (Qrc& qrc : this->Qrcs) {
@@ -734,7 +722,7 @@ void cmQtAutoGenInitializer::InitCustomTargets()
     // Add user defined autogen target dependencies
     {
       std::string const deps =
-        GetSafeProperty(this->Target, "AUTOGEN_TARGET_DEPENDS");
+        this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS");
       if (!deps.empty()) {
         std::vector<std::string> extraDeps;
         cmSystemTools::ExpandListArgument(deps, extraDeps);
@@ -907,7 +895,7 @@ void cmQtAutoGenInitializer::SetupCustomTargets()
     }
 
     // Parallel processing
-    this->Parallel = GetSafeProperty(this->Target, "AUTOGEN_PARALLEL");
+    this->Parallel = this->Target->GetSafeProperty("AUTOGEN_PARALLEL");
     if (this->Parallel.empty() || (this->Parallel == "AUTO")) {
       // Autodetect number of CPUs
       this->Parallel = std::to_string(GetParallelCPUCount());
@@ -1000,12 +988,12 @@ void cmQtAutoGenInitializer::SetupCustomTargets()
         CWrite("AM_MOC_INCLUDES", this->MocIncludes);
         CWriteMap("AM_MOC_INCLUDES", this->MocIncludesConfig);
         CWrite("AM_MOC_OPTIONS",
-               GetSafeProperty(this->Target, "AUTOMOC_MOC_OPTIONS"));
+               this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS"));
         CWrite("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE"));
         CWrite("AM_MOC_MACRO_NAMES",
-               GetSafeProperty(this->Target, "AUTOMOC_MACRO_NAMES"));
+               this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES"));
         CWrite("AM_MOC_DEPEND_FILTERS",
-               GetSafeProperty(this->Target, "AUTOMOC_DEPEND_FILTERS"));
+               this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS"));
         CWrite("AM_MOC_PREDEFS_CMD", this->MocPredefsCmd);
       }
 
@@ -1182,7 +1170,7 @@ void cmQtAutoGenInitializer::SetupCustomTargetsUic()
   // Uic search paths
   {
     std::string const usp =
-      GetSafeProperty(this->Target, "AUTOUIC_SEARCH_PATHS");
+      this->Target->GetSafeProperty("AUTOUIC_SEARCH_PATHS");
     if (!usp.empty()) {
       cmSystemTools::ExpandListArgument(usp, this->UicSearchPaths);
       std::string const srcDir = makefile->GetCurrentSourceDirectory();
@@ -1231,7 +1219,7 @@ void cmQtAutoGenInitializer::SetupCustomTargetsUic()
           this->UicSkip.insert(absFile);
         }
         // Check if the .ui file has uic options
-        std::string const uicOpts = GetSafeProperty(sf, "AUTOUIC_OPTIONS");
+        std::string const uicOpts = sf->GetSafeProperty("AUTOUIC_OPTIONS");
         if (!uicOpts.empty()) {
           // Check if file isn't skipped
           if (this->UicSkip.count(absFile) == 0) {

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=127094f2f0e444b78d224d933a28a8313e487d36
commit 127094f2f0e444b78d224d933a28a8313e487d36
Author:     Sebastian Holtermann <sebh...@xwmw.org>
AuthorDate: Mon Jul 2 12:39:54 2018 +0200
Commit:     Sebastian Holtermann <sebh...@xwmw.org>
CommitDate: Mon Jul 2 12:39:54 2018 +0200

    Add GetSafeProperty method to cmTarget, cmGeneratorTarget and cmSourceFile

diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 41e55a5..02f181e 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -221,6 +221,15 @@ const char* cmGeneratorTarget::GetProperty(const 
std::string& prop) const
   return this->Target->GetProperty(prop);
 }
 
+const char* cmGeneratorTarget::GetSafeProperty(const std::string& prop) const
+{
+  const char* ret = this->GetProperty(prop);
+  if (!ret) {
+    return "";
+  }
+  return ret;
+}
+
 const char* cmGeneratorTarget::GetOutputTargetType(
   cmStateEnums::ArtifactType artifact) const
 {
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index aa36823..5b77610 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -68,7 +68,10 @@ public:
   std::string GetExportName() const;
 
   std::vector<std::string> GetPropertyKeys() const;
+  ///! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
+  ///! Always returns a valid pointer
+  const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   void GetSourceFiles(std::vector<cmSourceFile*>& files,
                       const std::string& config) const;
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 6792d66..05e26ea 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -296,6 +296,15 @@ const char* cmSourceFile::GetProperty(const std::string& 
prop) const
   return retVal;
 }
 
+const char* cmSourceFile::GetSafeProperty(const std::string& prop) const
+{
+  const char* ret = this->GetProperty(prop);
+  if (!ret) {
+    return "";
+  }
+  return ret;
+}
+
 bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
 {
   return cmSystemTools::IsOn(this->GetProperty(prop));
diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h
index 1516d98..ab0f229 100644
--- a/Source/cmSourceFile.h
+++ b/Source/cmSourceFile.h
@@ -45,7 +45,10 @@ public:
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
+  ///! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
+  ///! Always returns a valid pointer
+  const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
 
   /** Implement getting a property when called from a CMake language
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 1a6e1d1..803a0a9 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -1412,6 +1412,15 @@ const char* cmTarget::GetProperty(const std::string& 
prop) const
   return retVal;
 }
 
+const char* cmTarget::GetSafeProperty(const std::string& prop) const
+{
+  const char* ret = this->GetProperty(prop);
+  if (!ret) {
+    return "";
+  }
+  return ret;
+}
+
 bool cmTarget::GetPropertyAsBool(const std::string& prop) const
 {
   return cmSystemTools::IsOn(this->GetProperty(prop));
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 5f0b33c..7a3ab65 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -200,7 +200,10 @@ public:
   void SetProperty(const std::string& prop, const char* value);
   void AppendProperty(const std::string& prop, const char* value,
                       bool asString = false);
+  ///! Might return a nullptr if the property is not set or invalid
   const char* GetProperty(const std::string& prop) const;
+  ///! Always returns a valid pointer
+  const char* GetSafeProperty(const std::string& prop) const;
   bool GetPropertyAsBool(const std::string& prop) const;
   void CheckProperty(const std::string& prop, cmMakefile* context) const;
   const char* GetComputedProperty(const std::string& prop,

-----------------------------------------------------------------------

Summary of changes:
 Help/cpack_gen/external.rst                        | 249 +++++++++
 Help/manual/cpack-generators.7.rst                 |   1 +
 Help/release/dev/cpack-external.rst                |   8 +
 Modules/Internal/CPack/CPackExt.cmake              |  53 ++
 Source/CMakeLists.txt                              |   3 +-
 Source/CPack/cmCPackComponentGroup.h               |  25 +
 Source/CPack/cmCPackExtGenerator.cxx               | 291 +++++++++++
 Source/CPack/cmCPackExtGenerator.h                 |  86 +++
 Source/CPack/cmCPackGenerator.cxx                  | 576 +++++++++++----------
 Source/CPack/cmCPackGenerator.h                    |  13 +
 Source/CPack/cmCPackGeneratorFactory.cxx           |   5 +
 Source/cmGeneratorTarget.cxx                       |   9 +
 Source/cmGeneratorTarget.h                         |   3 +
 Source/cmQtAutoGenInitializer.cxx                  |  34 +-
 Source/cmSourceFile.cxx                            |   9 +
 Source/cmSourceFile.h                              |   3 +
 Source/cmTarget.cxx                                |   9 +
 Source/cmTarget.h                                  |   3 +
 Tests/RunCMake/CMakeLists.txt                      |   2 +-
 Tests/RunCMake/CPack/Ext/Helpers.cmake             |  31 ++
 .../CPack/Ext/Prerequirements.cmake}               |   0
 Tests/RunCMake/CPack/RunCMakeTest.cmake            |   3 +-
 Tests/RunCMake/CPack/VerifyResult.cmake            |   8 +-
 Tests/RunCMake/CPack/tests/EXT/ExpectedFiles.cmake |   6 +
 Tests/RunCMake/CPack/tests/EXT/VerifyResult.cmake  |   3 +
 .../RunCMake/CPack/tests/EXT/bad_major-stderr.txt  |   6 +
 .../RunCMake/CPack/tests/EXT/bad_minor-stderr.txt  |   6 +
 .../RunCMake/CPack/tests/EXT/expected-json-1.0.txt | 176 +++++++
 .../CPack/tests/EXT/invalid_bad-stderr.txt         |   6 +
 Tests/RunCMake/CPack/tests/EXT/test.cmake          |  83 +++
 30 files changed, 1406 insertions(+), 304 deletions(-)
 create mode 100644 Help/cpack_gen/external.rst
 create mode 100644 Help/release/dev/cpack-external.rst
 create mode 100644 Modules/Internal/CPack/CPackExt.cmake
 create mode 100644 Source/CPack/cmCPackExtGenerator.cxx
 create mode 100644 Source/CPack/cmCPackExtGenerator.h
 create mode 100644 Tests/RunCMake/CPack/Ext/Helpers.cmake
 copy Tests/{Wrapping/vtkIncluded.cxx => 
RunCMake/CPack/Ext/Prerequirements.cmake} (100%)
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/ExpectedFiles.cmake
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/VerifyResult.cmake
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/bad_major-stderr.txt
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/bad_minor-stderr.txt
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/expected-json-1.0.txt
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/invalid_bad-stderr.txt
 create mode 100644 Tests/RunCMake/CPack/tests/EXT/test.cmake


hooks/post-receive
-- 
CMake
_______________________________________________
Cmake-commits mailing list
Cmake-commits@cmake.org
https://cmake.org/mailman/listinfo/cmake-commits

Reply via email to