Use of -isystem

We had a problem when cross-compiling software against sentry, which
is linked to sentry-targets.cmake causing usage of
$sysroot/usr/include, which causes -isystem to appear early in the
commandline. “gcc -v” shows that when this happens the
$sysroot/usr/include that occured near the end of the search path
(after STL’s $sysroot/usr/include/c++/7.3.0) is the one that gets
dropped. This in turn causes problems for STL headers, as
#include_next <stdlib.h> now fails to find the file, as can be also
seen in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70129

Digging, I found this is caused by Modules/Compiler/GNU.cmake, with a
declaration which I suppose is used in
cmLocalGenerator::GetIncludeFlags(), where a logic says “if
IsSystemIncludeDirectory() use -isystem instead of -I”.

The reason exposed in https://cmake.org/Bug/view.php?id=3453 is “The
-isystem instead of -I is very useful when you compile your own code
with -pedantic warnings and don’t want to see teh warnings noise”.

In bug 3462 (sorry I’m forbidden to use more than 1 link) we learn it was felt not to
be a problem because gcc documentation in 2006 said “If a standard
system include directory, or a directory specified with -isystem, is
also specified with -I, the -I option will be ignored.”

Now in 2020 it says “If you specify other options on the command line,
such as ‘-I’, that affect where the preprocessor searches for header
files, the directory list printed by the ‘-v’ option reflects the
actual search path used by the preprocessor.” which does not seem to
give any such warranty.

In fact, it seems that in the case of double specification of a system
include, the first one is kept, so it seems reasonable that we never
want to add -isystem on a system header, so as to avoid unwanted
side-effects.

Removing this statement causes cmake to use -I instead of -isystem, in which
case it is the system include which is kept, and the build can proceed.
This would be the following patch.

Does it seem reasonable ?

--- cmake-3.10.3.orig/Modules/Compiler/GNU.cmake
+++ cmake-3.10.3/Modules/Compiler/GNU.cmake
@@ -44,9 +44,6 @@ macro(__compiler_gnu lang)
   string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
   set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
   set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
-  if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4) # work around #4462
-    set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
-  endif()
 
   set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES)
   set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER NO)

Removing -isystem in general is not a good solution. That’s supposed to apply to user-provided include directories e.g. for external dependencies.

CMake tries pretty hard not to pass the compiler’s own implicit include directories on the command line at all. We even have CMake Issue 19227 where people want to turn that filtering off.

If CMake is generating an explicit -isystem $sysroot/usr/include when that is one of the compiler’s builtin include directories then something is going wrong with the detection and filtering. In a build tree where this happens, what is the output of the following?

$ grep IMPLICIT_INCLUDE_DIRECTORIES CMakeFiles/*/CMake*Compiler.cmake

Jus nothing:

$ ls CMakeFiles/*/CMake*Compiler.cmake
CMakeFiles/3.10.3/CMakeCCompiler.cmake  CMakeFiles/3.10.3/CMakeCXXCompiler.cmake
$ grep IMPLICIT_INCLUDE_DIRECTORIES CMakeFiles/*/CMake*Compiler.cmake
$

CMakeFiles/3.10.3/CMakeCCompiler.cmake

CMake 3.10 pre-dates the filtering I mentioned. Please try a more recent version.