Merge topic 'rename-cross-config-variable'

310b58e961 Ninja Multi-Config: Rename variable to be more consistent

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4234
diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim
index 31ec1d0..0676f7e 100644
--- a/Auxiliary/vim/syntax/cmake.vim
+++ b/Auxiliary/vim/syntax/cmake.vim
@@ -221,6 +221,7 @@
             \ JOB_POOLS
             \ JOB_POOL_COMPILE
             \ JOB_POOL_LINK
+            \ JOB_POOL_PRECOMPILE_HEADER
             \ KEEP_EXTENSION
             \ LABELS
             \ LANGUAGE
@@ -1066,6 +1067,7 @@
             \ CMAKE_JOB_POOLS
             \ CMAKE_JOB_POOL_COMPILE
             \ CMAKE_JOB_POOL_LINK
+            \ CMAKE_JOB_POOL_PRECOMPILE_HEADER
             \ CMAKE_Java
             \ CMAKE_Java_ANDROID_TOOLCHAIN_MACHINE
             \ CMAKE_Java_ANDROID_TOOLCHAIN_PREFIX
@@ -2864,6 +2866,11 @@
             \ _LINKER_WRAPPER_FLAG
             \ _LINKER_WRAPPER_FLAG_SEP
 
+syn keyword cmakeKWtarget_precompile_headers contained
+            \ INTERFACE
+            \ PRIVATE
+            \ PUBLIC
+
 syn keyword cmakeKWtarget_sources contained
             \ ALIAS
             \ IMPORTED
@@ -3168,6 +3175,7 @@
             \ target_link_directories
             \ target_link_libraries
             \ target_link_options
+            \ target_precompile_headers
             \ target_sources
             \ try_compile
             \ try_run
@@ -3324,6 +3332,7 @@
 hi def link cmakeKWtarget_link_directories ModeMsg
 hi def link cmakeKWtarget_link_libraries ModeMsg
 hi def link cmakeKWtarget_link_options ModeMsg
+hi def link cmakeKWtarget_precompile_headers ModeMsg
 hi def link cmakeKWtarget_sources ModeMsg
 hi def link cmakeKWtry_compile ModeMsg
 hi def link cmakeKWtry_run ModeMsg
diff --git a/Help/cpack_gen/dmg.rst b/Help/cpack_gen/dmg.rst
index 1e37889..35320c2 100644
--- a/Help/cpack_gen/dmg.rst
+++ b/Help/cpack_gen/dmg.rst
@@ -81,6 +81,13 @@
   ``<language>.menu.txt`` and ``<language>.license.txt`` in the directory
   specified by the :variable:`CPACK_DMG_SLA_DIR` variable.
 
+.. variable:: CPACK_DMG_<component>_FILE_NAME
+
+ File name when packaging ``<component>`` as its own DMG
+ (``CPACK_COMPONENTS_GROUPING`` set to IGNORE).
+
+ - Default: ``CPACK_PACKAGE_FILE_NAME-<component>``
+
 .. variable:: CPACK_COMMAND_HDIUTIL
 
  Path to the ``hdiutil(1)`` command used to operate on disk image files on
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index b3802d1..393735e 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -253,6 +253,7 @@
    /prop_tgt/IOS_INSTALL_COMBINED
    /prop_tgt/JOB_POOL_COMPILE
    /prop_tgt/JOB_POOL_LINK
+   /prop_tgt/JOB_POOL_PRECOMPILE_HEADER
    /prop_tgt/LABELS
    /prop_tgt/LANG_CLANG_TIDY
    /prop_tgt/LANG_COMPILER_LAUNCHER
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 0cea2c8..ae22fdf 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -65,6 +65,7 @@
    /variable/CMAKE_IMPORT_LIBRARY_SUFFIX
    /variable/CMAKE_JOB_POOL_COMPILE
    /variable/CMAKE_JOB_POOL_LINK
+   /variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER
    /variable/CMAKE_JOB_POOLS
    /variable/CMAKE_LANG_COMPILER_AR
    /variable/CMAKE_LANG_COMPILER_RANLIB
diff --git a/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..ece28a4
--- /dev/null
+++ b/Help/prop_tgt/JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,21 @@
+JOB_POOL_PRECOMPILE_HEADER
+--------------------------
+
+Ninja only: Pool used for generating pre-compiled headers.
+
+The number of parallel compile processes could be limited by defining
+pools with the global :prop_gbl:`JOB_POOLS`
+property and then specifying here the pool name.
+
+For instance:
+
+.. code-block:: cmake
+
+  set_property(TARGET myexe PROPERTY JOB_POOL_PRECOMPILE_HEADER two_jobs)
+
+This property is initialized by the value of
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER`.
+
+If neither :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER` nor
+:variable:`CMAKE_JOB_POOL_PRECOMPILE_HEADER` are set then
+:prop_tgt:`JOB_POOL_COMPILE` will be used for this task.
diff --git a/Help/release/dev/custom-dmg-names.rst b/Help/release/dev/custom-dmg-names.rst
new file mode 100644
index 0000000..73a70a1
--- /dev/null
+++ b/Help/release/dev/custom-dmg-names.rst
@@ -0,0 +1,7 @@
+custom-dmg-names
+----------------
+
+* The :cpack_gen:`CPack DragNDrop Generator` learned to use
+  the :variable:`CPACK_DMG_<component>_FILE_NAME` variable
+  to set a custom filename when packaging components into
+  their own DMGs.
diff --git a/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
new file mode 100644
index 0000000..f9467b3
--- /dev/null
+++ b/Help/variable/CMAKE_JOB_POOL_PRECOMPILE_HEADER.rst
@@ -0,0 +1,6 @@
+CMAKE_JOB_POOL_PRECOMPILE_HEADER
+--------------------------------
+
+This variable is used to initialize the :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+property on all the targets. See :prop_tgt:`JOB_POOL_PRECOMPILE_HEADER`
+for additional information.
diff --git a/Modules/CMakeCSharpInformation.cmake b/Modules/CMakeCSharpInformation.cmake
index 48e1a1e..41cd449 100644
--- a/Modules/CMakeCSharpInformation.cmake
+++ b/Modules/CMakeCSharpInformation.cmake
@@ -10,7 +10,7 @@
 
 set(CMAKE_BUILD_TYPE_INIT Debug)
 
-set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE /langversion:3")
+set(CMAKE_CSharp_FLAGS_INIT "/define:TRACE")
 set(CMAKE_CSharp_FLAGS_DEBUG_INIT "/debug:full /optimize- /warn:3 /errorreport:prompt /define:DEBUG")
 set(CMAKE_CSharp_FLAGS_RELEASE_INIT "/debug:none /optimize  /warn:1  /errorreport:queue")
 set(CMAKE_CSharp_FLAGS_RELWITHDEBINFO_INIT "/debug:full /optimize-")
diff --git a/Modules/Compiler/NAG-Fortran.cmake b/Modules/Compiler/NAG-Fortran.cmake
index c54ab9d..2111c65 100644
--- a/Modules/Compiler/NAG-Fortran.cmake
+++ b/Modules/Compiler/NAG-Fortran.cmake
@@ -28,6 +28,8 @@
   endif()
 endif()
 
+set(CMAKE_Fortran_SUBMODULE_SEP ".")
+set(CMAKE_Fortran_SUBMODULE_EXT ".sub")
 set(CMAKE_Fortran_MODDIR_FLAG "-mdir ")
 set(CMAKE_SHARED_LIBRARY_Fortran_FLAGS "-PIC")
 set(CMAKE_Fortran_FORMAT_FIXED_FLAG "-fixed")
diff --git a/Modules/Platform/Windows-PGI.cmake b/Modules/Platform/Windows-PGI.cmake
index ad77e8a..8166240 100644
--- a/Modules/Platform/Windows-PGI.cmake
+++ b/Modules/Platform/Windows-PGI.cmake
@@ -9,9 +9,10 @@
 set(__WINDOWS_COMPILER_PGI 1)
 
 # PGI on Windows doesn't support parallel compile processes
-if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE)
+if(NOT DEFINED CMAKE_JOB_POOL_LINK OR NOT DEFINED CMAKE_JOB_POOL_COMPILE OR NOT DEFINED CMAKE_JOB_POOL_PRECOMPILE_HEADER)
   set(CMAKE_JOB_POOL_LINK PGITaskPool)
   set(CMAKE_JOB_POOL_COMPILE PGITaskPool)
+  set(CMAKE_JOB_POOL_PRECOMPILE_HEADER PGITaskPool)
   get_property(_pgijp GLOBAL PROPERTY JOB_POOLS)
   if(NOT _pgijp MATCHES "PGITaskPool=")
       set_property(GLOBAL APPEND PROPERTY JOB_POOLS PGITaskPool=1)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index e7dacfd..721e823 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,7 +1,7 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 16)
-set(CMake_VERSION_PATCH 20200116)
+set(CMake_VERSION_PATCH 20200117)
 #set(CMake_VERSION_RC 0)
 set(CMake_VERSION_IS_DIRTY 0)
 
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index ea71007..3516235 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -775,6 +775,11 @@
     }
   }
 
+  std::string componentFileName =
+    "CPACK_DMG_" + cmSystemTools::UpperCase(componentName) + "_FILE_NAME";
+  if (this->IsSet(componentFileName)) {
+    return this->GetOption(componentFileName);
+  }
   return GetComponentPackageFileName(package_file_name, componentName, false);
 }
 
diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx
index ee43587..3692202 100644
--- a/Source/cmDependsFortran.cxx
+++ b/Source/cmDependsFortran.cxx
@@ -33,6 +33,8 @@
     ext_len = 4;
   } else if (cmHasLiteralSuffix(mod, ".smod")) {
     ext_len = 5;
+  } else if (cmHasLiteralSuffix(mod, ".sub")) {
+    ext_len = 4;
   }
   std::string const& name = mod.substr(0, mod.size() - ext_len);
   std::string const& ext = mod.substr(mod.size() - ext_len);
@@ -284,7 +286,8 @@
       if (doing_provides) {
         std::string mod = line;
         if (!cmHasLiteralSuffix(mod, ".mod") &&
-            !cmHasLiteralSuffix(mod, ".smod")) {
+            !cmHasLiteralSuffix(mod, ".smod") &&
+            !cmHasLiteralSuffix(mod, ".sub")) {
           // Support fortran.internal files left by older versions of CMake.
           // They do not include the ".mod" extension.
           mod += ".mod";
@@ -470,7 +473,8 @@
   if (args.size() >= 5) {
     compilerId = args[4];
   }
-  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod")) {
+  if (!cmHasLiteralSuffix(mod, ".mod") && !cmHasLiteralSuffix(mod, ".smod") &&
+      !cmHasLiteralSuffix(mod, ".sub")) {
     // Support depend.make files left by older versions of CMake.
     // They do not include the ".mod" extension.
     mod += ".mod";
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 1fdfa87..d1775a7 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1707,7 +1707,8 @@
   // as we receive downloaded bits from curl...
   //
   std::string dir = cmSystemTools::GetFilenamePath(file);
-  if (!cmSystemTools::FileExists(dir) && !cmSystemTools::MakeDirectory(dir)) {
+  if (!dir.empty() && !cmSystemTools::FileExists(dir) &&
+      !cmSystemTools::MakeDirectory(dir)) {
     std::string errstring = "DOWNLOAD error: cannot create directory '" + dir +
       "' - Specify file by full path name and verify that you "
       "have directory creation and file write privileges.";
diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx
index bd19b28..5a8c144 100644
--- a/Source/cmNinjaTargetGenerator.cxx
+++ b/Source/cmNinjaTargetGenerator.cxx
@@ -1196,6 +1196,13 @@
   this->addPoolNinjaVariable("JOB_POOL_COMPILE", this->GetGeneratorTarget(),
                              vars);
 
+  if (!pchSource.empty() && !source->GetProperty("SKIP_PRECOMPILE_HEADERS")) {
+    if (source->GetFullPath() == pchSource) {
+      this->addPoolNinjaVariable("JOB_POOL_PRECOMPILE_HEADER",
+                                 this->GetGeneratorTarget(), vars);
+    }
+  }
+
   this->SetMsvcTargetPdbVariable(vars, config);
 
   objBuild.RspFile = objectFileName + ".rsp";
diff --git a/Source/cmSourceFile.cxx b/Source/cmSourceFile.cxx
index 2a345eb..60adf7f 100644
--- a/Source/cmSourceFile.cxx
+++ b/Source/cmSourceFile.cxx
@@ -128,7 +128,7 @@
   // The file is not generated.  It must exist on disk.
   cmMakefile const* makefile = this->Location.GetMakefile();
   // Location path
-  std::string const lPath = this->Location.GetFullPath();
+  std::string const& lPath = this->Location.GetFullPath();
   // List of extension lists
   std::array<std::vector<std::string> const*, 2> const extsLists = {
     { &makefile->GetCMakeInstance()->GetSourceExtensions(),
@@ -145,7 +145,7 @@
       return true;
     }
     // Try full path with extension
-    for (auto exts : extsLists) {
+    for (auto& exts : extsLists) {
       for (std::string const& ext : *exts) {
         if (!ext.empty()) {
           std::string extPath = cmStrCat(fullPath, '.', ext);
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 6590629..ae1393f 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -513,6 +513,7 @@
       this->GetType() != cmStateEnums::UTILITY) {
     initProp("JOB_POOL_COMPILE");
     initProp("JOB_POOL_LINK");
+    initProp("JOB_POOL_PRECOMPILE_HEADER");
   }
 
   if (impl->TargetType <= cmStateEnums::UTILITY) {
diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt
index 1619081..e32d693 100644
--- a/Tests/CMakeTests/CMakeLists.txt
+++ b/Tests/CMakeTests/CMakeLists.txt
@@ -33,8 +33,9 @@
 AddCMakeTest(CMakeHostSystemInformation "")
 
 AddCMakeTest(FileDownload "")
-set_property(TEST CMake.FileDownload PROPERTY
+set_tests_properties(CMake.FileDownload PROPERTIES
   PASS_REGULAR_EXPRESSION "file already exists with expected MD5 sum"
+  FAIL_REGULAR_EXPRESSION "Unexpected status"
   )
 AddCMakeTest(FileDownloadBadHash "")
 set_property(TEST CMake.FileDownloadBadHash PROPERTY
diff --git a/Tests/CMakeTests/FileDownloadTest.cmake.in b/Tests/CMakeTests/FileDownloadTest.cmake.in
index 3935449..5bd3803 100644
--- a/Tests/CMakeTests/FileDownloadTest.cmake.in
+++ b/Tests/CMakeTests/FileDownloadTest.cmake.in
@@ -1,23 +1,50 @@
+# We do not contact any real URLs, but do try a bogus one.
+# Remove any proxy configuration that may change behavior.
+unset(ENV{http_proxy})
+unset(ENV{https_proxy})
+
+set(timeout 4)
+
 if(NOT "@CMAKE_CURRENT_SOURCE_DIR@" MATCHES "^/")
   set(slash /)
 endif()
 set(url "file://${slash}@CMAKE_CURRENT_SOURCE_DIR@/FileDownloadInput.png")
 set(dir "@CMAKE_CURRENT_BINARY_DIR@/downloads")
 
+# Beware Windows asynchronous file/directory removal, rename and then
+# remove the renamed dir so we can be certain the dir isn't there when
+# we get to the file() commands below
+if(EXISTS "${dir}")
+  file(RENAME ${dir} "${dir}_beingRemoved")
+  file(REMOVE_RECURSE "${dir}_beingRemoved")
+endif()
+
+function(__reportIfWrongStatus statusPair expectedStatusCode)
+  list(GET statusPair 0 statusCode)
+  if(NOT statusCode EQUAL expectedStatusCode)
+    message(SEND_ERROR
+            "Unexpected status: ${statusCode}, expected: ${expectedStatusCode}")
+  endif()
+endfunction()
+
 message(STATUS "FileDownload:1")
 file(DOWNLOAD
   ${url}
   ${dir}/file1.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:2")
 file(DOWNLOAD
   ${url}
   ${dir}/file2.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   SHOW_PROGRESS
   )
+__reportIfWrongStatus("${status}" 0)
 
 # Two calls in a row, exactly the same arguments.
 # Since downloaded file should exist already for 2nd call,
@@ -31,82 +58,108 @@
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
+  STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:4")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA1=67eee17f79d9ac557284fc0b8ad19f25723fb578
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:5")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA224=ba283726bbb602776818b463943189afd91836cb7ee5dd6e2c7b5ae4
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:6")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA256=cf3334b1275071e1da6e8c396ccb72cf1b2388d8c937526f3af26230affb9423
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:7")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA384=43a5d13978d97c660db44481aee0604cb4ff6ca0775cd5c2cd68cd8000e107e507c4caf6c228941231041e282ffb8950
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:8")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH SHA512=6984e0909a1018030ccaa418e3be1654223cdccff0fe6adc745f9aea7e377f178be53b9fc7d54a6f81c2b62ef9ddcd38ba1978fedf4c5e7139baaf355eefad5b
   )
+__reportIfWrongStatus("${status}" 0)
+
 message(STATUS "FileDownload:9")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_HASH MD5=dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
 
 message(STATUS "FileDownload:10")
 file(DOWNLOAD
   ${url}
   ${dir}/file3.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
   )
+__reportIfWrongStatus("${status}" 0)
+# Print status because we check its message too
 message(STATUS "${status}")
 
 message(STATUS "FileDownload:11")
 file(DOWNLOAD
   badhostname.png
   ${dir}/file11.png
-  TIMEOUT 2
+  TIMEOUT ${timeout}
   STATUS status
   )
 message(STATUS "${status}")
-list(GET status 0 status_code)
-if(NOT ${status_code} EQUAL 6)
-  message(SEND_ERROR "error: expected status code 6 for bad host name, got: ${status_code}")
+__reportIfWrongStatus("${status}" 6) # 6 corresponds to an unresolvable host name
+
+message(STATUS "FileDownload:12")
+set(absFile "@CMAKE_CURRENT_BINARY_DIR@/file12.png")
+if(EXISTS "${absFile}")
+  file(RENAME ${absFile} "${absFile}_beingRemoved")
+  file(REMOVE "${absFile}_beingRemoved")
+endif()
+file(DOWNLOAD
+  ${url}
+  file12.png
+  TIMEOUT ${timeout}
+  EXPECTED_MD5 dbd330d52f4dbd60115d4191904ded92
+  STATUS status
+  )
+__reportIfWrongStatus("${status}" 0)
+if(NOT EXISTS file12.png)
+  message(SEND_ERROR "file12.png not downloaded: ${status}")
 endif()
diff --git a/Tests/CMakeTests/FileTestScript.cmake b/Tests/CMakeTests/FileTestScript.cmake
index 9a43569..145f28a 100644
--- a/Tests/CMakeTests/FileTestScript.cmake
+++ b/Tests/CMakeTests/FileTestScript.cmake
@@ -183,7 +183,7 @@
 elseif(testname STREQUAL download_wrong_number_of_args) # fail
   file(DOWNLOAD zzzz://bogus/ffff)
 
-elseif(testname STREQUAL download_file_with_no_path) # fail
+elseif(testname STREQUAL download_file_with_no_path) # pass
   file(DOWNLOAD zzzz://bogus/ffff ffff)
 
 elseif(testname STREQUAL download_missing_time) # fail
diff --git a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
index f70cd24..01b37c5 100644
--- a/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
+++ b/Tests/CPackNSISGenerator/RunCPackVerifyResult.cmake
@@ -27,7 +27,7 @@
   message(STATUS "CPack_output=${CPack_output}")
 endif()
 
-set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/win32/NSIS/*.nsi")
+set(expected_file_mask "${CPackNSISGenerator_BINARY_DIR}/_CPack_Packages/*/NSIS/*.nsi")
 file(GLOB project_file "${expected_file_mask}")
 
 message(STATUS "project_file='${project_file}'")
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 7936f47..d302fe3 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -604,6 +604,9 @@
   STGZ
   External
   )
+if(APPLE)
+  list(APPEND cpack_tests DragNDrop)
+endif()
 add_RunCMake_test_group(CPack "${cpack_tests}")
 # add a test to make sure symbols are exported from a shared library
 # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
diff --git a/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
new file mode 100644
index 0000000..023e597
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Helpers.cmake
@@ -0,0 +1,54 @@
+set(ALL_FILES_GLOB "*.dmg")
+
+function(getPackageContent FILE RESULT_VAR)
+  get_filename_component(path_ "${FILE}" DIRECTORY)
+  file(REMOVE_RECURSE "${path_}/content")
+  file(MAKE_DIRECTORY "${path_}/content")
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} attach -mountroot ${path_}/content -nobrowse ${FILE}
+          RESULT_VARIABLE attach_result_
+          ERROR_VARIABLE attach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(attach_result_)
+    message(FATAL_ERROR "Failed to attach DMG: '${attach_result_}';"
+          " '${attach_error_}'.")
+  endif()
+
+  file(GLOB_RECURSE package_content_ LIST_DIRECTORIES true RELATIVE
+      "${path_}/content" "${path_}/content/*")
+  # Some versions of macOS have .Trashes, others do not.
+  list(FILTER package_content_ EXCLUDE REGEX "/.Trashes$")
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+
+  execute_process(COMMAND ${HDIUTIL_EXECUTABLE} detach ${path_}/content/volume-name
+          RESULT_VARIABLE detach_result_
+          ERROR_VARIABLE detach_error_
+          OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+  if(detach_result_)
+    message(FATAL_ERROR "Failed to detach DMG: '${detach_result_}';"
+          " '${detach_error_}'.")
+  endif()
+endfunction()
+
+function(getPackageNameGlobexpr NAME COMPONENT VERSION REVISION FILE_NO RESULT_VAR)
+  if(COMPONENT)
+    set(COMPONENT "-${COMPONENT}")
+  endif()
+
+  set(${RESULT_VAR} "${NAME}-${VERSION}-Darwin${COMPONENT}.dmg" PARENT_SCOPE)
+endfunction()
+
+function(getPackageContentList FILE RESULT_VAR)
+  getPackageContent("${FILE}" package_content_)
+
+  set(${RESULT_VAR} "${package_content_}" PARENT_SCOPE)
+endfunction()
+
+function(toExpectedContentList FILE_NO CONTENT_VAR)
+  set(prefix_ "volume-name")
+  list(TRANSFORM ${CONTENT_VAR} PREPEND "${prefix_}" OUTPUT_VARIABLE prepared_)
+  list(APPEND prepared_ "${prefix_}")
+
+  set(${CONTENT_VAR} "${prepared_}" PARENT_SCOPE)
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
new file mode 100644
index 0000000..f0aaf2c
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/Prerequirements.cmake
@@ -0,0 +1,8 @@
+function(get_test_prerequirements found_var config_file)
+  find_program(HDIUTIL_EXECUTABLE hdiutil)
+
+  if(HDIUTIL_EXECUTABLE)
+    file(WRITE "${config_file}" "set(HDIUTIL_EXECUTABLE \"${HDIUTIL_EXECUTABLE}\")")
+    set(${found_var} true PARENT_SCOPE)
+  endif()
+endfunction()
diff --git a/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
new file mode 100644
index 0000000..aa6c8ff
--- /dev/null
+++ b/Tests/RunCMake/CPack/DragNDrop/packaging_COMPONENT_default.cmake
@@ -0,0 +1,3 @@
+set(CPACK_COMPONENTS_GROUPING "IGNORE")
+set(CPACK_DMG_DISABLE_APPLICATIONS_SYMLINK ON)
+set(CPACK_DMG_VOLUME_NAME "volume-name")
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 6e413aa..0fb0cc4 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -5,7 +5,7 @@
 
 # run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
 run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM.CUSTOM_BINARY_SPEC_FILE" false "MONOLITHIC;COMPONENT")
-run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ" true "COMPONENT")
+run_cpack_test(CUSTOM_NAMES "RPM.CUSTOM_NAMES;DEB.CUSTOM_NAMES;TGZ;DragNDrop" true "COMPONENT")
 run_cpack_test(DEBUGINFO "RPM.DEBUGINFO;DEB.DEBUGINFO" true "COMPONENT")
 run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM.DEFAULT_PERMISSIONS;DEB.DEFAULT_PERMISSIONS" false "MONOLITHIC;COMPONENT")
 run_cpack_test(DEPENDENCIES "RPM.DEPENDENCIES;DEB.DEPENDENCIES" true "COMPONENT")
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
index 07226df..9ac19e2 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/ExpectedFiles.cmake
@@ -12,4 +12,7 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(EXPECTED_FILE_2 "second.tar.gz")
   set(EXPECTED_FILE_3 "pkg_3_abc.tar.gz")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(EXPECTED_FILE_2 "second.dmg")
+  set(EXPECTED_FILE_3 "pkg_3_abc.dmg")
 endif()
diff --git a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
index 4c20e41..899258e 100644
--- a/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
+++ b/Tests/RunCMake/CPack/tests/CUSTOM_NAMES/test.cmake
@@ -10,6 +10,9 @@
 elseif(GENERATOR_TYPE STREQUAL "TGZ")
   set(CPACK_ARCHIVE_PKG_2_FILE_NAME "second")
   set(CPACK_ARCHIVE_PKG_3_FILE_NAME "pkg_3_abc")
+elseif(GENERATOR_TYPE STREQUAL "DragNDrop")
+  set(CPACK_DMG_PKG_2_FILE_NAME "second")
+  set(CPACK_DMG_PKG_3_FILE_NAME "pkg_3_abc")
 endif()
 
 install(FILES CMakeLists.txt DESTINATION foo COMPONENT pkg_1)