Bug 1461836 - Check configure dependencies and re-run configure if needed when invoking the Tup backend. draft
authorChris Manchester <cmanchester@mozilla.com>
Mon, 21 May 2018 14:01:56 -0700
changeset 797857 91299bd8a60d8fc14b4443a14e65d0f32cdb7b9b
parent 797856 deca7995870bcb5fbe5436413d3ddcd864b4ac23
push id110605
push userbmo:cmanchester@mozilla.com
push dateMon, 21 May 2018 21:02:30 +0000
bugs1461836
milestone62.0a1
Bug 1461836 - Check configure dependencies and re-run configure if needed when invoking the Tup backend. MozReview-Commit-ID: LHYT3r4u2CY
python/mozbuild/mozbuild/controller/building.py
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -965,43 +965,47 @@ class BuildDriver(MozbuildObject):
                 return 1
 
             if directory is not None:
                 disable_extra_make_dependencies=True
                 directory = mozpath.normsep(directory)
                 if directory.startswith('/'):
                     directory = directory[1:]
 
-            def backend_out_of_date(backend_file):
-                dep_file = '%s.in' % backend_file
-                if not os.path.exists(backend_file):
+            def build_out_of_date(output, dep_file):
+                if not os.path.isfile(output):
                     return True
-                if not os.path.exists(dep_file):
+                if not os.path.isfile(dep_file):
                     return True
 
-                dep_files = None
+                deps = []
                 with open(dep_file, 'r') as fh:
-                    dep_files = fh.read().splitlines()
-                if not dep_files:
-                    return True
+                    deps = fh.read().splitlines()
 
-                mtime = os.path.getmtime(backend_file)
-                for f in dep_files:
-                    if os.path.getmtime(f) > mtime:
+                mtime = os.path.getmtime(output)
+                for f in deps:
+                    try:
+                        dep_mtime = os.path.getmtime(f)
+                    except OSError as e:
+                        if e.errno == errno.ENOENT:
+                            return True
+                        raise
+                    if dep_mtime > mtime:
                         return True
+                return False
 
-                return False
+            def backend_out_of_date(backend_file):
+                dep_file = '%s.in' % backend_file
+                return build_out_of_date(backend_file, dep_file)
 
             def maybe_invoke_backend(active_backend):
                 # Attempt to bypass the make-oriented logic below. Note this
                 # will only succeed in case we're building with a non-make
                 # backend (Tup), and otherwise be harmless.
                 if active_backend:
-                    if 'Make' in active_backend:
-                        return None
                     if backend_out_of_date(mozpath.join(self.topobjdir,
                                                         'backend.%sBackend' %
                                                         active_backend)):
                         print('Build configuration changed. Regenerating backend.')
                         args = [config.substs['PYTHON'],
                                 mozpath.join(self.topobjdir, 'config.status')]
                         self.run_process(args, cwd=self.topobjdir)
                     backend_cls = get_backend_class(active_backend)(config)
@@ -1019,18 +1023,34 @@ class BuildDriver(MozbuildObject):
             if config is None:
                 config_rc = self.configure(buildstatus_messages=True,
                                            line_handler=output.on_line)
                 if config_rc != 0:
                     return config_rc
 
                 config = self.config_environment
 
-            status = maybe_invoke_backend(config.substs.get('BUILD_BACKENDS',
-                                                            [None])[0])
+            status = None
+            active_backend = config.substs.get('BUILD_BACKENDS', [None])[0]
+            if active_backend and 'Make' not in active_backend:
+                # Write out any changes to the current mozconfig in case
+                # they should invalidate configure.
+                self._write_mozconfig_json()
+                # Even if we have a config object, it may be out of date
+                # if something that influences its result has changed.
+                if build_out_of_date(mozpath.join(self.topobjdir,
+                                                  'config.status'),
+                                     mozpath.join(self.topobjdir,
+                                                  'config_status_deps.in')):
+                    config_rc = self.configure(buildstatus_messages=True,
+                                               line_handler=output.on_line)
+                    if config_rc != 0:
+                        return config_rc
+
+                status = maybe_invoke_backend(active_backend)
 
             if what and status is None:
                 # Collect target pairs.
                 target_pairs = []
                 for target in what:
                     path_arg = self._wrap_path_argument(target)
 
                     if directory is not None:
@@ -1315,16 +1335,25 @@ class BuildDriver(MozbuildObject):
             # If we don't actually have a list of tests to install we install
             # test and support files wholesale.
             self._run_make(target='install-test-files', pass_thru=True,
                            print_directory=False)
         else:
             install_test_files(mozpath.normpath(self.topsrcdir), self.topobjdir,
                                '_tests', test_objs)
 
+    def _write_mozconfig_json(self):
+        mozconfig_json = os.path.join(self.topobjdir, '.mozconfig.json')
+        with FileAvoidWrite(mozconfig_json) as fh:
+            json.dump({
+                'topsrcdir': self.topsrcdir,
+                'topobjdir': self.topobjdir,
+                'mozconfig': self.mozconfig,
+            }, fh, sort_keys=True, indent=2)
+
     def _run_client_mk(self, target=None, line_handler=None, jobs=0,
                        verbose=None, keep_going=False, append_env=None):
         append_env = dict(append_env or {})
         append_env['TOPSRCDIR'] = self.topsrcdir
 
         append_env['CONFIG_GUESS'] = self.resolve_config_guess()
 
         mozconfig = self.mozconfig
@@ -1361,23 +1390,17 @@ class BuildDriver(MozbuildObject):
                                            '.mozconfig-client-mk')
         with FileAvoidWrite(mozconfig_client_mk) as fh:
             fh.write(b'\n'.join(mozconfig_make_lines))
 
         mozconfig_mk = os.path.join(self.topobjdir, '.mozconfig.mk')
         with FileAvoidWrite(mozconfig_mk) as fh:
             fh.write(b'\n'.join(mozconfig_filtered_lines))
 
-        mozconfig_json = os.path.join(self.topobjdir, '.mozconfig.json')
-        with FileAvoidWrite(mozconfig_json) as fh:
-            json.dump({
-                'topsrcdir': self.topsrcdir,
-                'topobjdir': self.topobjdir,
-                'mozconfig': mozconfig,
-            }, fh, sort_keys=True, indent=2)
+        self._write_mozconfig_json()
 
         # Copy the original mozconfig to the objdir.
         mozconfig_objdir = os.path.join(self.topobjdir, '.mozconfig')
         if mozconfig['path']:
             with open(mozconfig['path'], 'rb') as ifh:
                 with FileAvoidWrite(mozconfig_objdir) as ofh:
                     ofh.write(ifh.read())
         else: