Browse Source

Do not exclude include directories made implicit by CPATH

Entries of the `CPATH` environment variable are implicitly searched as
include directories by some C/C++ compilers.  Since commit 5990ecb741
(Compute implicit include directories from compiler output, 2018-12-07,
v3.14.0-rc1~108^2) these entries are detected by CMake and included in
the `CMAKE_{C,CXX}_IMPLICIT_INCLUDE_DIRECTORIES` variables.

However, we should not exclude them from explicit specification via `-I`
or particularly `-isystem` because they are meant as user-specified
include directories that can be re-ordered without breaking compiler
builtin headers.  In particular, we need explicit requests via
`include_directories` with the `SYSTEM` option to result in `-isystem`
so that third-party headers do not produce warnings.

Co-Author: Ben Boeckel <[email protected]>
Fixes: #19291
Brad King 6 years ago
parent
commit
2d0b0e2b9d

+ 8 - 0
Help/release/3.14.rst

@@ -412,3 +412,11 @@ Changes made since CMake 3.14.0 include the following.
   incorrectly propagate usage requirements of those dependencies to
   dependents that link the static library.  This has been fixed.
   The bug also existed in 3.13.0 through 3.13.4 and is fixed in 3.13.5.
+
+3.14.5
+------
+
+* Entries of the ``CPATH`` environment variable are no longer excluded
+  from explicit use via :command:`include_directories` and
+  :command:`target_include_directories` as they were in CMake 3.14.0
+  through 3.14.4.

+ 25 - 3
Source/cmLocalGenerator.cxx

@@ -88,6 +88,19 @@ cmLocalGenerator::cmLocalGenerator(cmGlobalGenerator* gg, cmMakefile* makefile)
 
   this->ComputeObjectMaxPath();
 
+  // Canonicalize entries of the CPATH environment variable the same
+  // way detection of CMAKE_<LANG>_IMPLICIT_INCLUDE_DIRECTORIES does.
+  {
+    std::vector<std::string> cpath;
+    cmSystemTools::GetPath(cpath, "CPATH");
+    for (std::string& cp : cpath) {
+      if (cmSystemTools::FileIsFullPath(cp)) {
+        cp = cmSystemTools::CollapseFullPath(cp);
+        this->EnvCPATH.emplace(std::move(cp));
+      }
+    }
+  }
+
   std::vector<std::string> enabledLanguages =
     this->GetState()->GetEnabledLanguages();
 
@@ -988,9 +1001,18 @@ std::vector<BT<std::string>> cmLocalGenerator::GetIncludeDirectoriesImplicit(
   }
 
   // Checks if this is not an excluded (implicit) include directory.
-  auto notExcluded = [&implicitSet, &implicitExclude](std::string const& dir) {
-    return ((implicitSet.find(dir) == implicitSet.end()) &&
-            (implicitExclude.find(dir) == implicitExclude.end()));
+  auto notExcluded = [this, &implicitSet, &implicitExclude,
+                      &lang](std::string const& dir) {
+    return (
+      // Do not exclude directories that are not in an excluded set.
+      ((implicitSet.find(dir) == implicitSet.end()) &&
+       (implicitExclude.find(dir) == implicitExclude.end()))
+      // Do not exclude entries of the CPATH environment variable even though
+      // they are implicitly searched by the compiler.  They are meant to be
+      // user-specified directories that can be re-ordered or converted to
+      // -isystem without breaking real compiler builtin headers.
+      || ((lang == "C" || lang == "CXX") &&
+          (this->EnvCPATH.find(dir) != this->EnvCPATH.end())));
   };
 
   // Get the target-specific include directories.

+ 2 - 0
Source/cmLocalGenerator.h

@@ -429,6 +429,8 @@ protected:
   std::string::size_type ObjectPathMax;
   std::set<std::string> ObjectMaxPathViolations;
 
+  std::set<std::string> EnvCPATH;
+
   typedef std::unordered_map<std::string, cmGeneratorTarget*>
     GeneratorTargetMap;
   GeneratorTargetMap GeneratorTargetSearchIndex;

+ 18 - 0
Tests/CMakeLists.txt

@@ -3620,6 +3620,24 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
     --test-command IncludeDirectories)
   list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectories")
 
+  if(CMAKE_GENERATOR MATCHES "^((Unix|MSYS) Makefiles|Ninja)$" AND
+     ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.4)
+      OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC")
+      OR (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")))
+    add_test(IncludeDirectoriesCPATH ${CMAKE_CTEST_COMMAND}
+      --build-and-test
+      "${CMake_SOURCE_DIR}/Tests/IncludeDirectoriesCPATH"
+      "${CMake_BINARY_DIR}/Tests/IncludeDirectoriesCPATH"
+      --build-two-config
+      ${build_generator_args}
+      --build-project IncludeDirectoriesCPATH
+      --build-options ${build_options})
+    list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/IncludeDirectoriesCPATH")
+    set_tests_properties(IncludeDirectoriesCPATH
+      PROPERTIES
+        ENVIRONMENT "CPATH=${CMAKE_CURRENT_SOURCE_DIR}/IncludeDirectoriesCPATH/viacpath")
+  endif()
+
   add_test(InterfaceLinkLibraries ${CMAKE_CTEST_COMMAND}
     --build-and-test
     "${CMake_SOURCE_DIR}/Tests/InterfaceLinkLibraries"

+ 22 - 0
Tests/IncludeDirectoriesCPATH/CMakeLists.txt

@@ -0,0 +1,22 @@
+cmake_minimum_required (VERSION 3.14)
+project(IncludeDirectoriesCPATH CXX)
+message(STATUS "ENV{CPATH}: '$ENV{CPATH}'")
+message(STATUS "CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES: '${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}'")
+
+include(CheckCXXCompilerFlag)
+check_cxx_compiler_flag(-Wunused-variable run_sys_includes_test)
+if(run_sys_includes_test)
+  # The Bullseye wrapper appears to break the -isystem effect.
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER} --version OUTPUT_VARIABLE out ERROR_VARIABLE out)
+  if("x${out}" MATCHES "Bullseye")
+    set(run_sys_includes_test 0)
+  endif()
+endif()
+if (NOT run_sys_includes_test)
+  return()
+endif()
+
+add_library(consumer consumer.cpp)
+add_library(consumer_system consumer.cpp)
+target_compile_options(consumer_system PRIVATE -Werror=unused-variable)
+target_include_directories(consumer_system SYSTEM PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/viacpath")

+ 6 - 0
Tests/IncludeDirectoriesCPATH/consumer.cpp

@@ -0,0 +1,6 @@
+#include "systemlib.h"
+
+int consumer()
+{
+  return systemlib();
+}

+ 15 - 0
Tests/IncludeDirectoriesCPATH/viacpath/systemlib.h

@@ -0,0 +1,15 @@
+#ifndef SYSTEMLIB_H
+#define SYSTEMLIB_H
+
+int systemlib()
+{
+  return 0;
+}
+
+int unusedFunc()
+{
+  int unused;
+  return systemlib();
+}
+
+#endif