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 274846 27005ff563d0522b4e82ace30481b72daa4e5fbb
parent 274845 0f3f236937943e54089ceae0a673b1b0b2f67d7c
child 274847 d85ee61074c4d9abe82f48bc849e1629362ecaef
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmshal
bugs924187
milestone41.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 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',
 ]