Bug 924187 - Deal with interfaces.manifest from the backend. r=mshal
authorBrian O'Keefe <bokeefe@alum.wpi.edu>
Fri, 13 Feb 2015 08:11:57 -0500
changeset 244092 27005ff563d0522b4e82ace30481b72daa4e5fbb
parent 244091 0f3f236937943e54089ceae0a673b1b0b2f67d7c
child 244093 d85ee61074c4d9abe82f48bc849e1629362ecaef
push id12987
push userphilringnalda@gmail.com
push dateSat, 16 May 2015 16:53:11 +0000
treeherderfx-team@2f6ea66057fe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmshal
bugs924187
milestone41.0a1
Bug 924187 - Deal with interfaces.manifest from the backend. r=mshal
Makefile.in
config/makefiles/xpidl/Makefile.in
config/rules.mk
netwerk/test/httpserver/Makefile.in
netwerk/test/httpserver/moz.build
python/mozbuild/mozbuild/backend/common.py
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/frontend/context.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/test/backend/test_recursivemake.py
xpcom/tests/Makefile.in
xpcom/tests/moz.build
--- a/Makefile.in
+++ b/Makefile.in
@@ -16,17 +16,17 @@ export TOPLEVEL_BUILD := 1
 default::
 
 ifdef MOZ_BUILD_APP
 include $(topsrcdir)/$(MOZ_BUILD_APP)/build.mk
 endif
 
 include $(topsrcdir)/config/config.mk
 
-GARBAGE_DIRS += dist _javagen _profile staticlib
+GARBAGE_DIRS += _javagen _profile staticlib
 DIST_GARBAGE = config.cache config.log config.status* config-defs.h \
    config/autoconf.mk \
    mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    .mozconfig.mk
 
 ifdef JS_STANDALONE
 configure_dir = $(topsrcdir)/js/src
@@ -136,20 +136,20 @@ install-_tests: $(install_manifest_depen
 	$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
 
 # For compatibility
 .PHONY: install-tests
 install-tests: install-_tests
 
 include $(topsrcdir)/build/moz-automation.mk
 
-# _tests should be purged during cleaning. However, we don't want it purged
-# during PGO builds because it contains some auto-generated files.
+# dist and _tests should be purged during cleaning. However, we don't want them
+# purged during PGO builds because they contain some auto-generated files.
 ifneq ($(filter-out maybe_clobber_profiledbuild,$(MAKECMDGOALS)),)
-GARBAGE_DIRS += _tests
+GARBAGE_DIRS += dist _tests
 endif
 
 # Windows PGO builds don't perform a clean before the 2nd pass. So, we want
 # to preserve content for the 2nd pass on Windows. Everywhere else, we always
 # process the install manifests as part of export.
 # For the binaries rule, not all the install manifests matter, so force only
 # the interesting ones to be done.
 ifdef MOZ_PROFILE_USE
--- a/config/makefiles/xpidl/Makefile.in
+++ b/config/makefiles/xpidl/Makefile.in
@@ -38,26 +38,36 @@ endif
 # in the virtualenv.
 %.xpt:
 	@echo "$(@F)"
 	$(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \
 		$(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
 		$(dist_include_dir) $(@D) $(idl_deps_dir) $(libxul_sdk_includes) \
 		$(basename $(notdir $@)) $($(basename $(notdir $@))_deps)
 
+# Chrome manifests may be written from several Makefiles at various times during
+# the build. The 'buildlist' action adds to the file if it already exists, but
+# if it does exist, make considers it to be up-to-date (as we have no inputs to
+# depend on). We use FORCE to ensure that we always add the interface manifest,
+# whether or not the chrome manifest already exists.
+%/chrome.manifest: FORCE
+	$(call py_action,buildlist,$@ 'manifest components/interfaces.manifest')
+
+chrome_manifests := @chrome_manifests@
+
 xpidl_modules := @xpidl_modules@
 xpt_files := @xpt_files@
 
 @xpidl_rules@
 
 depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
 
 GARBAGE += $(xpt_files) $(depends_files)
 
-xpidl:: $(xpt_files)
+xpidl:: $(xpt_files) $(chrome_manifests)
 
 $(xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(dist_include_dir))
 
 define xpt_deps
 $(1): $(call mkdir_deps,$(dir $(1)))
 $(1): $(addsuffix .idl,$(addprefix $(dist_idl_dir)/,$($(basename $(notdir $(1)))_deps)))
 endef
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1163,31 +1163,16 @@ ifndef NO_DIST_INSTALL
 AUTOCFG_JS_EXPORTS_FILES := $(AUTOCFG_JS_EXPORTS)
 AUTOCFG_JS_EXPORTS_DEST := $(FINAL_TARGET)/defaults/autoconfig
 AUTOCFG_JS_EXPORTS_TARGET := export
 INSTALL_TARGETS += AUTOCFG_JS_EXPORTS
 endif
 endif
 
 ################################################################################
-# Install a linked .xpt into the appropriate place.
-# This should ideally be performed by the non-recursive idl make file. Some day.
-ifdef XPT_NAME #{
-
-ifndef NO_DIST_INSTALL
-ifndef NO_INTERFACES_MANIFEST
-export:: $(call mkdir_deps,$(FINAL_TARGET)/components)
-	$(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest 'interfaces $(XPT_NAME)')
-	$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'manifest components/interfaces.manifest')
-endif
-endif
-
-endif #} XPT_NAME
-
-################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
 ifdef EXTRA_COMPONENTS
 misc:: $(EXTRA_COMPONENTS)
 ifndef NO_DIST_INSTALL
 EXTRA_COMPONENTS_FILES := $(EXTRA_COMPONENTS)
 EXTRA_COMPONENTS_DEST := $(FINAL_TARGET)/components
 EXTRA_COMPONENTS_TARGET := misc
 INSTALL_TARGETS += EXTRA_COMPONENTS
deleted file mode 100644
--- a/netwerk/test/httpserver/Makefile.in
+++ /dev/null
@@ -1,7 +0,0 @@
-# vim: noexpandtab ts=8 sw=8
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-NO_INTERFACES_MANIFEST = 1
--- a/netwerk/test/httpserver/moz.build
+++ b/netwerk/test/httpserver/moz.build
@@ -5,16 +5,19 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIHttpServer.idl',
 ]
 
 XPIDL_MODULE = 'test_necko'
 
+# Don't add our test-only .xpt files to the normal manifests
+XPIDL_NO_MANIFEST = True
+
 XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
 
 EXTRA_COMPONENTS += [
     'httpd.js',
     'httpd.manifest',
 ]
 
 TESTING_JS_MODULES += [
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -40,39 +40,49 @@ class XPIDLManager(object):
     """Helps manage XPCOM IDLs in the context of the build system."""
     def __init__(self, config):
         self.config = config
         self.topsrcdir = config.topsrcdir
         self.topobjdir = config.topobjdir
 
         self.idls = {}
         self.modules = {}
+        self.interface_manifests = {}
+        self.chrome_manifests = set()
 
-    def register_idl(self, source, module, install_target, allow_existing=False):
+    def register_idl(self, idl, allow_existing=False):
         """Registers an IDL file with this instance.
 
         The IDL file will be built, installed, etc.
         """
-        basename = mozpath.basename(source)
+        basename = mozpath.basename(idl.source_path)
         root = mozpath.splitext(basename)[0]
+        xpt = '%s.xpt' % idl.module
+        manifest = mozpath.join(idl.install_target, 'components', 'interfaces.manifest')
+        chrome_manifest = mozpath.join(idl.install_target, 'chrome.manifest')
 
         entry = {
-            'source': source,
-            'module': module,
+            'source': idl.source_path,
+            'module': idl.module,
             'basename': basename,
             'root': root,
+            'manifest': manifest,
         }
 
         if not allow_existing and entry['basename'] in self.idls:
             raise Exception('IDL already registered: %s' % entry['basename'])
 
         self.idls[entry['basename']] = entry
-        t = self.modules.setdefault(entry['module'], (install_target, set()))
+        t = self.modules.setdefault(entry['module'], (idl.install_target, set()))
         t[1].add(entry['root'])
 
+        if idl.add_to_manifest:
+            self.interface_manifests.setdefault(manifest, set()).add(xpt)
+            self.chrome_manifests.add(chrome_manifest)
+
 
 class WebIDLCollection(object):
     """Collects WebIDL info referenced during the build."""
 
     def __init__(self):
         self.sources = set()
         self.generated_sources = set()
         self.generated_events_sources = set()
@@ -185,18 +195,17 @@ class CommonBackend(BuildBackend):
         self._configs.add(obj.config)
 
         if isinstance(obj, TestManifest):
             for test in obj.tests:
                 self._test_manager.add(test, flavor=obj.flavor,
                     topsrcdir=obj.topsrcdir)
 
         elif isinstance(obj, XPIDLFile):
-            self._idl_manager.register_idl(obj.source_path, obj.module,
-                obj.install_target)
+            self._idl_manager.register_idl(obj)
 
         elif isinstance(obj, ConfigFileSubstitution):
             # Do not handle ConfigFileSubstitution for Makefiles. Leave that
             # to other
             if mozpath.basename(obj.output_path) == 'Makefile':
                 return
             with self._get_preprocessor(obj) as pp:
                 pp.do_include(obj.input_path)
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -97,16 +97,17 @@ MOZBUILD_VARIABLES = [
     'JAVA_JAR_TARGETS',
     'LD_VERSION_SCRIPT',
     'LIBRARY_NAME',
     'LIBS',
     'MAKE_FRAMEWORK',
     'MODULE',
     'NO_DIST_INSTALL',
     'NO_EXPAND_LIBS',
+    'NO_INTERFACES_MANIFEST',
     'NO_JS_MANIFEST',
     'OS_LIBS',
     'PARALLEL_DIRS',
     'PREF_JS_EXPORTS',
     'PROGRAM',
     'PYTHON_UNIT_TESTS',
     'RESOURCE_FILES',
     'SDK_HEADERS',
@@ -1067,30 +1068,47 @@ INSTALL_TARGETS += %(prefix)s
                 prefix, subpath = path.split('/', 1)
                 key = 'dist_%s' % prefix
 
                 self._install_manifests[key].add_optional_exists(subpath)
 
         rules = StringIO()
         mk.dump(rules, removal_guard=False)
 
+        # Write out manifests defining interfaces
+        dist_dir = mozpath.join(self.environment.topobjdir, 'dist')
+        for manifest, entries in manager.interface_manifests.items():
+            path = mozpath.join(self.environment.topobjdir, manifest)
+            with self._write_file(path) as fh:
+                for xpt in sorted(entries):
+                    fh.write('interfaces %s\n' % xpt)
+
+            if install_target.startswith('dist/'):
+                path = mozpath.relpath(path, dist_dir)
+                prefix, subpath = path.split('/', 1)
+                key = 'dist_%s' % prefix
+                self._install_manifests[key].add_optional_exists(subpath)
+
+        chrome_manifests = [mozpath.join('$(DEPTH)', m) for m in sorted(manager.chrome_manifests)]
+
         # Create dependency for output header so we force regeneration if the
         # header was deleted. This ideally should not be necessary. However,
         # some processes (such as PGO at the time this was implemented) wipe
         # out dist/include without regard to our install manifests.
 
         obj = self.Substitution()
         obj.output_path = mozpath.join(self.environment.topobjdir, 'config',
             'makefiles', 'xpidl', 'Makefile')
         obj.input_path = mozpath.join(self.environment.topsrcdir, 'config',
             'makefiles', 'xpidl', 'Makefile.in')
         obj.topsrcdir = self.environment.topsrcdir
         obj.topobjdir = self.environment.topobjdir
         obj.config = self.environment
         self._create_makefile(obj, extra=dict(
+            chrome_manifests = ' '.join(chrome_manifests),
             xpidl_rules=rules.getvalue(),
             xpidl_modules=' '.join(xpt_modules),
             xpt_files=' '.join(sorted(xpt_files)),
         ))
 
     def _process_program(self, program, backend_file):
         backend_file.write('PROGRAM = %s\n' % program)
 
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -1142,16 +1142,24 @@ VARIABLES = {
     'XPIDL_MODULE': (unicode, unicode,
         """XPCOM Interface Definition Module Name.
 
         This is the name of the ``.xpt`` file that is created by linking
         ``XPIDL_SOURCES`` together. If unspecified, it defaults to be the same
         as ``MODULE``.
         """, None),
 
+    'XPIDL_NO_MANIFEST': (bool, bool,
+        """Indicate that the XPIDL module should not be added to a manifest.
+
+        This flag exists primarily to prevent test-only XPIDL modules from being
+        added to the application's chrome manifest. Most XPIDL modules should
+        not use this flag.
+        """, None),
+
     'IPDL_SOURCES': (StrictOrderingOnAppendList, list,
         """IPDL source files.
 
         These are ``.ipdl`` files that will be parsed and converted to
         ``.cpp`` files.
         """, 'export'),
 
     'WEBIDL_FILES': (StrictOrderingOnAppendList, list,
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -155,27 +155,29 @@ class VariablePassthru(ContextDerived):
     def __init__(self, context):
         ContextDerived.__init__(self, context)
         self.variables = {}
 
 class XPIDLFile(ContextDerived):
     """Describes an XPIDL file to be compiled."""
 
     __slots__ = (
+        'add_to_manifest',
         'basename',
         'install_target',
         'source_path',
     )
 
-    def __init__(self, context, source, module):
+    def __init__(self, context, source, module, add_to_manifest):
         ContextDerived.__init__(self, context)
 
         self.source_path = source
         self.basename = mozpath.basename(source)
         self.module = module
+        self.add_to_manifest = add_to_manifest
 
         self.install_target = context['FINAL_TARGET']
 
 class Defines(ContextDerived):
     """Context derived container object for DEFINES, which is an OrderedDict.
     """
     __slots__ = ('defines')
 
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -809,17 +809,17 @@ class TreeMetadataEmitter(LoggingMixin):
 
         if context['XPIDL_SOURCES'] and context['DIST_INSTALL'] is False:
             self.log(logging.WARN, 'mozbuild_warning', dict(
                 path=context.main_path),
                 '{path}: DIST_INSTALL = False has no effect on XPIDL_SOURCES.')
 
         for idl in context['XPIDL_SOURCES']:
             yield XPIDLFile(context, mozpath.join(context.srcdir, idl),
-                xpidl_module)
+                xpidl_module, add_to_manifest=not context['XPIDL_NO_MANIFEST'])
 
     def _process_generated_files(self, context):
         generated_files = context.get('GENERATED_FILES')
         if not generated_files:
             return
 
         for f in generated_files:
             flags = generated_files[f]
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -492,16 +492,17 @@ class TestRecursiveMakeBackend(BackendTe
         self.assertIn('bar.idl', m)
         self.assertIn('foo.idl', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'xpidl'))
         self.assertIn('.deps/my_module.pp', m)
 
         m = InstallManifest(path=os.path.join(install_dir, 'dist_bin'))
         self.assertIn('components/my_module.xpt', m)
+        self.assertIn('components/interfaces.manifest', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'dist_include'))
         self.assertIn('foo.h', m)
 
         p = mozpath.join(env.topobjdir, 'config/makefiles/xpidl')
         self.assertTrue(os.path.isdir(p))
 
         self.assertTrue(os.path.isfile(mozpath.join(p, 'Makefile')))
--- a/xpcom/tests/Makefile.in
+++ b/xpcom/tests/Makefile.in
@@ -1,18 +1,15 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Make sure we have symbols in case we need to debug these.
 MOZ_DEBUG_SYMBOLS = 1
 
-# Don't add our test-only .xpt files to the normal manifests
-NO_INTERFACES_MANIFEST = 1
-
 include $(topsrcdir)/config/rules.mk
 
 ifneq (,$(SIMPLE_PROGRAMS))
 libs::
 	$(INSTALL) $(SIMPLE_PROGRAMS) $(DEPTH)/_tests/xpcshell/$(relativesrcdir)/unit
 endif
 
 libs::
--- a/xpcom/tests/moz.build
+++ b/xpcom/tests/moz.build
@@ -96,15 +96,18 @@ if CONFIG['MOZ_DEBUG'] and CONFIG['OS_AR
         'TestDeadlockDetectorScalability',
     ])
 
 XPIDL_MODULE = 'xpcomtest'
 XPIDL_SOURCES += [
     'NotXPCOMTest.idl',
 ]
 
+# Don't add our test-only .xpt files to the normal manifests
+XPIDL_NO_MANIFEST = True
+
 LOCAL_INCLUDES += [
     '../ds',
 ]
 
 RESOURCE_FILES += [
     'test.properties',
 ]