Merge branch 'server-file-monitor-check' into release-3.12

Merge-request: !2556
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 2d04b84..d765bdf 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -1163,21 +1163,24 @@
 
     # return the updated value
     set(${matlab_final_version} ${Matlab_VERSION_STRING_INTERNAL} PARENT_SCOPE)
-  else()
+  elseif(EXISTS "${matlab_root}/VersionInfo.xml")
     # MCR
     # we cannot run anything in order to extract the version. We assume that the file
     # VersionInfo.xml exists under the MatlabRoot, we look for it and extract the version from there
     set(_matlab_version_tmp "unknown")
     file(STRINGS "${matlab_root}/VersionInfo.xml" versioninfo_string NEWLINE_CONSUME)
-    # parses "<version>9.2.0.538062</version>"
-    string(REGEX MATCH "<version>(.*)</version>"
-           version_reg_match
-           ${versioninfo_string}
-          )
 
-    if(NOT "${version_reg_match}" STREQUAL "")
-      if("${CMAKE_MATCH_1}" MATCHES "(([0-9])\\.([0-9]))[\\.0-9]*")
-        set(_matlab_version_tmp "${CMAKE_MATCH_1}")
+    if(versioninfo_string)
+      # parses "<version>9.2.0.538062</version>"
+      string(REGEX MATCH "<version>(.*)</version>"
+             version_reg_match
+             ${versioninfo_string}
+            )
+
+      if(NOT "${version_reg_match}" STREQUAL "")
+        if("${CMAKE_MATCH_1}" MATCHES "(([0-9])\\.([0-9]))[\\.0-9]*")
+          set(_matlab_version_tmp "${CMAKE_MATCH_1}")
+        endif()
       endif()
     endif()
     set(${matlab_final_version} "${_matlab_version_tmp}" PARENT_SCOPE)
@@ -1185,8 +1188,7 @@
         "${_matlab_version_tmp}"
         CACHE INTERNAL "Matlab (MCR) version (automatically determined)"
         FORCE)
-
-    endif() # Matlab or MCR
+  endif() # Matlab or MCR
 
 endfunction()
 
diff --git a/Modules/UseSWIG.cmake b/Modules/UseSWIG.cmake
index b7b9fe1..492842b 100644
--- a/Modules/UseSWIG.cmake
+++ b/Modules/UseSWIG.cmake
@@ -479,6 +479,10 @@
   get_property (compile_options SOURCE "${infile}" PROPERTY GENERATED_COMPILE_OPTIONS)
   set_property (SOURCE "${swig_generated_file_fullname}" PROPERTY COMPILE_OPTIONS $<TARGET_GENEX_EVAL:${target_name},$<TARGET_PROPERTY:${target_name},SWIG_GENERATED_COMPILE_OPTIONS>> ${compile_options})
 
+  if (SWIG_MODULE_${name}_SWIG_LANGUAGE_FLAG MATCHES "php")
+    set_property (SOURCE "${swig_generated_file_fullname}" APPEND PROPERTY INCLUDE_DIRECTORIES "${outdir}")
+  endif()
+
   set(${outfiles} "${swig_generated_file_fullname}" ${swig_extra_generated_files} PARENT_SCOPE)
 
   # legacy support
diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx
index 91b92a3..d005134 100644
--- a/Source/CTest/cmCTestTestHandler.cxx
+++ b/Source/CTest/cmCTestTestHandler.cxx
@@ -1686,6 +1686,7 @@
   cm.GetState()->AddBuiltinCommand("set_tests_properties", newCom4);
 
   // Add handler for SET_DIRECTORY_PROPERTIES
+  cm.GetState()->RemoveBuiltinCommand("set_directory_properties");
   cmCTestSetDirectoryPropertiesCommand* newCom5 =
     new cmCTestSetDirectoryPropertiesCommand;
   newCom5->TestHandler = this;
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index dc9318e..7c32e6d 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -148,6 +148,8 @@
   state->AddBuiltinCommand("separate_arguments",
                            new cmSeparateArgumentsCommand);
   state->AddBuiltinCommand("set", new cmSetCommand);
+  state->AddBuiltinCommand("set_directory_properties",
+                           new cmSetDirectoryPropertiesCommand);
   state->AddBuiltinCommand("set_property", new cmSetPropertyCommand);
   state->AddBuiltinCommand("site_name", new cmSiteNameCommand);
   state->AddBuiltinCommand("string", new cmStringCommand);
@@ -237,8 +239,6 @@
   state->AddBuiltinCommand("install_targets", new cmInstallTargetsCommand);
   state->AddBuiltinCommand("link_directories", new cmLinkDirectoriesCommand);
   state->AddBuiltinCommand("project", new cmProjectCommand);
-  state->AddBuiltinCommand("set_directory_properties",
-                           new cmSetDirectoryPropertiesCommand);
   state->AddBuiltinCommand("set_source_files_properties",
                            new cmSetSourceFilesPropertiesCommand);
   state->AddBuiltinCommand("set_target_properties",
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index 9e6560f..ce9bc87 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -788,7 +788,7 @@
     std::string propval;
     if (auto* p = target->GetProperty("COMMON_LANGUAGE_RUNTIME")) {
       propval = p;
-    } else if (target->HasLanguage("CSharp", config)) {
+    } else if (target->IsCSharpOnly()) {
       // C# projects do not have the /clr flag, so we set the property
       // here to mark the target as (only) managed (i.e. no .lib file
       // to link to). Otherwise the  COMMON_LANGUAGE_RUNTIME target
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index 8aab1be..9918b87 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -5221,20 +5221,23 @@
   }
 }
 
-bool cmGeneratorTarget::HasLanguage(std::string const& language,
-                                    std::string const& config,
-                                    bool exclusive) const
+bool cmGeneratorTarget::IsCSharpOnly() const
 {
-  std::set<std::string> languages;
-  this->GetLanguages(languages, config);
-  // The "exclusive" check applies only to source files and not
-  // the linker language which may be affected by dependencies.
-  if (exclusive && languages.size() > 1) {
+  // Only certain target types may compile CSharp.
+  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
     return false;
   }
-  // add linker language (if it is different from compiler languages)
-  languages.insert(this->GetLinkerLanguage(config));
-  return languages.count(language) > 0;
+  std::set<std::string> languages;
+  this->GetLanguages(languages, "");
+  // Consider an explicit linker language property, but *not* the
+  // computed linker language that may depend on linked targets.
+  const char* linkLang = this->GetProperty("LINKER_LANGUAGE");
+  if (linkLang && *linkLang) {
+    languages.insert(linkLang);
+  }
+  return languages.size() == 1 && languages.count("CSharp") > 0;
 }
 
 void cmGeneratorTarget::ComputeLinkImplementationLanguages(
@@ -5555,6 +5558,5 @@
   // C# targets are always managed. This language specific check
   // is added to avoid that the COMMON_LANGUAGE_RUNTIME target property
   // has to be set manually for C# targets.
-  return this->HasLanguage("CSharp", config) ? ManagedType::Managed
-                                             : ManagedType::Native;
+  return this->IsCSharpOnly() ? ManagedType::Managed : ManagedType::Native;
 }
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 2810887..14197f8 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -364,11 +364,7 @@
   void GetLanguages(std::set<std::string>& languages,
                     std::string const& config) const;
 
-  // Evaluate if the target uses the given language for compilation
-  // and/or linking. If 'exclusive' is true, 'language' is expected
-  // to be the only language used in source files for the target.
-  bool HasLanguage(std::string const& language, std::string const& config,
-                   bool exclusive = true) const;
+  bool IsCSharpOnly() const;
 
   void GetObjectLibrariesCMP0026(
     std::vector<cmGeneratorTarget*>& objlibs) const;
diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx
index 0b086b0..ba12fac 100644
--- a/Source/cmGlobalVisualStudio71Generator.cxx
+++ b/Source/cmGlobalVisualStudio71Generator.cxx
@@ -98,7 +98,7 @@
     ext = ".vfproj";
     project = "Project(\"{6989167D-11E4-40FE-8C1A-2192A86A7E90}\") = \"";
   }
-  if (t->HasLanguage("CSharp", "")) {
+  if (t->IsCSharpOnly()) {
     ext = ".csproj";
     project = "Project(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"";
   }
diff --git a/Source/cmLinkLineDeviceComputer.cxx b/Source/cmLinkLineDeviceComputer.cxx
index 557fa41..20bd537 100644
--- a/Source/cmLinkLineDeviceComputer.cxx
+++ b/Source/cmLinkLineDeviceComputer.cxx
@@ -23,6 +23,23 @@
 {
 }
 
+static bool cmLinkItemValidForDevice(std::string const& item)
+{
+  // Valid items are:
+  // * Non-flags (does not start in '-')
+  // * Specific flags --library, --library-path, -l, -L
+  // For example:
+  // * 'cublas_device' => pass-along
+  // * '--library pthread' => pass-along
+  // * '-lpthread' => pass-along
+  // * '-pthread' => drop
+  // * '-a' => drop
+  return (!cmHasLiteralPrefix(item, "-") || //
+          cmHasLiteralPrefix(item, "-l") || //
+          cmHasLiteralPrefix(item, "-L") || //
+          cmHasLiteralPrefix(item, "--library"));
+}
+
 std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
   cmComputeLinkInformation& cli, std::string const& stdLibString)
 {
@@ -51,16 +68,16 @@
     }
 
     if (item.IsPath) {
-      // nvcc understands absolute paths to libraries ending in '.a' should
-      // be passed to nvlink.  Other extensions like '.so' or '.dylib' are
-      // rejected by the nvcc front-end even though nvlink knows to ignore
-      // them.  Bypass the front-end via '-Xnvlink'.
-      if (!cmHasLiteralSuffix(item.Value, ".a")) {
-        fout << "-Xnvlink ";
+      // nvcc understands absolute paths to libraries ending in '.a' or '.lib'.
+      // These should be passed to nvlink.  Other extensions need to be left
+      // out because nvlink may not understand or need them.  Even though it
+      // can tolerate '.so' or '.dylib' it cannot tolerate '.so.1'.
+      if (cmHasLiteralSuffix(item.Value, ".a") ||
+          cmHasLiteralSuffix(item.Value, ".lib")) {
+        fout << this->ConvertToOutputFormat(
+          this->ConvertToLinkReference(item.Value));
       }
-      fout << this->ConvertToOutputFormat(
-        this->ConvertToLinkReference(item.Value));
-    } else {
+    } else if (cmLinkItemValidForDevice(item.Value)) {
       fout << item.Value;
     }
     fout << " ";
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index b2f6091..a32e04a 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -497,6 +497,16 @@
   return commandNames;
 }
 
+void cmState::RemoveBuiltinCommand(std::string const& name)
+{
+  assert(name == cmSystemTools::LowerCase(name));
+  std::map<std::string, cmCommand*>::iterator i =
+    this->BuiltinCommands.find(name);
+  assert(i != this->BuiltinCommands.end());
+  delete i->second;
+  this->BuiltinCommands.erase(i);
+}
+
 void cmState::RemoveUserDefinedCommands()
 {
   cmDeleteAll(this->ScriptedCommands);
diff --git a/Source/cmState.h b/Source/cmState.h
index 38bdfec..b20e8c6 100644
--- a/Source/cmState.h
+++ b/Source/cmState.h
@@ -135,6 +135,7 @@
                             cmPolicies::PolicyID policy, const char* message);
   void AddUnexpectedCommand(std::string const& name, const char* error);
   void AddScriptedCommand(std::string const& name, cmCommand* command);
+  void RemoveBuiltinCommand(std::string const& name);
   void RemoveUserDefinedCommands();
   std::vector<std::string> GetCommandNames() const;
 
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 72fd2bb..75c8caf 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1703,6 +1703,32 @@
   fflush(out);
 }
 
+bool la_diagnostic(struct archive* ar, __LA_SSIZE_T r)
+{
+  // See archive.h definition of ARCHIVE_OK for return values.
+
+  if (r >= ARCHIVE_OK) {
+    return true;
+  }
+
+  if (r >= ARCHIVE_WARN) {
+    const char* warn = archive_error_string(ar);
+    if (!warn) {
+      warn = "unknown warning";
+    }
+    std::cerr << "cmake -E tar: warning: " << warn << '\n';
+    return true;
+  }
+
+  // Error.
+  const char* err = archive_error_string(ar);
+  if (!err) {
+    err = "unknown error";
+  }
+  std::cerr << "cmake -E tar: error: " << err << '\n';
+  return false;
+}
+
 // Return 'true' on success
 bool copy_data(struct archive* ar, struct archive* aw)
 {
@@ -1716,24 +1742,17 @@
 #  endif
 
   for (;;) {
-    // Return value:
-    // * ARCHIVE_OK - read succeed
-    // * ARCHIVE_EOF - no more data to read left
+    // See archive.h definition of ARCHIVE_OK for return values.
     r = archive_read_data_block(ar, &buff, &size, &offset);
     if (r == ARCHIVE_EOF) {
       return true;
     }
-    if (r != ARCHIVE_OK) {
+    if (!la_diagnostic(ar, r)) {
       return false;
     }
-    // Return value:
-    // * >= ARCHIVE_OK - write succeed
-    // * < ARCHIVE_OK - write failed
-    const __LA_SSIZE_T w_size =
-      archive_write_data_block(aw, buff, size, offset);
-    if (w_size < ARCHIVE_OK) {
-      cmSystemTools::Message("archive_write_data_block()",
-                             archive_error_string(aw));
+    // See archive.h definition of ARCHIVE_OK for return values.
+    __LA_SSIZE_T const w = archive_write_data_block(aw, buff, size, offset);
+    if (!la_diagnostic(ar, w)) {
       return false;
     }
   }
@@ -1792,7 +1811,6 @@
       r = archive_write_header(ext, entry);
       if (r == ARCHIVE_OK) {
         if (!copy_data(a, ext)) {
-          cmSystemTools::Error("Problem with copy_data");
           break;
         }
         r = archive_write_finish_entry(ext);
diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx
index b8b04ae..c455fa2 100644
--- a/Source/cmVisualStudio10TargetGenerator.cxx
+++ b/Source/cmVisualStudio10TargetGenerator.cxx
@@ -215,12 +215,11 @@
   return cmSystemTools::Strucmp(ext.c_str(), ".targets") == 0;
 }
 
-static std::string computeProjectFileExtension(cmGeneratorTarget const* t,
-                                               const std::string& config)
+static std::string computeProjectFileExtension(cmGeneratorTarget const* t)
 {
   std::string res;
   res = ".vcxproj";
-  if (t->HasLanguage("CSharp", config)) {
+  if (t->IsCSharpOnly()) {
     res = ".csproj";
   }
   return res;
@@ -316,8 +315,8 @@
       this->GeneratorTarget->GetProperty("EXTERNAL_MSPROJECT")) {
     return;
   }
-  const std::string ProjectFileExtension = computeProjectFileExtension(
-    this->GeneratorTarget, *this->Configurations.begin());
+  const std::string ProjectFileExtension =
+    computeProjectFileExtension(this->GeneratorTarget);
   if (ProjectFileExtension == ".vcxproj") {
     this->ProjectType = vcxproj;
     this->Managed = false;
@@ -1399,8 +1398,7 @@
   std::string path = this->LocalGenerator->GetCurrentBinaryDirectory();
   path += "/";
   path += this->Name;
-  path += computeProjectFileExtension(this->GeneratorTarget,
-                                      *this->Configurations.begin());
+  path += computeProjectFileExtension(this->GeneratorTarget);
   path += ".filters";
   cmGeneratedFileStream fout(path.c_str());
   fout.SetCopyIfDifferent(true);
@@ -3734,7 +3732,7 @@
       path = lg->GetCurrentBinaryDirectory();
       path += "/";
       path += dt->GetName();
-      path += computeProjectFileExtension(dt, *this->Configurations.begin());
+      path += computeProjectFileExtension(dt);
     }
     ConvertToWindowsSlash(path);
     Elem e2(e1, "ProjectReference");
@@ -3761,7 +3759,7 @@
       // Workaround for static library C# targets
       if (referenceNotManaged &&
           dt->GetType() == cmStateEnums::STATIC_LIBRARY) {
-        referenceNotManaged = !dt->HasLanguage("CSharp", "");
+        referenceNotManaged = !dt->IsCSharpOnly();
       }
       if (referenceNotManaged) {
         e2.Element("ReferenceOutputAssembly", "false");
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 637c5c2..6122350 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -171,6 +171,7 @@
 if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF")
   add_RunCMake_test(RuntimePath)
 endif()
+add_RunCMake_test(ScriptMode)
 add_RunCMake_test(Swift)
 add_RunCMake_test(TargetObjects)
 add_RunCMake_test(TargetSources)
diff --git a/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake b/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake
index fa5618a..ab3e51b 100644
--- a/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CSharpCustomCommand/RunCMakeTest.cmake
@@ -1,5 +1,13 @@
 include(RunCMake)
 
+function(run_TargetWithCommand)
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/TargetWithCommand-build)
+  run_cmake(TargetWithCommand)
+  set(RunCMake_TEST_NO_CLEAN 1)
+  run_cmake_command(TargetWithCommand-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+run_TargetWithCommand()
+
 # Use a single build tree for a few tests without cleaning.
 set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/CommandWithOutput-build)
 set(RunCMake_TEST_NO_CLEAN 1)
diff --git a/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt
new file mode 100644
index 0000000..c212a8f
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand-build-stdout.txt
@@ -0,0 +1 @@
+Custom target with CSharp source
diff --git a/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake
new file mode 100644
index 0000000..fdaea5c
--- /dev/null
+++ b/Tests/RunCMake/CSharpCustomCommand/TargetWithCommand.cmake
@@ -0,0 +1,4 @@
+enable_language(CSharp)
+
+add_custom_target(drive ALL SOURCES dummy.cs
+  COMMAND ${CMAKE_COMMAND} -E echo "Custom target with CSharp source")
diff --git a/Tests/RunCMake/ScriptMode/RunCMakeTest.cmake b/Tests/RunCMake/ScriptMode/RunCMakeTest.cmake
new file mode 100644
index 0000000..4c44ffb
--- /dev/null
+++ b/Tests/RunCMake/ScriptMode/RunCMakeTest.cmake
@@ -0,0 +1,3 @@
+include(RunCMake)
+
+run_cmake_command(set_directory_properties ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/set_directory_properties.cmake)
diff --git a/Tests/RunCMake/ScriptMode/set_directory_properties.cmake b/Tests/RunCMake/ScriptMode/set_directory_properties.cmake
new file mode 100644
index 0000000..bf79317
--- /dev/null
+++ b/Tests/RunCMake/ScriptMode/set_directory_properties.cmake
@@ -0,0 +1 @@
+set_directory_properties(PROPERTIES SOME_PROPERTY FALSE)