Merge topic 'fix-legacy-implicit-includes'

6fc3382944 Update logic for sysroot in detected implicit include directories
2ad14ef4ea cmAlgorithms: Add cmHasPrefix to match existing cmHasSuffix
557b2d6e65 Fix regression in -I/usr/include exclusion logic
017598a444 macOS: Fix addition of <sdk>/usr/include to default implicit include dirs

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2957
diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake
index a73ffba..5590433 100644
--- a/Modules/Platform/Darwin.cmake
+++ b/Modules/Platform/Darwin.cmake
@@ -214,7 +214,7 @@
 if(_CMAKE_OSX_SYSROOT_PATH AND EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
   list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${_CMAKE_OSX_SYSROOT_PATH}/usr)
   foreach(lang C CXX)
-    list(APPEND CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
+    list(APPEND _CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT ${_CMAKE_OSX_SYSROOT_PATH}/usr/include)
   endforeach()
 endif()
 list(APPEND CMAKE_SYSTEM_PREFIX_PATH
diff --git a/Modules/Platform/UnixPaths.cmake b/Modules/Platform/UnixPaths.cmake
index 4ae4514..46c24bb 100644
--- a/Modules/Platform/UnixPaths.cmake
+++ b/Modules/Platform/UnixPaths.cmake
@@ -63,11 +63,6 @@
   /lib /lib32 /lib64 /usr/lib /usr/lib32 /usr/lib64
   )
 
-# Platform-wide directories to avoid adding via -I<dir>.
-list(APPEND CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES
-  /usr/include
-  )
-
 # Default per-language values.  These may be later replaced after
 # parsing the implicit directory information from compiler output.
 set(_CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES_INIT
diff --git a/Source/cmAlgorithms.h b/Source/cmAlgorithms.h
index 30328c6..1c4160b 100644
--- a/Source/cmAlgorithms.h
+++ b/Source/cmAlgorithms.h
@@ -348,6 +348,14 @@
   return std::reverse_iterator<Iter>(it);
 }
 
+inline bool cmHasPrefix(std::string const& str, std::string const& prefix)
+{
+  if (str.size() < prefix.size()) {
+    return false;
+  }
+  return str.compare(0, prefix.size(), prefix) == 0;
+}
+
 inline bool cmHasSuffix(const std::string& str, const std::string& suffix)
 {
   if (str.size() < suffix.size()) {
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index ba3c574..a2d0efe 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -935,16 +935,11 @@
     } else {
       rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
     }
+    cmSystemTools::ConvertToUnixSlashes(rootPath);
 
     // Raw list of implicit include directories
     std::vector<std::string> impDirVec;
 
-    // Get platform-wide implicit directories.
-    if (const char* implicitIncludes = (this->Makefile->GetDefinition(
-          "CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES"))) {
-      cmSystemTools::ExpandListArgument(implicitIncludes, impDirVec);
-    }
-
     // Load implicit include directories for this language.
     std::string key = "CMAKE_";
     key += lang;
@@ -953,9 +948,28 @@
       cmSystemTools::ExpandListArgument(value, impDirVec);
     }
 
+    // The Platform/UnixPaths module used to hard-code /usr/include for C, CXX,
+    // and CUDA in CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES, but those
+    // variables are now computed.  On macOS the /usr/include directory is
+    // inside the platform SDK so the computed value does not contain it
+    // directly.  In this case adding -I/usr/include can hide SDK headers so we
+    // must still exclude it.
+    if ((lang == "C" || lang == "CXX" || lang == "CUDA") &&
+        std::find(impDirVec.begin(), impDirVec.end(), "/usr/include") ==
+          impDirVec.end() &&
+        std::find_if(impDirVec.begin(), impDirVec.end(),
+                     [](std::string const& d) {
+                       return cmHasLiteralSuffix(d, "/usr/include");
+                     }) != impDirVec.end()) {
+      impDirVec.emplace_back("/usr/include");
+    }
+
     for (std::string const& i : impDirVec) {
-      std::string imd = rootPath + i;
+      std::string imd = i;
       cmSystemTools::ConvertToUnixSlashes(imd);
+      if (!rootPath.empty() && !cmHasPrefix(imd, rootPath)) {
+        imd = rootPath + imd;
+      }
       if (implicitSet.insert(imd).second) {
         implicitDirs.emplace_back(std::move(imd));
       }