Bug 874078 - Move RecursiveMakeBackend.built rule to rules.mk; r=glandium
authorGregory Szorc <gps@mozilla.com>
Mon, 20 May 2013 23:26:20 -0700
changeset 139611 0931f7400cf2af6e6ee742b6beb17f92069755f8
parent 139610 54553d06c80d790660566074ec02b57fdcb9d768
child 139612 668d1525ef292bf2e3208d0938ea9e134e0175ab
push id3911
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 20:17:26 +0000
treeherdermozilla-aurora@7e26ca8db92b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs874078
milestone24.0a1
Bug 874078 - Move RecursiveMakeBackend.built rule to rules.mk; r=glandium
CLOBBER
Makefile.in
build/ConfigStatus.py
config/rules.mk
js/src/build/ConfigStatus.py
js/src/config/rules.mk
python/mozbuild/mozbuild/backend/base.py
python/mozbuild/mozbuild/backend/recursivemake.py
--- a/CLOBBER
+++ b/CLOBBER
@@ -12,12 +12,12 @@
 #          O               O
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
-Landing bug 865806
+Refactored build system core dependencies in bug 874078.
 
 Alternative to clobber is to run ./config.status from the objdir and to
 touch the CLOBBER file in the objdir.
--- a/Makefile.in
+++ b/Makefile.in
@@ -33,16 +33,18 @@ include $(topsrcdir)/config/config.mk
 GARBAGE_DIRS += dist _javagen _profile _tests staticlib
 DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
    config/autoconf.mk \
    unallmakefiles mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    $(topsrcdir)/.mozconfig.mk $(topsrcdir)/.mozconfig.out
 
 ifndef MOZ_PROFILE_USE
+# We need to explicitly put backend.RecursiveMakeBackend.built here
+# otherwise the rule in rules.mk doesn't run early enough.
 default alldep all:: CLOBBER $(topsrcdir)/configure config.status backend.RecursiveMakeBackend.built
 	$(RM) -r $(DIST)/sdk
 	$(RM) -r $(DIST)/include
 	$(RM) -r $(DIST)/private
 	$(RM) -r $(DIST)/public
 	$(RM) -r $(DIST)/bin
 	$(RM) -r _tests
 endif
@@ -68,24 +70,16 @@ config.status: $(topsrcdir)/configure
 	@exit 1
 
 # Build pseudo-external modules first when export is explicitly called
 export::
 	$(RM) -r $(DIST)/sdk
 	$(MAKE) -C config export
 	$(MAKE) tier_nspr
 
-backend.RecursiveMakeBackend.built:
-	@echo "Updating build backend because of moz.build changes."
-	@$(PYTHON) ./config.status
-
-include backend.RecursiveMakeBackend.built.pp
-
-export MOZBUILD_BACKEND_CHECKED=1
-
 ifdef ENABLE_TESTS
 # Additional makefile targets to call automated test suites
 include $(topsrcdir)/testing/testsuite-targets.mk
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 distclean::
--- a/build/ConfigStatus.py
+++ b/build/ConfigStatus.py
@@ -77,17 +77,17 @@ def config_status(topobjdir = '.', topsr
     parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
                       help='display verbose output')
     parser.add_option('-n', dest='not_topobjdir', action='store_true',
                       help='do not consider current directory as top object directory')
     (options, args) = parser.parse_args()
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
-        topobjdir = '.'
+        topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs)
 
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     backend = RecursiveMakeBackend(env)
     # This won't actually do anything because of the magic of generators.
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -621,18 +621,24 @@ else
 HOST_OUTOPTION = -o # eol
 endif
 ################################################################################
 
 # Regenerate the build backend if it is out of date. We only check this once
 # per traversal, hence the ifdef and the export. This rule needs to come before
 # other rules for the default target or else it may not run in time.
 ifndef MOZBUILD_BACKEND_CHECKED
-default::
-	$(MAKE) -C $(DEPTH) backend.RecursiveMakeBackend.built
+
+$(DEPTH)/backend.RecursiveMakeBackend.built:
+	@echo "Build configuration changed. Regenerating backend."
+	@cd $(DEPTH) && $(PYTHON) ./config.status
+
+include $(DEPTH)/backend.RecursiveMakeBackend.built.pp
+
+default:: $(DEPTH)/backend.RecursiveMakeBackend.built
 
 export MOZBUILD_BACKEND_CHECKED=1
 endif
 
 
 # SUBMAKEFILES: List of Makefiles for next level down.
 #   This is used to update or create the Makefiles before invoking them.
 SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
--- a/js/src/build/ConfigStatus.py
+++ b/js/src/build/ConfigStatus.py
@@ -77,17 +77,17 @@ def config_status(topobjdir = '.', topsr
     parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
                       help='display verbose output')
     parser.add_option('-n', dest='not_topobjdir', action='store_true',
                       help='do not consider current directory as top object directory')
     (options, args) = parser.parse_args()
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
-        topobjdir = '.'
+        topobjdir = os.path.abspath('.')
 
     env = ConfigEnvironment(topsrcdir, topobjdir, defines=defines,
             non_global_defines=non_global_defines, substs=substs)
 
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     backend = RecursiveMakeBackend(env)
     # This won't actually do anything because of the magic of generators.
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -621,18 +621,24 @@ else
 HOST_OUTOPTION = -o # eol
 endif
 ################################################################################
 
 # Regenerate the build backend if it is out of date. We only check this once
 # per traversal, hence the ifdef and the export. This rule needs to come before
 # other rules for the default target or else it may not run in time.
 ifndef MOZBUILD_BACKEND_CHECKED
-default::
-	$(MAKE) -C $(DEPTH) backend.RecursiveMakeBackend.built
+
+$(DEPTH)/backend.RecursiveMakeBackend.built:
+	@echo "Build configuration changed. Regenerating backend."
+	@cd $(DEPTH) && $(PYTHON) ./config.status
+
+include $(DEPTH)/backend.RecursiveMakeBackend.built.pp
+
+default:: $(DEPTH)/backend.RecursiveMakeBackend.built
 
 export MOZBUILD_BACKEND_CHECKED=1
 endif
 
 
 # SUBMAKEFILES: List of Makefiles for next level down.
 #   This is used to update or create the Makefiles before invoking them.
 SUBMAKEFILES += $(addsuffix /Makefile, $(DIRS) $(TOOL_DIRS) $(PARALLEL_DIRS))
--- a/python/mozbuild/mozbuild/backend/base.py
+++ b/python/mozbuild/mozbuild/backend/base.py
@@ -103,16 +103,38 @@ class BuildBackend(LoggingMixin):
 
         self.environment = environment
         self.summary = BackendConsumeSummary()
 
         # Files whose modification should cause a new read and backend
         # generation.
         self.backend_input_files = set()
 
+        # Pull in Python files for this package as dependencies so backend
+        # regeneration occurs if any of the code affecting it changes.
+        for name, module in sys.modules.items():
+            if not module or not name.startswith('mozbuild'):
+                continue
+
+            p = module.__file__
+
+            # We need to look at the actual source files as opposed to derived
+            # because there may be nothing loading these modules at build time.
+            # Assuming each .pyc comes from a .py file in the same directory is
+            # not a safe assumption. Hence the assert to catch future changes
+            # in behavior. A better solution likely involves loading all
+            # mozbuild modules at the top of the build to force .pyc
+            # generation.
+            if p.endswith('.pyc'):
+                p = p[0:-1]
+
+            assert os.path.exists(p)
+
+            self.backend_input_files.add((os.path.abspath(p)))
+
         self._environments = {}
         self._environments[environment.topobjdir] = environment
 
         self._init()
 
     def _init():
         """Hook point for child classes to perform actions during __init__.
 
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -221,17 +221,22 @@ class RecursiveMakeBackend(BuildBackend)
             self.summary.managed_count += 1
 
         # Write out a dependency file used to determine whether a config.status
         # re-run is needed.
         backend_built_path = os.path.join(self.environment.topobjdir,
             'backend.%s.built' % self.__class__.__name__).replace(os.sep, '/')
         backend_deps = FileAvoidWrite('%s.pp' % backend_built_path)
         inputs = sorted(p.replace(os.sep, '/') for p in self.backend_input_files)
-        backend_deps.write('%s: %s\n' % (backend_built_path, ' '.join(inputs)))
+
+        # We need to use $(DEPTH) so the target here matches what's in
+        # rules.mk. If they are different, the dependencies don't get pulled in
+        # properly.
+        backend_deps.write('$(DEPTH)/backend.RecursiveMakeBackend.built: %s\n' %
+            ' '.join(inputs))
         for path in inputs:
             backend_deps.write('%s:\n' % path)
 
         self._update_from_avoid_write(backend_deps.close())
         self.summary.managed_count += 1
 
     def _process_directory_traversal(self, obj, backend_file):
         """Process a data.DirectoryTraversal instance."""