Generate dependency scanning hooks in the Ninja file.
diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py
index 7fb1597..91d72e0 100644
--- a/mesonbuild/backend/ninjabackend.py
+++ b/mesonbuild/backend/ninjabackend.py
@@ -112,7 +112,7 @@
 # variables (or variables we use them in) is interpreted directly by ninja
 # (e.g. the value of the depfile variable is a pathname that ninja will read
 # from, etc.), so it must not be shell quoted.
-raw_names = {'DEPFILE_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep'}
+raw_names = {'DEPFILE_UNQUOTED', 'DESC', 'pool', 'description', 'targetdep', 'dyndep'}
 
 NINJA_QUOTE_BUILD_PAT = re.compile(r"[$ :\n]")
 NINJA_QUOTE_VAR_PAT = re.compile(r"[$ \n]")
@@ -492,7 +492,7 @@
     def generate(self):
         ninja = environment.detect_ninja_command_and_version(log=True)
         if ninja is None:
-            raise MesonException('Could not detect Ninja v1.7 or newer')
+            raise MesonException('Could not detect Ninja v1.10 or newer')
         (self.ninja_command, self.ninja_version) = ninja
         outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
         tempfilename = outfilename + '~'
@@ -500,7 +500,7 @@
             outfile.write('# This is the build file for project "{}"\n'.format(self.build.get_project()))
             outfile.write('# It is autogenerated by the Meson build system.\n')
             outfile.write('# Do not edit by hand.\n\n')
-            outfile.write('ninja_required_version = 1.7.1\n\n')
+            outfile.write('ninja_required_version = 1.10.1\n\n')
 
             num_pools = self.environment.coredata.backend_options['backend_max_links'].value
             if num_pools > 0:
@@ -687,6 +687,8 @@
             self.generate_custom_target(target)
         if isinstance(target, build.RunTarget):
             self.generate_run_target(target)
+        compiled_sources = []
+        source2object = {}
         name = target.get_id()
         if name in self.processed_targets:
             return
@@ -784,10 +786,12 @@
         # because we need `header_deps` to be fully generated in the above loop.
         for src in generated_source_files:
             if self.environment.is_llvm_ir(src):
-                o = self.generate_llvm_ir_compile(target, src)
+                o, s = self.generate_llvm_ir_compile(target, src)
             else:
-                o = self.generate_single_compile(target, src, True,
+                o, s = self.generate_single_compile(target, src, True,
                                                  order_deps=header_deps)
+            compiled_sources.append(s)
+            source2object[s] = o
             obj_list.append(o)
 
         use_pch = self.environment.coredata.base_options.get('b_pch', False)
@@ -822,7 +826,8 @@
             # Passing 'vala' here signifies that we want the compile
             # arguments to be specialized for C code generated by
             # valac. For instance, no warnings should be emitted.
-            obj_list.append(self.generate_single_compile(target, src, 'vala', [], header_deps))
+            o, s = self.generate_single_compile(target, src, 'vala', [], header_deps)
+            obj_list.append(o)
 
         # Generate compile targets for all the pre-existing sources for this target
         for src in target_sources.values():
@@ -834,16 +839,32 @@
                                            src.rel_to_builddir(self.build_to_src))
                     unity_src.append(abs_src)
                 else:
-                    obj_list.append(self.generate_single_compile(target, src, False, [], header_deps))
+                    o, s = self.generate_single_compile(target, src, False, [], header_deps)
+                    obj_list.append(o)
+                    compiled_sources.append(s)
+                    source2object[src] = o
+
         obj_list += self.flatten_object_list(target)
         if is_unity:
             for src in self.generate_unity_files(target, unity_src):
-                obj_list.append(self.generate_single_compile(target, src, True, unity_deps + header_deps))
+                o, s = self.generate_single_compile(target, src, True, unity_deps + header_deps)
+                obj_list.append(o)
+                compiled_sources.append(s)
+                source2object[src] = o
         linker, stdlib_args = self.determine_linker_and_stdlib_args(target)
+        self.generate_dependency_scan_target(target, compiled_sources, source2object)
         elem = self.generate_link(target, outname, obj_list, linker, pch_objects, stdlib_args=stdlib_args)
         self.generate_shlib_aliases(target, self.get_target_dir(target))
         self.add_build(elem)
 
+    def generate_dependency_scan_target(self, target, compiled_sources, source2object):
+        if 'cpp' not in target.compilers:
+            return
+        depscan_file = self.get_dep_scan_file_for(target)
+        rule_name = 'cppscan'
+        elem = NinjaBuildElement(self.all_outputs, depscan_file, rule_name, compiled_sources)
+        self.add_build(elem)
+
     def process_target_dependencies(self, target):
         for t in target.get_dependencies():
             if t.get_id() not in self.processed_targets:
@@ -2237,7 +2258,7 @@
         element = NinjaBuildElement(self.all_outputs, rel_obj, compiler_name, rel_src)
         element.add_item('ARGS', commands)
         self.add_build(element)
-        return rel_obj
+        return (rel_obj, rel_src)
 
     def get_source_dir_include_args(self, target, compiler):
         curdir = target.get_subdir()
@@ -2459,8 +2480,20 @@
             element.add_orderdep(i)
         element.add_item('DEPFILE', dep_file)
         element.add_item('ARGS', commands)
+
+        self.add_dependency_scanner_entries_to_element(target, compiler, element)
         self.add_build(element)
-        return rel_obj
+        return (rel_obj, rel_src)
+
+    def add_dependency_scanner_entries_to_element(self, target, compiler, element):
+        if compiler.get_language() != 'cpp':
+            return
+        dep_scan_file = self.get_dep_scan_file_for(target)
+        element.add_item('dyndep', dep_scan_file)
+        element.add_orderdep(dep_scan_file)
+
+    def get_dep_scan_file_for(self, target):
+        return os.path.join(self.get_target_private_dir(target), 'depscan.dd')
 
     def add_header_deps(self, target, ninja_element, header_deps):
         for d in header_deps:
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 7194d03..f78d8ed 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -179,7 +179,7 @@
     r = detect_ninja_command_and_version(version, log)
     return r[0] if r else None
 
-def detect_ninja_command_and_version(version: str = '1.7', log: bool = False) -> (T.List[str], str):
+def detect_ninja_command_and_version(version: str = '1.10.1', log: bool = False) -> (T.List[str], str):
     from .dependencies.base import ExternalProgram
     env_ninja = os.environ.get('NINJA', None)
     for n in [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu']: