Repository: mesonbuild/meson

Issue:
PCH together with -isystem/usr/include: fatal error: stdlib.h: No such file or directory
In my project I get the error: `stdlib.h: No such file or directory`. I tracked this down to the fact that it only happens if I compile with precompiled headers and if this command includes `-isystem/usr/include`.

**To Reproduce**
I have made an MWE:

```
$ tree
├── meson.build
├── pch
│   └── test.h
└── reproducer.cc
```

meson.build:
```
project('reproducer', 'cpp',
  version : '0.1',
  default_options : ['warning_level=3'])

boost_dep = dependency('boost', modules: ['graph'], include_type: 'system')

exe = executable('reproducer', 'reproducer.cc',
  install : true,
  cpp_pch: 'pch/test.h',
  dependencies: boost_dep)

test('basic', exe)
```

test.h
```
#include <boost/graph/filtered_graph.hpp>
```

reproducer.cc
```
#include <boost/graph/filtered_graph.hpp>

int main() {}
```

**Actual behavior**
```
$ meson build
The Meson build system
Version: 0.54.2
Source dir: /home/ci3nt/test/reproducer
Build dir: /home/ci3nt/test/reproducer/build
Build type: native build
Project name: reproducer
Project version: 0.1
C++ compiler for the host machine: ccache c++ (gcc 9.3.0 "c++ (Gentoo 9.3.0 p2) 9.3.0")
C++ linker for the host machine: c++ ld.bfd 2.33.1
Host machine cpu family: x86_64
Host machine cpu: x86_64
Run-time dependency Boost (found: graph) found: YES 1.72.0 (/usr)
Build targets in project: 1

Found ninja-1.10.0 at /usr/bin/ninja
$ cd build && ninja
[1/3] Precompiling header ../pch/test.h
FAILED: reproducer@exe/test.h.gch 
ccache c++ -Ireproducer@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -g -isystem/usr/include -DBOOST_ALL_NO_LIB -x c++-header -MD -MQ 'reproducer@exe/test.h.gch' -MF 'reproducer@exe/test.h.gch.d' -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
In file included from /usr/include/boost/config/platform/linux.hpp:15,
                 from /usr/include/boost/config.hpp:57,
                 from /usr/include/boost/graph/graph_traits.hpp:13,
                 from /usr/include/boost/graph/filtered_graph.hpp:13,
                 from ../pch/test.h:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/include/g++-v9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
   75 | #include_next <stdlib.h>
      |               ^~~~~~~~~~
compilation terminated.
ninja: build stopped: subcommand failed.
$ meson configure -Db_pch=false
$ ninja -v
[1/2] ccache c++ -Ireproducer@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -g -DBOOST_ALL_NO_LIB -MD -MQ 'reproducer@exe/reproducer.cc.o' -MF 'reproducer@exe/reproducer.cc.o.d' -o 'reproducer@exe/reproducer.cc.o' -c ../reproducer.cc
[2/2] c++  -o reproducer 'reproducer@exe/reproducer.cc.o' -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group /usr/lib64/libboost_graph.so.1.72.0 -Wl,--end-group
$ g++ -Ireproducer@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -g -isystem/usr/include -DBOOST_ALL_NO_LIB -x c++-header -MD -MQ 'reproducer@exe/test.h.gch' -MF 'reproducer@exe/test.h.gch.d' -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
In file included from /usr/include/boost/config/platform/linux.hpp:15,
                 from /usr/include/boost/config.hpp:57,
                 from /usr/include/boost/graph/graph_traits.hpp:13,
                 from /usr/include/boost/graph/filtered_graph.hpp:13,
                 from ../pch/test.h:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/include/g++-v9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
   75 | #include_next <stdlib.h>
      |               ^~~~~~~~~~
compilation terminated.
$ # note that in the next command only -isystem/usr/include is missing
$ g++ -Ireproducer@exe -I. -I.. -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -Wextra -Wpedantic -g -DBOOST_ALL_NO_LIB -x c++-header -MD -MQ 'reproducer@exe/test.h.gch' -MF 'reproducer@exe/test.h.gch.d' -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
<works>
$ g++ -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
<works>
$ g++ -isystem/usr/include -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
In file included from /usr/include/boost/config/platform/linux.hpp:15,
                 from /usr/include/boost/config.hpp:57,
                 from /usr/include/boost/graph/graph_traits.hpp:13,
                 from /usr/include/boost/graph/filtered_graph.hpp:13,
                 from ../pch/test.h:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.3.0/include/g++-v9/cstdlib:75:15: fatal error: stdlib.h: No such file or directory
   75 | #include_next <stdlib.h>
      |               ^~~~~~~~~~
compilation terminated.
$ g++ -I/usr/include -o 'reproducer@exe/test.h.gch' -c ../pch/test.h
<works>
```

**Expected behavior**
It should work in all cases.

I'm not sure, if this is a problem of my toolchain and why this error happens. Maybe you have an idea. If I drop the `include_type: 'system'` keyword argument in the meson.build, everything works. However, other includes with `isystem` don't make problems. In my real project also Python and LLVM are included with `isystem` without problems.

**system parameters**
* OS: Gentoo
* Python: multiple, meson uses 3.8.2
* `meson --version`: 0.54.2
* `ninja --version`: 1.10.0
* gcc: 9.3.0


Discussion:
Could you please post the output of `gcc -xc -E -v - < /dev/null`? Meson should automatically filter out all system include paths.

Resolving patch:
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -151,6 +151,10 @@ def add_orderdep(self, dep):
             self.orderdeps.add(dep)
 
     def add_item(self, name, elems):
+        # Always convert from GCC-style argument naming to the naming used by the
+        # current compiler. Also filter system include paths, deduplicate, etc.
+        if isinstance(elems, CompilerArgs):
+            elems = elems.to_native()
         if isinstance(elems, str):
             elems = [elems]
         self.elems.append((name, elems))
@@ -1985,9 +1989,6 @@ def generate_llvm_ir_compile(self, target, src):
         # Write the Ninja build command
         compiler_name = self.get_compiler_rule_name('llvm_ir', compiler.for_machine)
         element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
-        # Convert from GCC-style link argument naming to the naming used by the
-        # current compiler.
-        commands = commands.to_native()
         element.add_item('ARGS', commands)
         self.add_build(element)
         return rel_obj
@@ -2204,9 +2205,6 @@ def generate_single_compile(self, target, src, is_generated=False, header_deps=N
                 d = os.path.join(self.get_target_private_dir(target), d)
             element.add_orderdep(d)
         element.add_dep(pch_dep)
-        # Convert from GCC-style link argument naming to the naming used by the
-        # current compiler.
-        commands = commands.to_native()
         for i in self.get_fortran_orderdeps(target, compiler):
             element.add_orderdep(i)
         element.add_item('DEPFILE', dep_file)
@@ -2594,9 +2592,6 @@ def generate_link(self, target, outname, obj_list, linker, extra_args=None, stdl
         commands += extra_args
         commands += custom_target_libraries
         commands += stdlib_args # Standard library arguments go last, because they never depend on anything.
-        # Convert from GCC-style link argument naming to the naming used by the
-        # current compiler.
-        commands = commands.to_native()
         dep_targets.extend([self.get_dependency_filename(t) for t in dependencies])
         dep_targets.extend([self.get_dependency_filename(t)
                             for t in target.link_depends])


Test patch:
diff --git a/test cases/common/226 include_type dependency/main.cpp b/test cases/common/226 include_type dependency/main.cpp
new file mode 100644
--- /dev/null
+++ b/test cases/common/226 include_type dependency/main.cpp	
@@ -0,0 +1,8 @@
+#include <iostream>
+#include <boost/graph/filtered_graph.hpp>
+
+using namespace std;
+
+int main(void) {
+  return 0;
+}
diff --git a/test cases/common/226 include_type dependency/meson.build b/test cases/common/226 include_type dependency/meson.build
--- a/test cases/common/226 include_type dependency/meson.build	
+++ b/test cases/common/226 include_type dependency/meson.build	
@@ -4,10 +4,16 @@ project(
 )
 
 dep = dependency('zlib', method: 'pkg-config', required : false)
+boost_dep = dependency('boost', modules: ['graph'], include_type : 'system', required: false)
+
 if not dep.found()
   error('MESON_SKIP_TEST zlib was not found')
 endif
 
+if not boost_dep.found()
+  error('MESON_SKIP_TEST boost was not found')
+endif
+
 assert(dep.include_type() == 'preserve', 'include_type must default to "preserve"')
 
 dep_sys = dep.as_system()
@@ -26,3 +32,7 @@ assert(sp_dep.include_type() == 'preserve', 'default is preserve')
 sp_dep_sys = sp_dep.as_system('system')
 assert(sp_dep_sys.include_type() == 'system', 'changing include_type works')
 assert(sp_dep.include_type() == 'preserve', 'as_system must not mutate the original object')
+
+# Check that PCH works with `include_type : 'system'` See https://github.com/mesonbuild/meson/issues/7167
+main_exe = executable('main_exe', 'main.cpp', cpp_pch: 'pch/test.hpp', dependencies: boost_dep)
+test('main_test', main_exe)
diff --git a/test cases/common/226 include_type dependency/pch/test.hpp b/test cases/common/226 include_type dependency/pch/test.hpp
new file mode 100644
--- /dev/null
+++ b/test cases/common/226 include_type dependency/pch/test.hpp	
@@ -0,0 +1 @@
+#include <boost/graph/filtered_graph.hpp>