Bug 1461836 - Check configure dependencies and re-run configure if needed when invoking the Tup backend. r=mshal
authorChris Manchester <cmanchester@mozilla.com>
Mon, 21 May 2018 14:01:56 -0700
changeset 419271 c7e9e54de140fad7a92b6b22862c3ed00491fa3a
parent 419270 ec5cda49535fddf8860091ff4bd37155d90b248d
child 419272 fa332d9d704da9056d4c7493bcc4b718810c4529
push id103497
push usernbeleuzu@mozilla.com
push dateTue, 22 May 2018 11:25:17 +0000
treeherdermozilla-inbound@738e6d38c1d9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmshal
bugs1461836
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1461836 - Check configure dependencies and re-run configure if needed when invoking the Tup backend. r=mshal 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: