Bug 850380 - Derecursify and optimize XPIDL processing and move into precompile tier; r=glandium
authorGregory Szorc <gps@mozilla.com>
Wed, 14 Aug 2013 08:40:25 -0700
changeset 142690 13f3b8949f63adc20b0725fd3a3b3917f66c2d63
parent 142689 59d88e3d4c839f374260222175ec5f877e579791
child 142691 f17435611c5a0918ec6a26541148dd86329401ee
push id25104
push useremorley@mozilla.com
push dateThu, 15 Aug 2013 10:56:09 +0000
treeherdermozilla-central@31c08ca022b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs850380
milestone26.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 850380 - Derecursify and optimize XPIDL processing and move into precompile tier; r=glandium
browser/components/places/moz.build
browser/components/places/src/moz.build
config/config.mk
config/makefiles/precompile/Makefile.in
config/makefiles/xpidl/Makefile.in
config/rules.mk
dom/activities/interfaces/moz.build
dom/alarm/moz.build
dom/base/moz.build
dom/camera/moz.build
dom/cellbroadcast/interfaces/moz.build
dom/file/moz.build
dom/fm/moz.build
dom/icc/interfaces/moz.build
dom/indexedDB/moz.build
dom/interfaces/apps/moz.build
dom/interfaces/base/moz.build
dom/interfaces/contacts/moz.build
dom/interfaces/core/moz.build
dom/interfaces/css/moz.build
dom/interfaces/devicestorage/moz.build
dom/interfaces/events/moz.build
dom/interfaces/geolocation/moz.build
dom/interfaces/html/moz.build
dom/interfaces/json/moz.build
dom/interfaces/notification/moz.build
dom/interfaces/offline/moz.build
dom/interfaces/permission/moz.build
dom/interfaces/range/moz.build
dom/interfaces/settings/moz.build
dom/interfaces/smil/moz.build
dom/interfaces/storage/moz.build
dom/interfaces/stylesheets/moz.build
dom/interfaces/svg/moz.build
dom/interfaces/traversal/moz.build
dom/interfaces/xbl/moz.build
dom/interfaces/xpath/moz.build
dom/interfaces/xul/moz.build
dom/messages/interfaces/moz.build
dom/mobilemessage/interfaces/moz.build
dom/network/interfaces/moz.build
dom/payment/interfaces/moz.build
dom/system/gonk/moz.build
dom/telephony/moz.build
dom/voicemail/moz.build
dom/wifi/moz.build
hal/moz.build
js/src/config/config.mk
js/src/config/rules.mk
js/xpconnect/tests/idl/Makefile.in
netwerk/mime/moz.build
netwerk/protocol/file/moz.build
netwerk/protocol/http/moz.build
netwerk/protocol/res/moz.build
netwerk/protocol/viewsource/moz.build
netwerk/protocol/wyciwyg/moz.build
netwerk/streamconv/public/moz.build
python/mozbuild/mozbuild/action/xpidl-process.py
python/mozbuild/mozbuild/backend/common.py
python/mozbuild/mozbuild/backend/configenvironment.py
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/frontend/data.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/frontend/sandbox_symbols.py
python/mozbuild/mozbuild/test/backend/common.py
python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
python/mozbuild/mozbuild/test/backend/data/xpidl/config/makefiles/xpidl/Makefile.in
python/mozbuild/mozbuild/test/backend/data/xpidl/moz.build
python/mozbuild/mozbuild/test/backend/test_recursivemake.py
python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
python/mozbuild/mozbuild/test/frontend/test_emitter.py
toolkit/crashreporter/test/Makefile.in
xpcom/idl-parser/Makefile.in
--- a/browser/components/places/moz.build
+++ b/browser/components/places/moz.build
@@ -2,12 +2,8 @@
 # vim: set filetype=python:
 # 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/.
 
 DIRS += ['src']
 TEST_DIRS += ['tests']
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/browser/components/',
-]
-
--- a/browser/components/places/src/moz.build
+++ b/browser/components/places/src/moz.build
@@ -1,18 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/browser/components',
-]
-
 EXTRA_COMPONENTS += [
     'BrowserPlaces.manifest',
     'PlacesProtocolHandler.js',
 ]
 
 EXTRA_JS_MODULES += [
     'PlacesUIUtils.jsm',
 ]
--- a/config/config.mk
+++ b/config/config.mk
@@ -359,17 +359,16 @@ endif
 #
 MY_CONFIG	:= $(DEPTH)/config/myconfig.mk
 MY_RULES	:= $(DEPTH)/config/myrules.mk
 
 #
 # Default command macros; can be overridden in <arch>.mk.
 #
 CCC = $(CXX)
-XPIDL_LINK = $(PYTHON) $(LIBXUL_DIST)/sdk/bin/xpt.py link
 
 # Java macros
 JAVA_GEN_DIR  = _javagen
 JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR)
 JAVA_IFACES_PKG_NAME = org/mozilla/interfaces
 
 OS_INCLUDES += $(MOZ_JPEG_CFLAGS) $(MOZ_PNG_CFLAGS) $(MOZ_ZLIB_CFLAGS)
 
@@ -516,22 +515,18 @@ endif
 ifneq (WINNT_,$(OS_ARCH)_$(GNU_CC))
 LIBS_DIR	= -L$(DIST)/bin -L$(DIST)/lib
 ifdef LIBXUL_SDK
 LIBS_DIR	+= -L$(LIBXUL_SDK)/bin -L$(LIBXUL_SDK)/lib
 endif
 endif
 
 # Default location of include files
-IDL_DIR		= $(DIST)/idl
-
-XPIDL_FLAGS += -I$(srcdir) -I$(IDL_DIR)
-ifdef LIBXUL_SDK
-XPIDL_FLAGS += -I$(LIBXUL_SDK)/idl
-endif
+IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser
+IDL_PARSER_CACHE_DIR = $(DEPTH)/xpcom/idl-parser
 
 SDK_LIB_DIR = $(DIST)/sdk/lib
 SDK_BIN_DIR = $(DIST)/sdk/bin
 
 DEPENDENCIES	= .md
 
 MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS)
 
--- a/config/makefiles/precompile/Makefile.in
+++ b/config/makefiles/precompile/Makefile.in
@@ -10,28 +10,34 @@ topsrcdir := @top_srcdir@
 srcdir := @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 SUPPRESS_DEFAULT_RULES := 1
 
 include $(topsrcdir)/config/rules.mk
 
+# We don't print the build status messages unless we're in a top level build
+# otherwise the output is unexpected and it confuses downstream parsers.
 define make_subtier_dir
 @echo "BUILDSTATUS SUBTIER_START precompile $(1)"
-$(MAKE) -C $(2) $(3)
++$(MAKE) -C $(2) $(3)
 @echo "BUILDSTATUS SUBTIER_FINISH precompile $(1)"
 
 endef
 
 export::
-	@echo "BUILDSTATUS SUBTIERS IPDL WebIDL"
+	@echo "BUILDSTATUS SUBTIERS IPDL WebIDL XPIDL"
 
-export:: ipdl webidl xpidl-parser
+export:: ipdl webidl xpidl-parser xpidl
 
 ipdl:
 	$(call make_subtier_dir,IPDL,$(DEPTH)/ipc/ipdl,ipdl)
 
 webidl:
 	$(call make_subtier_dir,WebIDL,$(DEPTH)/dom/bindings,webidl)
 
 xpidl-parser:
 	$(call make_subtier_dir,XPIDLParser,$(DEPTH)/xpcom/idl-parser,xpidl-parser)
+
+xpidl: xpidl-parser
+	$(call py_action,process_install_manifest,$(DIST)/idl $(DEPTH)/_build_manifests/install/dist_idl)
+	$(call make_subtier_dir,XPIDL,$(DEPTH)/config/makefiles/xpidl,xpidl)
new file mode 100644
--- /dev/null
+++ b/config/makefiles/xpidl/Makefile.in
@@ -0,0 +1,84 @@
+# 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/.
+
+DEPTH := @DEPTH@
+topsrcdir := @top_srcdir@
+srcdir := @srcdir@
+VPATH := @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+SUPPRESS_DEFAULT_RULES := 1
+STANDALONE_MAKEFILE := 1
+
+include $(topsrcdir)/config/rules.mk
+
+# Building XPIDLs effectively consists of two steps:
+#
+#   1) Staging all .idl files to a common directory.
+#   2) Doing everything with the .idl files.
+#
+# Each .idl file is processed into a .h file and typelib information.
+# The .h file shares the same stem as the input file and is installed
+# in the common headers include directory.
+#
+# XPIDL files are logically grouped together by modules. The typelib
+# information for all XPIDLs in the same module is linked together into
+# an .xpt file having the name of the module.
+#
+# As an optimization to reduce overall CPU usage, we process all .idl
+# belonging to a module with a single command invocation. This prevents
+# redundant parsing of .idl files and significantly reduces CPU cycles.
+#
+# Future improvement: Headers are currently written to a local directory then
+# installed in the distribution directory. It is preferable to write headers
+# directly into the distribution directory. However, PGO builds remove the dist
+# directory via rm -rf (with no regards to manifests). Since the cost of
+# processing XPIDL files is not trivial, it is preferrable to cache the headers
+# and reinstall them rather than regenerate them. Ideally the dist pruning is
+# performed with manifests. At that time we can write headers directly to the
+# dist directory.
+
+# For dependency files.
+idl_deps_dir := .deps
+
+# Where generated headers go.
+idl_headers_dir := headers
+
+# Where we put our final, linked .xpt files.
+idl_xpt_dir := xpt
+
+dist_idl_dir := $(DIST)/idl
+dist_include_dir := $(DIST)/include
+process_py := $(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py
+
+# TODO we should use py_action, but that would require extra directories to be
+# in the virtualenv.
+idlprocess := $(PYTHON_PATH) $(PLY_INCLUDE) -I$(IDL_PARSER_DIR) -I$(IDL_PARSER_CACHE_DIR) \
+    $(process_py) --cache-dir $(IDL_PARSER_CACHE_DIR) $(dist_idl_dir) \
+        $(idl_headers_dir) $(idl_xpt_dir) $(idl_deps_dir)
+
+xpidl_headers := @xpidl_headers@
+xpidl_modules := @xpidl_modules@
+
+@xpidl_rules@
+
+dist_headers := $(addprefix $(dist_include_dir)/,$(xpidl_headers))
+linked_xpt_files := $(addprefix $(idl_xpt_dir)/,$(addsuffix .xpt,$(xpidl_modules)))
+depends_files := $(foreach root,$(xpidl_modules),$(idl_deps_dir)/$(root).pp)
+
+$(dist_headers): $(dist_include_dir)/%.h: $(idl_headers_dir)/%.h
+	$(INSTALL) $< $(dist_include_dir)
+
+xpidl:: $(linked_xpt_files) $(dist_headers)
+
+$(linked_xpt_files): $(process_py) $(call mkdir_deps,$(idl_deps_dir) $(idl_headers_dir) $(idl_xpt_dir))
+
+ifdef .PYMAKE
+-includedeps $(depends_files)
+else
+-include $(depends_files)
+endif
+
+.PHONY: xpidl
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -28,25 +28,33 @@ endif
   NO_DIST_INSTALL \
   PARALLEL_DIRS \
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPIDL_MODULE \
   $(NULL)
 
+_DEPRECATED_VARIABLES := \
+  XPIDL_FLAGS \
+  $(NULL)
+
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
 # Using $(firstword) may not be perfect. But it should be good enough for most
 # scenarios.
 _current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
 
 $(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
     $(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
     ))
 
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+    $(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
+    ))
+
 ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
     $(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
 endif
 
 # Import the automatically generated backend file. If this file doesn't exist,
 # the backend hasn't been properly configured. We want this to be a fatal
 # error, hence not using "-include".
 ifndef STANDALONE_MAKEFILE
@@ -412,18 +420,16 @@ endif
 #
 # the Solaris WorkShop template repository cache.  it occasionally can get
 # out of sync, so targets like clobber should kill it.
 #
 ifeq ($(SOLARIS_SUNPRO_CXX),1)
 GARBAGE_DIRS += SunWS_cache
 endif
 
-XPIDL_GEN_DIR		= _xpidlgen
-
 ifdef MOZ_UPDATE_XTERM
 # Its good not to have a newline at the end of the titlebar string because it
 # makes the make -s output easier to read.  Echo -n does not work on all
 # platforms, but we can trick printf into doing it.
 UPDATE_TITLE = printf "\033]0;%s in %s\007" $(1) $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$(2) ;
 endif
 
 # Static directories are largely independent of our build system. But, they
@@ -1383,108 +1389,33 @@ 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
 
 ################################################################################
-# Export the elements of $(XPIDLSRCS)
-# generating .h and .xpt files and moving them to the appropriate places.
-
-ifneq ($(XPIDLSRCS),) #{
-
-export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS))
-
-ifndef XPIDL_MODULE
-XPIDL_MODULE		= $(MODULE)
-endif
-
-ifeq ($(XPIDL_MODULE),) # we need $(XPIDL_MODULE) to make $(XPIDL_MODULE).xpt
-export:: FORCE
-	@echo
-	@echo "*** Error processing XPIDLSRCS:"
-	@echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS,"
-	@echo "so we have a module name to use when creating MODULE.xpt."
-	@echo; sleep 2; false
-endif
-
-# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
-# warn against overriding existing .h file.
-
-XPIDL_DEPS = \
-  $(LIBXUL_DIST)/sdk/bin/header.py \
-  $(LIBXUL_DIST)/sdk/bin/typelib.py \
-  $(LIBXUL_DIST)/sdk/bin/xpidl.py \
-  $(NULL)
-
-xpidl-preqs = \
-  $(call mkdir_deps,$(XPIDL_GEN_DIR)) \
-  $(call mkdir_deps,$(MDDEPDIR)) \
-  $(NULL)
-
-$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
-	$(REPORT_BUILD)
-	$(PYTHON_PATH) \
-	  $(PLY_INCLUDE) \
-	  $(LIBXUL_DIST)/sdk/bin/header.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
-	@if test -n "$(findstring $*.h, $(EXPORTS))"; \
-	  then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
-
-# generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link
-# into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components.
-$(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
-	$(REPORT_BUILD)
-	$(PYTHON_PATH) \
-	  $(PLY_INCLUDE) \
-	  -I$(topsrcdir)/xpcom/typelib/xpt/tools \
-	  $(LIBXUL_DIST)/sdk/bin/typelib.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
-
-# no need to link together if XPIDLSRCS contains only XPIDL_MODULE
-ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
-XPT_PY = $(filter %/xpt.py,$(XPIDL_LINK))
-
-xpidl-idl2xpt = $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
-xpidl-module-deps = $(xpidl-idl2xpt) $(GLOBAL_DEPS) $(XPT_PY)
-
-$(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(xpidl-module-deps)
-	$(XPIDL_LINK) $@ $(xpidl-idl2xpt)
-
-$(XPT_PY):
-	$(MAKE) -C $(DEPTH)/xpcom/typelib/xpt/tools libs
-
-endif # XPIDL_MODULE.xpt != XPIDLSRCS
+# 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
-XPIDL_MODULE_FILES := $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
-XPIDL_MODULE_DEST := $(FINAL_TARGET)/components
-INSTALL_TARGETS += XPIDL_MODULE
+_XPT_NAME_FILES := $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME)
+_XPT_NAME_DEST := $(FINAL_TARGET)/components
+INSTALL_TARGETS += _XPT_NAME
 
 ifndef NO_INTERFACES_MANIFEST
 libs:: $(call mkdir_deps,$(FINAL_TARGET)/components)
-	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
+	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
-GARBAGE_DIRS		+= $(XPIDL_GEN_DIR)
-
-ifndef NO_DIST_INSTALL
-XPIDL_HEADERS_FILES := $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS))
-XPIDL_HEADERS_DEST := $(DIST)/include
-XPIDL_HEADERS_TARGET := export
-INSTALL_TARGETS += XPIDL_HEADERS
-
-XPIDLSRCS_FILES := $(XPIDLSRCS)
-XPIDLSRCS_DEST := $(IDL_DIR)
-XPIDLSRCS_TARGET := export
-INSTALL_TARGETS += XPIDLSRCS
-endif
-endif #} XPIDLSRCS
+endif #} XPT_NAME
 
 ################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
 ifneq (,$(filter %.js,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
 ifeq (,$(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
 ifndef NO_JS_MANIFEST
 $(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
 endif
@@ -1686,17 +1617,17 @@ endif
 #
 #   We use $(CURDIR) in the rule's target to ensure that we don't find
 #   a dependency directory in the source tree via VPATH (perhaps from
 #   a previous build in the source tree) and thus neglect to create a
 #   dependency directory in the object directory, where we really need
 #   it.
 
 ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
-MDDEPEND_FILES		:= $(strip $(wildcard $(foreach file,$(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS) $(TARGETS) $(XPIDLSRCS:.idl=.h) $(XPIDLSRCS:.idl=.xpt)),$(MDDEPDIR)/$(notdir $(file)).pp) $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES))))
+MDDEPEND_FILES		:= $(strip $(wildcard $(foreach file,$(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS) $(TARGETS)),$(MDDEPDIR)/$(notdir $(file)).pp) $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES))))
 
 ifneq (,$(MDDEPEND_FILES))
 ifdef .PYMAKE
 includedeps $(MDDEPEND_FILES)
 else
 include $(MDDEPEND_FILES)
 endif
 endif
@@ -1879,17 +1810,16 @@ check:: $(SUBMAKEFILES) $(MAKE_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 endif
 
 
 FREEZE_VARIABLES = \
   CSRCS \
   CPPSRCS \
   EXPORTS \
-  XPIDLSRCS \
   DIRS \
   LIBRARY \
   MODULE \
   SHORT_LIBNAME \
   TIERS \
   EXTRA_COMPONENTS \
   EXTRA_PP_COMPONENTS \
   MOCHITEST_FILES \
--- a/dom/activities/interfaces/moz.build
+++ b/dom/activities/interfaces/moz.build
@@ -10,14 +10,8 @@ XPIDL_SOURCES += [
     'nsIDOMActivityHandlerDescription.idl',
     'nsIDOMActivityOptions.idl',
     'nsIDOMActivityRequestHandler.idl',
     'nsIDOMNavigatorActivities.idl',
 ]
 
 XPIDL_MODULE = 'dom_activities'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
--- a/dom/alarm/moz.build
+++ b/dom/alarm/moz.build
@@ -8,20 +8,16 @@ TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'nsIAlarmHalService.idl',
     'nsIDOMAlarmsManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_alarm'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom.alarm += [
     'AlarmHalService.h',
 ]
 
 CPP_SOURCES += [
     'AlarmHalService.cpp',
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -9,21 +9,16 @@ TEST_DIRS += ['test']
 XPIDL_SOURCES += [
     'nsIDOMDOMCursor.idl',
     'nsIDOMDOMRequest.idl',
     'nsIEntropyCollector.idl',
     'nsIScriptChannel.idl',
     'nsISiteSpecificUserAgent.idl',
 ]
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 EXPORTS += [
     'Crypto.h',
     'nsContentPermissionHelper.h',
     'nsDOMCID.h',
     'nsDOMClassInfoClasses.h',
     'nsDOMClassInfoID.h',
--- a/dom/camera/moz.build
+++ b/dom/camera/moz.build
@@ -5,23 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMCameraManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_camera'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-    '-I$(topsrcdir)/dom/media',
-]
-
 MODULE = 'dom'
 
 EXPORTS += [
     'CameraCommon.h',
     'CameraPreviewMediaStream.h',
     'DOMCameraManager.h',
     'GonkCameraControl.h',
 ]
--- a/dom/cellbroadcast/interfaces/moz.build
+++ b/dom/cellbroadcast/interfaces/moz.build
@@ -8,14 +8,8 @@ XPIDL_SOURCES += [
     'nsICellBroadcastProvider.idl',
     'nsIDOMMozCellBroadcast.idl',
     'nsIDOMMozCellBroadcastEvent.idl',
     'nsIDOMMozCellBroadcastMessage.idl',
 ]
 
 XPIDL_MODULE = 'dom_cellbroadcast'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
--- a/dom/file/moz.build
+++ b/dom/file/moz.build
@@ -8,22 +8,16 @@ TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'nsIDOMFileHandle.idl',
     'nsIDOMLockedFile.idl',
 ]
 
 XPIDL_MODULE = 'dom_file'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 EXPORTS += [
     'nsIFileStorage.h',
 ]
 
 EXPORTS.mozilla.dom.file += [
     'ArchiveEvent.h',
--- a/dom/fm/moz.build
+++ b/dom/fm/moz.build
@@ -6,20 +6,16 @@
 
 XPIDL_SOURCES += [
     'nsIDOMFMRadio.idl',
     'nsIFMRadio.idl',
 ]
 
 XPIDL_MODULE = 'dom_fm'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 CPP_SOURCES += [
     'FMRadio.cpp',
     'nsFMRadioSettings.cpp',
 ]
 
 EXTRA_JS_MODULES += [
--- a/dom/icc/interfaces/moz.build
+++ b/dom/icc/interfaces/moz.build
@@ -8,14 +8,8 @@ XPIDL_SOURCES += [
     'SimToolKit.idl',
     'nsIDOMIccCardLockErrorEvent.idl',
     'nsIDOMIccInfo.idl',
     'nsIDOMIccManager.idl',
     'nsIIccProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_icc'
-
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
--- a/dom/indexedDB/moz.build
+++ b/dom/indexedDB/moz.build
@@ -9,21 +9,16 @@ TEST_DIRS += ['test']
 
 XPIDL_SOURCES += [
     'nsIIDBKeyRange.idl',
     'nsIIndexedDatabaseManager.idl',
 ]
 
 XPIDL_MODULE = 'dom_indexeddb'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom.indexedDB += [
     'Client.h',
     'DatabaseInfo.h',
     'FileInfo.h',
     'FileManager.h',
     'IDBCursor.h',
--- a/dom/interfaces/apps/moz.build
+++ b/dom/interfaces/apps/moz.build
@@ -10,15 +10,10 @@ XPIDL_SOURCES += [
     'nsIAppsService.idl',
     'nsIDOMApplicationRegistry.idl',
     'nsIDOMApplicationRegistry2.idl',
     'nsIDOMMozApplicationEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_apps'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -54,14 +54,10 @@ if CONFIG['MOZ_B2G']:
 
 if CONFIG['MOZ_WEBSPEECH']:
     XPIDL_SOURCES += [
         'nsISpeechSynthesisGetter.idl'
     ]
 
 XPIDL_MODULE = 'dom_base'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/contacts/moz.build
+++ b/dom/interfaces/contacts/moz.build
@@ -7,15 +7,10 @@
 XPIDL_SOURCES += [
     'nsIContactProperties.idl',
     'nsIDOMContactManager.idl',
     'nsIDOMMozContactChangeEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_contacts'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/core/moz.build
+++ b/dom/interfaces/core/moz.build
@@ -24,14 +24,10 @@ XPIDL_SOURCES += [
     'nsIDOMText.idl',
     'nsIDOMUserDataHandler.idl',
     'nsIDOMXMLDocument.idl',
     'nsIInlineEventHandlers.idl',
 ]
 
 XPIDL_MODULE = 'dom_core'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/css/moz.build
+++ b/dom/interfaces/css/moz.build
@@ -28,15 +28,10 @@ XPIDL_SOURCES += [
     'nsIDOMElementCSSInlineStyle.idl',
     'nsIDOMMozCSSKeyframeRule.idl',
     'nsIDOMMozCSSKeyframesRule.idl',
     'nsIDOMRect.idl',
 ]
 
 XPIDL_MODULE = 'dom_css'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/stylesheets',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/devicestorage/moz.build
+++ b/dom/interfaces/devicestorage/moz.build
@@ -6,15 +6,10 @@
 
 XPIDL_SOURCES += [
     'nsIDOMDeviceStorage.idl',
     'nsIDOMDeviceStorageChangeEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_devicestorage'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/events/moz.build
+++ b/dom/interfaces/events/moz.build
@@ -54,14 +54,10 @@ XPIDL_SOURCES += [
     'nsIDOMTransitionEvent.idl',
     'nsIDOMUIEvent.idl',
     'nsIDOMUserProximityEvent.idl',
     'nsIDOMWheelEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_events'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/geolocation/moz.build
+++ b/dom/interfaces/geolocation/moz.build
@@ -10,14 +10,10 @@ XPIDL_SOURCES += [
     'nsIDOMGeoPositionCallback.idl',
     'nsIDOMGeoPositionCoords.idl',
     'nsIDOMGeoPositionError.idl',
     'nsIDOMGeoPositionErrorCallback.idl',
 ]
 
 XPIDL_MODULE = 'dom_geolocation'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/html/moz.build
+++ b/dom/interfaces/html/moz.build
@@ -63,15 +63,10 @@ XPIDL_SOURCES += [
     'nsIDOMMozBrowserFrame.idl',
     'nsIDOMTimeRanges.idl',
     'nsIDOMValidityState.idl',
     'nsIMozBrowserFrame.idl',
 ]
 
 XPIDL_MODULE = 'dom_html'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/core',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/json/moz.build
+++ b/dom/interfaces/json/moz.build
@@ -5,14 +5,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIJSON.idl',
 ]
 
 XPIDL_MODULE = 'dom_json'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/notification/moz.build
+++ b/dom/interfaces/notification/moz.build
@@ -5,14 +5,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMDesktopNotification.idl',
 ]
 
 XPIDL_MODULE = 'dom_notification'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/offline/moz.build
+++ b/dom/interfaces/offline/moz.build
@@ -6,14 +6,10 @@
 
 XPIDL_SOURCES += [
     'nsIDOMLoadStatus.idl',
     'nsIDOMOfflineResourceList.idl',
 ]
 
 XPIDL_MODULE = 'dom_offline'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/permission/moz.build
+++ b/dom/interfaces/permission/moz.build
@@ -6,14 +6,10 @@
 
 XPIDL_SOURCES += [
     'nsIDOMPermissionSettings.idl',
     'nsIPermissionPromptService.idl',
 ]
 
 XPIDL_MODULE = 'dom_permissionsettings'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/range/moz.build
+++ b/dom/interfaces/range/moz.build
@@ -5,14 +5,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMRange.idl',
 ]
 
 XPIDL_MODULE = 'dom_range'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/settings/moz.build
+++ b/dom/interfaces/settings/moz.build
@@ -6,15 +6,10 @@
 
 XPIDL_SOURCES += [
     'nsIDOMMozSettingsEvent.idl',
     'nsISettingsService.idl',
 ]
 
 XPIDL_MODULE = 'dom_settings'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/smil/moz.build
+++ b/dom/interfaces/smil/moz.build
@@ -5,17 +5,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMTimeEvent.idl',
 ]
 
 XPIDL_MODULE = 'dom_smil'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/core',
-    '-I$(topsrcdir)/dom/interfaces/events',
-    '-I$(topsrcdir)/dom/interfaces/svg',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/storage/moz.build
+++ b/dom/interfaces/storage/moz.build
@@ -9,19 +9,14 @@ XPIDL_SOURCES += [
     'nsIDOMStorageEvent.idl',
     'nsIDOMStorageIndexedDB.idl',
     'nsIDOMStorageManager.idl',
     'nsIDOMToString.idl',
 ]
 
 XPIDL_MODULE = 'dom_storage'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 EXPORTS += [
     'nsPIDOMStorage.h',
 ]
 
--- a/dom/interfaces/stylesheets/moz.build
+++ b/dom/interfaces/stylesheets/moz.build
@@ -7,14 +7,10 @@
 XPIDL_SOURCES += [
     'nsIDOMMediaList.idl',
     'nsIDOMStyleSheet.idl',
     'nsIDOMStyleSheetList.idl',
 ]
 
 XPIDL_MODULE = 'dom_stylesheets'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/svg/moz.build
+++ b/dom/interfaces/svg/moz.build
@@ -7,16 +7,10 @@
 XPIDL_SOURCES += [
     'nsIDOMSVGElement.idl',
     'nsIDOMSVGLength.idl',
     'nsIDOMSVGNumber.idl',
 ]
 
 XPIDL_MODULE = 'dom_svg'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/core',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/traversal/moz.build
+++ b/dom/interfaces/traversal/moz.build
@@ -7,14 +7,10 @@
 XPIDL_SOURCES += [
     'nsIDOMNodeFilter.idl',
     'nsIDOMNodeIterator.idl',
     'nsIDOMTreeWalker.idl',
 ]
 
 XPIDL_MODULE = 'dom_traversal'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/xbl/moz.build
+++ b/dom/interfaces/xbl/moz.build
@@ -5,14 +5,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIDOMDocumentXBL.idl',
 ]
 
 XPIDL_MODULE = 'dom_xbl'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/xpath/moz.build
+++ b/dom/interfaces/xpath/moz.build
@@ -10,15 +10,10 @@ XPIDL_SOURCES += [
     'nsIDOMXPathExpression.idl',
     'nsIDOMXPathNSResolver.idl',
     'nsIDOMXPathNamespace.idl',
     'nsIDOMXPathResult.idl',
 ]
 
 XPIDL_MODULE = 'dom_xpath'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/core',
-]
-
 MODULE = 'dom'
 
--- a/dom/interfaces/xul/moz.build
+++ b/dom/interfaces/xul/moz.build
@@ -24,16 +24,10 @@ XPIDL_SOURCES += [
     'nsIDOMXULSelectCntrlEl.idl',
     'nsIDOMXULSelectCntrlItemEl.idl',
     'nsIDOMXULTextboxElement.idl',
     'nsIDOMXULTreeElement.idl',
 ]
 
 XPIDL_MODULE = 'dom_xul'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/core',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
--- a/dom/messages/interfaces/moz.build
+++ b/dom/messages/interfaces/moz.build
@@ -6,12 +6,8 @@
 
 XPIDL_SOURCES += [
     'nsIDOMNavigatorSystemMessages.idl',
     'nsISystemMessagesInternal.idl',
 ]
 
 XPIDL_MODULE = 'dom_messages'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
--- a/dom/mobilemessage/interfaces/moz.build
+++ b/dom/mobilemessage/interfaces/moz.build
@@ -24,14 +24,8 @@ XPIDL_SOURCES += [
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRilMobileMessageDatabaseService.idl',
     ]
 
 XPIDL_MODULE = 'dom_mobilemessage'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
--- a/dom/network/interfaces/moz.build
+++ b/dom/network/interfaces/moz.build
@@ -23,14 +23,8 @@ if CONFIG['MOZ_B2G_RIL']:
         'nsIDOMMobileConnection.idl',
         'nsIDOMMozEmergencyCbModeEvent.idl',
         'nsIDOMNetworkStats.idl',
         'nsIDOMNetworkStatsManager.idl',
         'nsIMobileConnectionProvider.idl',
     ]
 
 XPIDL_MODULE = 'dom_network'
-
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
--- a/dom/payment/interfaces/moz.build
+++ b/dom/payment/interfaces/moz.build
@@ -8,12 +8,8 @@ XPIDL_SOURCES += [
     'nsIDOMPaymentRequestInfo.idl',
     'nsINavigatorPayment.idl',
     'nsIPaymentFlowInfo.idl',
     'nsIPaymentUIGlue.idl',
 ]
 
 XPIDL_MODULE = 'dom_payment'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/interfaces/base',
-]
-
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -24,20 +24,16 @@ XPIDL_SOURCES += [
     'nsIVolumeMountLock.idl',
     'nsIVolumeService.idl',
     'nsIVolumeStat.idl',
     'nsIWorkerHolder.idl',
 ]
 
 XPIDL_MODULE = 'dom_system_gonk'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/network/interfaces',
-]
-
 MODULE = 'dom'
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     EXPORTS += [
         'GonkGPSGeolocationProvider.h',
         'nsVolume.h',
         'nsVolumeService.h',
     ]
--- a/dom/telephony/moz.build
+++ b/dom/telephony/moz.build
@@ -5,22 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsITelephonyProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_telephony'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 CPP_SOURCES += [
     'CallEvent.cpp',
     'CallsList.cpp',
     'Telephony.cpp',
     'TelephonyCall.cpp',
 ]
--- a/dom/voicemail/moz.build
+++ b/dom/voicemail/moz.build
@@ -8,22 +8,16 @@ XPIDL_SOURCES += [
     'nsIDOMMozVoicemail.idl',
     'nsIDOMMozVoicemailEvent.idl',
     'nsIDOMMozVoicemailStatus.idl',
     'nsIVoicemailProvider.idl',
 ]
 
 XPIDL_MODULE = 'dom_voicemail'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-]
-
 MODULE = 'dom'
 
 EXPORTS.mozilla.dom += [
     'Voicemail.h',
 ]
 
 CPP_SOURCES += [
     'Voicemail.cpp',
--- a/dom/wifi/moz.build
+++ b/dom/wifi/moz.build
@@ -7,23 +7,16 @@
 XPIDL_SOURCES += [
     'nsIDOMMozWifiConnectionInfoEvent.idl',
     'nsIDOMMozWifiStatusChangeEvent.idl',
     'nsIWifi.idl',
 ]
 
 XPIDL_MODULE = 'dom_wifi'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/dom/base',
-    '-I$(topsrcdir)/dom/interfaces/base',
-    '-I$(topsrcdir)/dom/interfaces/events',
-    '-I$(topsrcdir)/dom/system/gonk',
-]
-
 MODULE = 'dom'
 
 EXTRA_COMPONENTS += [
     'DOMWifiManager.js',
     'DOMWifiManager.manifest',
     'WifiWorker.js',
     'WifiWorker.manifest',
 ]
--- a/hal/moz.build
+++ b/hal/moz.build
@@ -1,16 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
-    'nsIRecoveryService.idl',
+    'gonk/nsIRecoveryService.idl',
 ]
 
 MODULE = 'hal'
 
 EXPORTS.mozilla += [
     'Hal.h',
     'HalImpl.h',
     'HalSandbox.h',
--- a/js/src/config/config.mk
+++ b/js/src/config/config.mk
@@ -359,17 +359,16 @@ endif
 #
 MY_CONFIG	:= $(DEPTH)/config/myconfig.mk
 MY_RULES	:= $(DEPTH)/config/myrules.mk
 
 #
 # Default command macros; can be overridden in <arch>.mk.
 #
 CCC = $(CXX)
-XPIDL_LINK = $(PYTHON) $(LIBXUL_DIST)/sdk/bin/xpt.py link
 
 # Java macros
 JAVA_GEN_DIR  = _javagen
 JAVA_DIST_DIR = $(DEPTH)/$(JAVA_GEN_DIR)
 JAVA_IFACES_PKG_NAME = org/mozilla/interfaces
 
 OS_INCLUDES += $(MOZ_JPEG_CFLAGS) $(MOZ_PNG_CFLAGS) $(MOZ_ZLIB_CFLAGS)
 
@@ -516,22 +515,18 @@ endif
 ifneq (WINNT_,$(OS_ARCH)_$(GNU_CC))
 LIBS_DIR	= -L$(DIST)/bin -L$(DIST)/lib
 ifdef LIBXUL_SDK
 LIBS_DIR	+= -L$(LIBXUL_SDK)/bin -L$(LIBXUL_SDK)/lib
 endif
 endif
 
 # Default location of include files
-IDL_DIR		= $(DIST)/idl
-
-XPIDL_FLAGS += -I$(srcdir) -I$(IDL_DIR)
-ifdef LIBXUL_SDK
-XPIDL_FLAGS += -I$(LIBXUL_SDK)/idl
-endif
+IDL_PARSER_DIR = $(topsrcdir)/xpcom/idl-parser
+IDL_PARSER_CACHE_DIR = $(DEPTH)/xpcom/idl-parser
 
 SDK_LIB_DIR = $(DIST)/sdk/lib
 SDK_BIN_DIR = $(DIST)/sdk/bin
 
 DEPENDENCIES	= .md
 
 MOZ_COMPONENT_LIBS=$(XPCOM_LIBS) $(MOZ_COMPONENT_NSPR_LIBS)
 
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -28,25 +28,33 @@ endif
   NO_DIST_INSTALL \
   PARALLEL_DIRS \
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPIDL_MODULE \
   $(NULL)
 
+_DEPRECATED_VARIABLES := \
+  XPIDL_FLAGS \
+  $(NULL)
+
 ifndef EXTERNALLY_MANAGED_MAKE_FILE
 # Using $(firstword) may not be perfect. But it should be good enough for most
 # scenarios.
 _current_makefile = $(CURDIR)/$(firstword $(MAKEFILE_LIST))
 
 $(foreach var,$(_MOZBUILD_EXTERNAL_VARIABLES),$(if $($(var)),\
     $(error Variable $(var) is defined in $(_current_makefile). It should only be defined in moz.build files),\
     ))
 
+$(foreach var,$(_DEPRECATED_VARIABLES),$(if $($(var)),\
+    $(error Variable $(var) is defined in $(_current_makefile). This variable has been deprecated. It does nothing. It must be removed in order to build)\
+    ))
+
 ifneq (,$(XPIDLSRCS)$(SDK_XPIDLSRCS))
     $(error XPIDLSRCS and SDK_XPIDLSRCS have been merged and moved to moz.build files as the XPIDL_SOURCES variable. You must move these variables out of $(_current_makefile))
 endif
 
 # Import the automatically generated backend file. If this file doesn't exist,
 # the backend hasn't been properly configured. We want this to be a fatal
 # error, hence not using "-include".
 ifndef STANDALONE_MAKEFILE
@@ -412,18 +420,16 @@ endif
 #
 # the Solaris WorkShop template repository cache.  it occasionally can get
 # out of sync, so targets like clobber should kill it.
 #
 ifeq ($(SOLARIS_SUNPRO_CXX),1)
 GARBAGE_DIRS += SunWS_cache
 endif
 
-XPIDL_GEN_DIR		= _xpidlgen
-
 ifdef MOZ_UPDATE_XTERM
 # Its good not to have a newline at the end of the titlebar string because it
 # makes the make -s output easier to read.  Echo -n does not work on all
 # platforms, but we can trick printf into doing it.
 UPDATE_TITLE = printf "\033]0;%s in %s\007" $(1) $(shell $(BUILD_TOOLS)/print-depth-path.sh)/$(2) ;
 endif
 
 # Static directories are largely independent of our build system. But, they
@@ -1383,108 +1389,33 @@ 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
 
 ################################################################################
-# Export the elements of $(XPIDLSRCS)
-# generating .h and .xpt files and moving them to the appropriate places.
-
-ifneq ($(XPIDLSRCS),) #{
-
-export:: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS))
-
-ifndef XPIDL_MODULE
-XPIDL_MODULE		= $(MODULE)
-endif
-
-ifeq ($(XPIDL_MODULE),) # we need $(XPIDL_MODULE) to make $(XPIDL_MODULE).xpt
-export:: FORCE
-	@echo
-	@echo "*** Error processing XPIDLSRCS:"
-	@echo "Please define MODULE or XPIDL_MODULE when defining XPIDLSRCS,"
-	@echo "so we have a module name to use when creating MODULE.xpt."
-	@echo; sleep 2; false
-endif
-
-# generate .h files from into $(XPIDL_GEN_DIR), then export to $(DIST)/include;
-# warn against overriding existing .h file.
-
-XPIDL_DEPS = \
-  $(LIBXUL_DIST)/sdk/bin/header.py \
-  $(LIBXUL_DIST)/sdk/bin/typelib.py \
-  $(LIBXUL_DIST)/sdk/bin/xpidl.py \
-  $(NULL)
-
-xpidl-preqs = \
-  $(call mkdir_deps,$(XPIDL_GEN_DIR)) \
-  $(call mkdir_deps,$(MDDEPDIR)) \
-  $(NULL)
-
-$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
-	$(REPORT_BUILD)
-	$(PYTHON_PATH) \
-	  $(PLY_INCLUDE) \
-	  $(LIBXUL_DIST)/sdk/bin/header.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
-	@if test -n "$(findstring $*.h, $(EXPORTS))"; \
-	  then echo "*** WARNING: file $*.h generated from $*.idl overrides $(srcdir)/$*.h"; else true; fi
-
-# generate intermediate .xpt files into $(XPIDL_GEN_DIR), then link
-# into $(XPIDL_MODULE).xpt and export it to $(FINAL_TARGET)/components.
-$(XPIDL_GEN_DIR)/%.xpt: %.idl $(XPIDL_DEPS) $(xpidl-preqs)
-	$(REPORT_BUILD)
-	$(PYTHON_PATH) \
-	  $(PLY_INCLUDE) \
-	  -I$(topsrcdir)/xpcom/typelib/xpt/tools \
-	  $(LIBXUL_DIST)/sdk/bin/typelib.py $(XPIDL_FLAGS) $(_VPATH_SRCS) -d $(MDDEPDIR)/$(@F).pp -o $@
-
-# no need to link together if XPIDLSRCS contains only XPIDL_MODULE
-ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
-XPT_PY = $(filter %/xpt.py,$(XPIDL_LINK))
-
-xpidl-idl2xpt = $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
-xpidl-module-deps = $(xpidl-idl2xpt) $(GLOBAL_DEPS) $(XPT_PY)
-
-$(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(xpidl-module-deps)
-	$(XPIDL_LINK) $@ $(xpidl-idl2xpt)
-
-$(XPT_PY):
-	$(MAKE) -C $(DEPTH)/xpcom/typelib/xpt/tools libs
-
-endif # XPIDL_MODULE.xpt != XPIDLSRCS
+# 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
-XPIDL_MODULE_FILES := $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
-XPIDL_MODULE_DEST := $(FINAL_TARGET)/components
-INSTALL_TARGETS += XPIDL_MODULE
+_XPT_NAME_FILES := $(DEPTH)/config/makefiles/xpidl/xpt/$(XPT_NAME)
+_XPT_NAME_DEST := $(FINAL_TARGET)/components
+INSTALL_TARGETS += _XPT_NAME
 
 ifndef NO_INTERFACES_MANIFEST
 libs:: $(call mkdir_deps,$(FINAL_TARGET)/components)
-	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPIDL_MODULE).xpt"
+	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/components/interfaces.manifest "interfaces $(XPT_NAME)"
 	@$(PYTHON) $(MOZILLA_DIR)/config/buildlist.py $(FINAL_TARGET)/chrome.manifest "manifest components/interfaces.manifest"
 endif
 endif
 
-GARBAGE_DIRS		+= $(XPIDL_GEN_DIR)
-
-ifndef NO_DIST_INSTALL
-XPIDL_HEADERS_FILES := $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.h, $(XPIDLSRCS))
-XPIDL_HEADERS_DEST := $(DIST)/include
-XPIDL_HEADERS_TARGET := export
-INSTALL_TARGETS += XPIDL_HEADERS
-
-XPIDLSRCS_FILES := $(XPIDLSRCS)
-XPIDLSRCS_DEST := $(IDL_DIR)
-XPIDLSRCS_TARGET := export
-INSTALL_TARGETS += XPIDLSRCS
-endif
-endif #} XPIDLSRCS
+endif #} XPT_NAME
 
 ################################################################################
 # Copy each element of EXTRA_COMPONENTS to $(FINAL_TARGET)/components
 ifneq (,$(filter %.js,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
 ifeq (,$(filter %.manifest,$(EXTRA_COMPONENTS) $(EXTRA_PP_COMPONENTS)))
 ifndef NO_JS_MANIFEST
 $(error .js component without matching .manifest. See https://developer.mozilla.org/en/XPCOM/XPCOM_changes_in_Gecko_2.0)
 endif
@@ -1686,17 +1617,17 @@ endif
 #
 #   We use $(CURDIR) in the rule's target to ensure that we don't find
 #   a dependency directory in the source tree via VPATH (perhaps from
 #   a previous build in the source tree) and thus neglect to create a
 #   dependency directory in the object directory, where we really need
 #   it.
 
 ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
-MDDEPEND_FILES		:= $(strip $(wildcard $(foreach file,$(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS) $(TARGETS) $(XPIDLSRCS:.idl=.h) $(XPIDLSRCS:.idl=.xpt)),$(MDDEPDIR)/$(notdir $(file)).pp) $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES))))
+MDDEPEND_FILES		:= $(strip $(wildcard $(foreach file,$(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS) $(TARGETS)),$(MDDEPDIR)/$(notdir $(file)).pp) $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES))))
 
 ifneq (,$(MDDEPEND_FILES))
 ifdef .PYMAKE
 includedeps $(MDDEPEND_FILES)
 else
 include $(MDDEPEND_FILES)
 endif
 endif
@@ -1879,17 +1810,16 @@ check:: $(SUBMAKEFILES) $(MAKE_DIRS)
 	$(LOOP_OVER_TOOL_DIRS)
 endif
 
 
 FREEZE_VARIABLES = \
   CSRCS \
   CPPSRCS \
   EXPORTS \
-  XPIDLSRCS \
   DIRS \
   LIBRARY \
   MODULE \
   SHORT_LIBNAME \
   TIERS \
   EXTRA_COMPONENTS \
   EXTRA_PP_COMPONENTS \
   MOCHITEST_FILES \
--- a/js/xpconnect/tests/idl/Makefile.in
+++ b/js/xpconnect/tests/idl/Makefile.in
@@ -8,11 +8,11 @@ topsrcdir = @top_srcdir@
 srcdir = @srcdir@
 VPATH = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk
 
 componentdir = js/xpconnect/tests/components
-libs:: $(XPIDL_GEN_DIR)/$(MODULE).xpt
+libs:: $(DEPTH)/config/makefiles/xpidl/xpt/$(MODULE).xpt
 	$(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/native
 	$(INSTALL) $^ $(testxpcobjdir)/$(componentdir)/js
--- a/netwerk/mime/moz.build
+++ b/netwerk/mime/moz.build
@@ -5,20 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIMIMEHeaderParam.idl',
     'nsIMIMEInfo.idl',
     'nsIMIMEService.idl',
 ]
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'mimetype'
 
 EXPORTS += [
     'nsMimeTypes.h',
 ]
 
 CPP_SOURCES += [
     'nsMIMEHeaderParamImpl.cpp',
--- a/netwerk/protocol/file/moz.build
+++ b/netwerk/protocol/file/moz.build
@@ -6,20 +6,16 @@
 
 XPIDL_SOURCES += [
     'nsIFileChannel.idl',
     'nsIFileProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_file'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
 CPP_SOURCES += [
     'nsFileChannel.cpp',
     'nsFileProtocolHandler.cpp',
 ]
 
 LIBRARY_NAME = 'nkfile_s'
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -15,20 +15,16 @@ XPIDL_SOURCES += [
     'nsIHttpChannelInternal.idl',
     'nsIHttpEventSink.idl',
     'nsIHttpHeaderVisitor.idl',
     'nsIHttpProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_http'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
 EXPORTS += [
     'nsHttp.h',
     'nsHttpAtomList.h',
     'nsHttpHeaderArray.h',
     'nsHttpResponseHead.h',
 ]
--- a/netwerk/protocol/res/moz.build
+++ b/netwerk/protocol/res/moz.build
@@ -5,18 +5,14 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIResProtocolHandler.idl',
 ]
 
 XPIDL_MODULE = 'necko_res'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
 CPP_SOURCES += [
     'nsResProtocolHandler.cpp',
 ]
 
--- a/netwerk/protocol/viewsource/moz.build
+++ b/netwerk/protocol/viewsource/moz.build
@@ -5,20 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIViewSourceChannel.idl',
 ]
 
 XPIDL_MODULE = 'necko_viewsource'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
 CPP_SOURCES += [
     'nsViewSourceChannel.cpp',
     'nsViewSourceHandler.cpp',
 ]
 
 LIBRARY_NAME = 'nkviewsource_s'
--- a/netwerk/protocol/wyciwyg/moz.build
+++ b/netwerk/protocol/wyciwyg/moz.build
@@ -5,20 +5,16 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIWyciwygChannel.idl',
 ]
 
 XPIDL_MODULE = 'necko_wyciwyg'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
 EXPORTS.mozilla.net += [
     'WyciwygChannelChild.h',
     'WyciwygChannelParent.h',
 ]
 
 CPP_SOURCES += [
--- a/netwerk/streamconv/public/moz.build
+++ b/netwerk/streamconv/public/moz.build
@@ -15,14 +15,10 @@ XPIDL_SOURCES += [
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     XPIDL_SOURCES += [
         'nsIAppleFileDecoder.idl',
     ]
 
 XPIDL_MODULE = 'necko_strconv'
 
-XPIDL_FLAGS += [
-    '-I$(topsrcdir)/netwerk/base/public',
-]
-
 MODULE = 'necko'
 
new file mode 100755
--- /dev/null
+++ b/python/mozbuild/mozbuild/action/xpidl-process.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+# 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/.
+
+# This script is used to generate an output header and xpt file for
+# input IDL file(s). It's purpose is to directly support the build
+# system. The API will change to meet the needs of the build system.
+
+import argparse
+import os
+import sys
+
+from io import BytesIO
+
+from header import print_header
+from typelib import write_typelib
+from xpidl import IDLParser
+from xpt import xpt_link
+
+from mozbuild.util import FileAvoidWrite
+
+
+def process(input_dir, cache_dir, header_dir, xpt_dir, deps_dir, module, stems):
+    p = IDLParser(outputdir=cache_dir)
+
+    xpts = {}
+    deps = set()
+
+    # Write out dependencies for Python modules we import. If this list isn't
+    # up to date, we will not re-process XPIDL files if the processor changes.
+    for imported in ('header', 'typelib', 'xpidl', 'xpt'):
+        path = sys.modules[imported].__file__
+
+        if path.endswith('.pyc'):
+            path = path[0:-1]
+
+        deps.add(path)
+
+    for stem in stems:
+        path = os.path.join(input_dir, '%s.idl' % stem)
+        idl_data = open(path).read()
+
+        idl = p.parse(idl_data, filename=path)
+        idl.resolve([input_dir], p)
+
+        header_path = os.path.join(header_dir, '%s.h' % stem)
+        deps_path = os.path.join(deps_dir, '%s.pp' % stem)
+
+        xpt = BytesIO()
+        write_typelib(idl, xpt, path)
+        xpt.seek(0)
+        xpts[stem] = xpt
+
+        deps |= set(dep.replace('\\', '/') for dep in idl.deps)
+
+        with FileAvoidWrite(header_path) as fh:
+            print_header(idl, fh, path)
+
+    # TODO use FileAvoidWrite once it supports binary mode.
+    xpt_path = os.path.join(xpt_dir, '%s.xpt' % module)
+    xpt_link(xpts.values()).write(xpt_path)
+
+    deps_path = os.path.join(deps_dir, '%s.pp' % module)
+    with FileAvoidWrite(deps_path) as fh:
+        # Need output to be consistent to avoid rewrites.
+        s_deps = sorted(deps)
+        fh.write('%s: %s\n' % (xpt_path, ' '.join(s_deps)))
+        for dep in s_deps:
+            fh.write('%s:\n' % dep)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--cache-dir',
+        help='Directory in which to find or write cached lexer data.')
+    parser.add_argument('inputdir',
+        help='Directory in which to find source .idl files.')
+    parser.add_argument('headerdir',
+        help='Directory in which to write header files.')
+    parser.add_argument('xptdir',
+        help='Directory in which to write xpt file.')
+    parser.add_argument('depsdir',
+        help='Directory in which to write dependency files.')
+    parser.add_argument('module',
+        help='Final module name to use for linked output xpt file.')
+    parser.add_argument('idls', nargs='+',
+        help='Source .idl file(s). Specified as stems only.')
+
+    args = parser.parse_args()
+    process(args.inputdir, args.cache_dir, args.headerdir, args.xptdir,
+        args.depsdir, args.module, args.idls)
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -0,0 +1,58 @@
+# 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/.
+
+from __future__ import unicode_literals
+
+import mozpack.path as mozpath
+
+from .base import BuildBackend
+
+from ..frontend.data import XPIDLFile
+
+
+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 = {}
+
+    def register_idl(self, source, module, allow_existing=False):
+        """Registers an IDL file with this instance.
+
+        The IDL file will be built, installed, etc.
+        """
+        basename = mozpath.basename(source)
+        root = mozpath.splitext(basename)[0]
+
+        entry = {
+            'source': source,
+            'module': module,
+            'basename': basename,
+            'root': root,
+        }
+
+        if not allow_existing and entry['basename'] in self.idls:
+            raise Exception('IDL already registered: %' % entry['basename'])
+
+        self.idls[entry['basename']] = entry
+        self.modules.setdefault(entry['module'], set()).add(entry['root'])
+
+
+class CommonBackend(BuildBackend):
+    """Holds logic common to all build backends."""
+
+    def _init(self):
+        self._idl_manager = XPIDLManager(self.environment)
+
+    def consume_object(self, obj):
+        if isinstance(obj, XPIDLFile):
+            self._idl_manager.register_idl(obj.source_path, obj.module)
+
+    def consume_finished(self):
+        if len(self._idl_manager.idls):
+            self._handle_idl_manager(self._idl_manager)
--- a/python/mozbuild/mozbuild/backend/configenvironment.py
+++ b/python/mozbuild/mozbuild/backend/configenvironment.py
@@ -163,33 +163,35 @@ class ConfigEnvironment(object):
 
     def get_input(self, file):
         '''Returns the input file path in the source tree that can be used
         to create the given config file or header.
         '''
         assert(isinstance(file, basestring))
         return os.path.normpath(os.path.join(self.topsrcdir, "%s.in" % relpath(file, self.topobjdir)))
 
-    def create_config_file(self, path):
+    def create_config_file(self, path, extra=None):
         '''Creates the given config file. A config file is generated by
         taking the corresponding source file and replacing occurences of
         "@VAR@" by the value corresponding to "VAR" in the substs dict.
 
         Additional substs are defined according to the file being treated:
             "srcdir" for its the path to its source directory
             "relativesrcdir" for its source directory relative to the top
             "DEPTH" for the path to the top object directory
         '''
         input = self.get_input(path)
         pp = Preprocessor()
         pp.context.update(self.substs)
         pp.context.update(top_srcdir = self.get_top_srcdir(path))
         pp.context.update(srcdir = self.get_file_srcdir(path))
         pp.context.update(relativesrcdir = self.get_relative_srcdir(path))
         pp.context.update(DEPTH = self.get_depth(path))
+        if extra:
+            pp.context.update(extra)
         pp.do_filter('attemptSubstitution')
         pp.setMarker(None)
 
         pp.out = FileAvoidWrite(path)
         pp.do_include(input)
         return pp.out.close()
 
     def create_config_header(self, path):
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -4,32 +4,33 @@
 
 from __future__ import unicode_literals
 
 import errno
 import logging
 import os
 import types
 
-import mozpack.path
 from mozpack.copier import FilePurger
 from mozpack.manifests import (
     InstallManifest,
     PurgeManifest,
 )
+import mozpack.path as mozpath
 
-from .base import BuildBackend
+from .common import CommonBackend
 from ..frontend.data import (
     ConfigFileSubstitution,
     DirectoryTraversal,
     IPDLFile,
     SandboxDerived,
     VariablePassthru,
     Exports,
     Program,
+    XPIDLFile,
     XpcshellManifests,
 )
 from ..util import FileAvoidWrite
 
 
 STUB_MAKEFILE = '''
 # THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.
 
@@ -70,55 +71,70 @@ class BackendMakeFile(object):
     """
 
     def __init__(self, srcdir, objdir, environment):
         self.srcdir = srcdir
         self.objdir = objdir
         self.environment = environment
         self.path = os.path.join(objdir, 'backend.mk')
 
+        # XPIDLFiles attached to this file.
+        self.idls = []
+        self.xpt_name = None
+
         self.fh = FileAvoidWrite(self.path)
         self.fh.write('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT.\n')
         self.fh.write('\n')
         self.fh.write('MOZBUILD_DERIVED := 1\n')
 
         # The global rule to incur backend generation generates Makefiles.
         self.fh.write('NO_MAKEFILE_RULE := 1\n')
 
         # We can't blindly have a SUBMAKEFILES rule because some of the
         # Makefile may not have a corresponding Makefile.in. For the case
         # where a new directory is added, the mozbuild file referencing that
         # new directory will need updated. This will cause a full backend
         # scan and build, installing the new Makefile.
         self.fh.write('NO_SUBMAKEFILES_RULE := 1\n')
 
-
     def write(self, buf):
         self.fh.write(buf)
 
     def close(self):
+        if self.xpt_name:
+            self.fh.write('XPT_NAME := %s\n' % self.xpt_name)
+
+            self.fh.write('NONRECURSIVE_TARGETS += export\n')
+            self.fh.write('NONRECURSIVE_TARGETS_export += xpidl\n')
+            self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_DIRECTORY = '
+                '$(DEPTH)/config/makefiles/xpidl\n')
+            self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_TARGETS += '
+                'xpt/%s' % self.xpt_name)
+
         return self.fh.close()
 
 
-class RecursiveMakeBackend(BuildBackend):
+class RecursiveMakeBackend(CommonBackend):
     """Backend that integrates with the existing recursive make build system.
 
     This backend facilitates the transition from Makefile.in to moz.build
     files.
 
     This backend performs Makefile.in -> Makefile conversion. It also writes
     out .mk files containing content derived from moz.build files. Both are
     consumed by the recursive make builder.
 
     This backend may eventually evolve to write out non-recursive make files.
     However, as long as there are Makefile.in files in the tree, we are tied to
     recursive make and thus will need this backend.
     """
 
     def _init(self):
+        CommonBackend._init(self)
+
         self._backend_files = {}
         self._ipdl_sources = set()
 
         def detailed(summary):
             return '{:d} total backend files. {:d} created; {:d} updated; {:d} unchanged'.format(
                 summary.managed_count, summary.created_count,
                 summary.updated_count, summary.unchanged_count)
 
@@ -135,68 +151,80 @@ class RecursiveMakeBackend(BuildBackend)
 
         self._purge_manifests = dict(
             dist_bin=PurgeManifest(relpath='dist/bin'),
             dist_include=PurgeManifest(relpath='dist/include'),
             dist_private=PurgeManifest(relpath='dist/private'),
             dist_public=PurgeManifest(relpath='dist/public'),
             dist_sdk=PurgeManifest(relpath='dist/sdk'),
             tests=PurgeManifest(relpath='_tests'),
+            xpidl=PurgeManifest(relpath='config/makefiles/xpidl'),
+        )
+
+        self._install_manifests = dict(
+            dist_idl=InstallManifest(),
         )
 
     def _update_from_avoid_write(self, result):
         existed, updated = result
 
         if not existed:
             self.summary.created_count += 1
         elif updated:
             self.summary.updated_count += 1
         else:
             self.summary.unchanged_count += 1
 
     def consume_object(self, obj):
         """Write out build files necessary to build with recursive make."""
 
+        CommonBackend.consume_object(self, obj)
+
         if not isinstance(obj, SandboxDerived):
             return
 
         backend_file = self._backend_files.get(obj.srcdir,
             BackendMakeFile(obj.srcdir, obj.objdir, self.get_environment(obj)))
 
         if isinstance(obj, DirectoryTraversal):
             self._process_directory_traversal(obj, backend_file)
         elif isinstance(obj, ConfigFileSubstitution):
             self._update_from_avoid_write(
                 backend_file.environment.create_config_file(obj.output_path))
             self.backend_input_files.add(obj.input_path)
             self.summary.managed_count += 1
+        elif isinstance(obj, XPIDLFile):
+            backend_file.idls.append(obj)
+            backend_file.xpt_name = '%s.xpt' % obj.module
         elif isinstance(obj, VariablePassthru):
             # Sorted so output is consistent and we don't bump mtimes.
             for k, v in sorted(obj.variables.items()):
                 if isinstance(v, list):
                     for item in v:
                         backend_file.write('%s += %s\n' % (k, item))
 
                 else:
                     backend_file.write('%s := %s\n' % (k, v))
         elif isinstance(obj, Exports):
             self._process_exports(obj.exports, backend_file)
 
         elif isinstance(obj, IPDLFile):
-            self._ipdl_sources.add(mozpack.path.join(obj.srcdir, obj.basename))
+            self._ipdl_sources.add(mozpath.join(obj.srcdir, obj.basename))
 
         elif isinstance(obj, Program):
             self._process_program(obj.program, backend_file)
 
         elif isinstance(obj, XpcshellManifests):
             self._process_xpcshell_manifests(obj, backend_file)
 
         self._backend_files[obj.srcdir] = backend_file
 
     def consume_finished(self):
+        CommonBackend.consume_finished(self)
+
         for srcdir in sorted(self._backend_files.keys()):
             bf = self._backend_files[srcdir]
 
             if not os.path.exists(bf.objdir):
                 try:
                     os.makedirs(bf.objdir)
                 except OSError as error:
                     if error.errno != errno.EEXIST:
@@ -356,16 +384,69 @@ class RecursiveMakeBackend(BuildBackend)
                 p = '%s%s' % (namespace, s)
                 self._purge_manifests['dist_include'].add(p)
 
         children = exports.get_children()
         for subdir in sorted(children):
             self._process_exports(children[subdir], backend_file,
                                   namespace=namespace + subdir)
 
+    def _handle_idl_manager(self, manager):
+        build_files = self._purge_manifests['xpidl']
+
+        for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done',
+            'headers/.mkdir.done', 'xpt/.mkdir.done'):
+            build_files.add(p)
+
+        for idl in manager.idls.values():
+            self._install_manifests['dist_idl'].add_symlink(idl['source'],
+                idl['basename'])
+            self._purge_manifests['dist_include'].add('%s.h' % idl['root'])
+            build_files.add(mozpath.join('headers', '%s.h' % idl['root']))
+
+        for module in manager.modules:
+            build_files.add(mozpath.join('xpt', '%s.xpt' % module))
+            build_files.add(mozpath.join('.deps', '%s.pp' % module))
+
+        headers = sorted('%s.h' % idl['root'] for idl in manager.idls.values())
+        modules = manager.modules
+        xpt_modules = sorted(modules.keys())
+        rules = []
+
+        for module in xpt_modules:
+            deps = sorted(modules[module])
+            rules.extend([
+                '$(idl_xpt_dir)/%s.xpt:' % module,
+                '\t@echo "$(notdir $@)"',
+                '\t$(idlprocess) $(basename $(notdir $@)) %s' % ' '.join(deps),
+                '',
+            ])
+
+            # Set up linkage so make knows headers come from $(idlprocess).
+            h = ['$(idl_headers_dir)/%s.h' % dep for dep in deps]
+            rules.extend([
+                '%s: $(idl_xpt_dir)/%s.xpt' % (' '.join(h), module),
+                '',
+            ])
+
+        # 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/purge manifests.
+
+        out_path = os.path.join(self.environment.topobjdir, 'config',
+            'makefiles', 'xpidl', 'Makefile')
+        result = self.environment.create_config_file(out_path, extra=dict(
+            xpidl_rules='\n'.join(rules),
+            xpidl_modules=' '.join(xpt_modules),
+            xpidl_headers=' '.join(headers),
+        ))
+        self._update_from_avoid_write(result)
+        self.summary.managed_count += 1
+
     def _process_program(self, program, backend_file):
         backend_file.write('PROGRAM = %s\n' % program)
 
     def _process_xpcshell_manifests(self, obj, backend_file, namespace=""):
         manifest = obj.xpcshell_manifests
         backend_file.write('XPCSHELL_TESTS += %s\n' % os.path.dirname(manifest))
         if obj.relativedir != '':
             manifest = '%s/%s' % (obj.relativedir, manifest)
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -12,16 +12,18 @@ All data structures of interest are chil
 Logic for populating these data structures is not defined in this class.
 Instead, what we have here are dumb container classes. The emitter module
 contains the code for converting executed mozbuild files into these data
 structures.
 """
 
 from __future__ import unicode_literals
 
+import os
+
 from collections import OrderedDict
 
 
 class TreeMetadata(object):
     """Base class for all data being captured."""
 
 
 class ReaderSummary(TreeMetadata):
@@ -131,16 +133,32 @@ class VariablePassthru(SandboxDerived):
     in our build backends since we will continue to be tied to our rules.mk.
     """
     __slots__ = ('variables')
 
     def __init__(self, sandbox):
         SandboxDerived.__init__(self, sandbox)
         self.variables = {}
 
+class XPIDLFile(SandboxDerived):
+    """Describes an XPIDL file to be compiled."""
+
+    __slots__ = (
+        'basename',
+        'source_path',
+    )
+
+    def __init__(self, sandbox, source, module):
+        SandboxDerived.__init__(self, sandbox)
+
+        self.source_path = source
+        self.basename = os.path.basename(source)
+        self.module = module
+
+
 class Exports(SandboxDerived):
     """Sandbox container object for EXPORTS, which is a HierarchicalStringList.
 
     We need an object derived from SandboxDerived for use in the backend, so
     this object fills that role. It just has a reference to the underlying
     HierarchicalStringList, which is created when parsing EXPORTS.
     """
     __slots__ = ('exports')
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -1,39 +1,50 @@
 # 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/.
 
 from __future__ import unicode_literals
 
+import logging
 import os
 
+from mach.mixin.logging import LoggingMixin
+
+import mozpack.path as mozpath
+
 from .data import (
     ConfigFileSubstitution,
     DirectoryTraversal,
     Exports,
     IPDLFile,
     Program,
     ReaderSummary,
     VariablePassthru,
+    XPIDLFile,
     XpcshellManifests,
 )
 
-from .reader import MozbuildSandbox
+from .reader import (
+    MozbuildSandbox,
+    SandboxValidationError,
+)
 
 
-class TreeMetadataEmitter(object):
+class TreeMetadataEmitter(LoggingMixin):
     """Converts the executed mozbuild files into data structures.
 
     This is a bridge between reader.py and data.py. It takes what was read by
     reader.BuildReader and converts it into the classes defined in the data
     module.
     """
 
     def __init__(self, config):
+        self.populate_logger()
+
         self.config = config
 
     def emit(self, output):
         """Convert the BuildReader output into data structures.
 
         The return value from BuildReader.read_topsrcdir() (a generator) is
         typically fed into this function.
         """
@@ -69,16 +80,37 @@ class TreeMetadataEmitter(object):
                 path = path[1:]
 
             sub = ConfigFileSubstitution(sandbox)
             sub.input_path = os.path.join(sandbox['SRCDIR'], '%s.in' % path)
             sub.output_path = os.path.join(sandbox['OBJDIR'], path)
             sub.relpath = path
             yield sub
 
+        # XPIDL source files get processed and turned into .h and .xpt files.
+        # If there are multiple XPIDL files in a directory, they get linked
+        # together into a final .xpt, which has the name defined by either
+        # MODULE or XPIDL_MODULE (if the latter is defined).
+        xpidl_module = sandbox['MODULE']
+        if sandbox['XPIDL_MODULE']:
+            xpidl_module = sandbox['XPIDL_MODULE']
+
+        if sandbox['XPIDL_SOURCES'] and not xpidl_module:
+            raise SandboxValidationError('MODULE or XPIDL_MODULE must be '
+                'defined if XPIDL_SOURCES is defined.')
+
+        if sandbox['XPIDL_SOURCES'] and sandbox['NO_DIST_INSTALL']:
+            self.log(logging.WARN, 'mozbuild_warning', dict(
+                path=sandbox.main_path),
+                '{path}: NO_DIST_INSTALL has no effect on XPIDL_SOURCES.')
+
+        for idl in sandbox['XPIDL_SOURCES']:
+            yield XPIDLFile(sandbox, mozpath.join(sandbox['SRCDIR'], idl),
+                xpidl_module)
+
         # Proxy some variables as-is until we have richer classes to represent
         # them. We should aim to keep this set small because it violates the
         # desired abstraction of the build definition away from makefiles.
         passthru = VariablePassthru(sandbox)
         varmap = dict(
             # Makefile.in : moz.build
             ASFILES='ASFILES',
             CMMSRCS='CMMSRCS',
@@ -99,20 +131,17 @@ class TreeMetadataEmitter(object):
             JS_MODULES_PATH='JS_MODULES_PATH',
             LIBRARY_NAME='LIBRARY_NAME',
             LIBS='LIBS',
             MODULE='MODULE',
             SDK_LIBRARY='SDK_LIBRARY',
             SHARED_LIBRARY_LIBS='SHARED_LIBRARY_LIBS',
             SIMPLE_PROGRAMS='SIMPLE_PROGRAMS',
             SSRCS='SSRCS',
-            XPIDL_FLAGS='XPIDL_FLAGS',
-            XPIDL_MODULE='XPIDL_MODULE',
-            XPIDLSRCS='XPIDL_SOURCES',
-            )
+        )
         for mak, moz in varmap.items():
             if sandbox[moz]:
                 passthru.variables[mak] = sandbox[moz]
 
         if sandbox['NO_DIST_INSTALL']:
             passthru.variables['NO_DIST_INSTALL'] = '1'
 
         if passthru.variables:
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -290,20 +290,18 @@ VARIABLES = {
         like @foo@ will be substituted with the values of the AC_SUBST
         variables declared during configure.
         """),
 
     'MODULE': (unicode, unicode, "",
         """Module name.
 
         Historically, this variable was used to describe where to install header
-        files, but that feature is now handled by EXPORTS_NAMESPACES. Currently
-        it is used as the XPIDL module name if XPIDL_MODULE is not defined, but
-        using XPIDL_MODULE directly is preferred. MODULE will likely be removed
-        in the future.
+        files, but that feature is now handled by EXPORTS_NAMESPACES. MODULE
+        will likely be removed in the future.
         """),
 
     'EXPORTS': (HierarchicalStringList, list, HierarchicalStringList(),
         """List of files to be exported, and in which subdirectories.
 
         EXPORTS is generally used to list the include files to be exported to
         dist/include, but it can be used for other files as well. This variable
         behaves as a list when appending filenames for export in the top-level
@@ -350,24 +348,16 @@ 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.
         """),
 
-    'XPIDL_FLAGS': (list, list, [],
-        """XPCOM Interface Definition Module Flags.
-
-        This is a list of extra flags that are passed to the IDL compiler.
-        Typically this is a set of -I flags that denote extra include
-        directories to search for included .idl files.
-        """),
-
     'IPDL_SOURCES': (StrictOrderingOnAppendList, list, [],
         """IPDL source files.
 
         These are .ipdl files that will be parsed and converted to .cpp files.
         """),
 
     'XPCSHELL_TESTS_MANIFESTS': (StrictOrderingOnAppendList, list, [],
         """XPCSHELL Test Manifest list
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -70,16 +70,21 @@ CONFIGS = {
             ('XPCSHELL_TESTS_MANIFESTS', 'XPCSHELL_TESTS'),
             ],
     },
     'ipdl_sources': {
         'defines': [],
         'non_global_defines': [],
         'substs': [],
     },
+    'xpidl': {
+        'defines': [],
+        'non_global_defines': [],
+        'substs': [],
+    },
 }
 
 
 class BackendTester(unittest.TestCase):
     def _get_environment(self, name):
         """Obtain a new instance of a ConfigEnvironment for a known profile.
 
         A new temporary object directory is created for the environment. The
@@ -90,19 +95,17 @@ class BackendTester(unittest.TestCase):
         objdir = mkdtemp()
         self.addCleanup(rmtree, objdir)
 
         srcdir = os.path.join(test_data_path, name)
         config['substs'].append(('top_srcdir', srcdir))
         return ConfigEnvironment(srcdir, objdir, **config)
 
     def _emit(self, name, env=None):
-        if not env:
-            env = self._get_environment(name)
-
+        env = env or self._get_environment(name)
         reader = BuildReader(env)
         emitter = TreeMetadataEmitter(env)
 
         return env, emitter.emit(reader.read_topsrcdir())
 
     def _consume(self, name, cls, env=None):
         env, objs = self._emit(name, env=env)
         backend = cls(env)
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -1,15 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-XPIDL_SOURCES = ['bar.idl', 'biz.idl', 'foo.idl']
-XPIDL_MODULE = 'module_name'
-XPIDL_FLAGS = ['-Idir1', '-Idir2', '-Idir3']
+MODULE = 'module_name'
 
 ASFILES = ['bar.s', 'foo.asm']
 
 DEFINES = ['-Dbar', '-Dfoo']
 
 EXTRA_COMPONENTS = ['bar.js', 'foo.js']
 EXTRA_PP_COMPONENTS = ['bar.pp.js', 'foo.pp.js']
 
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/xpidl/moz.build
@@ -0,0 +1,6 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+MODULE = 'my_module'
+XPIDL_SOURCES = ['bar.idl', 'foo.idl']
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -212,29 +212,16 @@ class TestRecursiveMakeBackend(BackendTe
             'SIMPLE_PROGRAMS': [
                 'SIMPLE_PROGRAMS += bar.x',
                 'SIMPLE_PROGRAMS += foo.x',
             ],
             'SSRCS': [
                 'SSRCS += bar.S',
                 'SSRCS += foo.S',
             ],
-            'XPIDL_FLAGS': [
-                'XPIDL_FLAGS += -Idir1',
-                'XPIDL_FLAGS += -Idir2',
-                'XPIDL_FLAGS += -Idir3',
-            ],
-            'XPIDL_MODULE': [
-                'XPIDL_MODULE := module_name'
-            ],
-            'XPIDLSRCS': [
-                'XPIDLSRCS += bar.idl',
-                'XPIDLSRCS += biz.idl',
-                'XPIDLSRCS += foo.idl',
-            ]
         }
 
         for var, val in expected.items():
             # print("test_variable_passthru[%s]" % (var))
             found = [str for str in lines if str.startswith(var)]
             self.assertEqual(found, val)
 
     def test_exports(self):
@@ -276,16 +263,44 @@ class TestRecursiveMakeBackend(BackendTe
         # Avoid positional parameter and async related breakage
         var = 'XPCSHELL_TESTS'
         xpclines = sorted([val for val in lines if val.startswith(var)])
 
         # Assignment[aa], append[cc], conditional[valid]
         expected = ('aa', 'bb', 'cc', 'dd', 'valid_val')
         self.assertEqual(xpclines, ["XPCSHELL_TESTS += %s" % val for val in expected])
 
+    def test_xpidl_generation(self):
+        """Ensure xpidl files and directories are written out."""
+        env = self._consume('xpidl', RecursiveMakeBackend)
+
+        # Purge manifests should contain entries.
+        purge_dir = os.path.join(env.topobjdir, '_build_manifests', 'purge')
+        install_dir = os.path.join(env.topobjdir, '_build_manifests',
+            'install')
+        self.assertTrue(os.path.isfile(os.path.join(purge_dir, 'xpidl')))
+        self.assertTrue(os.path.isfile(os.path.join(install_dir, 'dist_idl')))
+
+        m = PurgeManifest(path=os.path.join(purge_dir, 'xpidl'))
+        self.assertIn('.deps/my_module.pp', m.entries)
+        self.assertIn('xpt/my_module.xpt', m.entries)
+
+        m = InstallManifest(path=os.path.join(install_dir, 'dist_idl'))
+        self.assertEqual(len(m), 2)
+        self.assertIn('bar.idl', m)
+        self.assertIn('foo.idl', m)
+
+        m = PurgeManifest(path=os.path.join(purge_dir, 'dist_include'))
+        self.assertIn('foo.h', m.entries)
+
+        p = os.path.join(env.topobjdir, 'config/makefiles/xpidl')
+        self.assertTrue(os.path.isdir(p))
+
+        self.assertTrue(os.path.isfile(os.path.join(p, 'Makefile')))
+
     def test_xpcshell_master_manifest(self):
         """Ensure that the master xpcshell manifest is written out correctly."""
         env = self._consume('xpcshell_manifests', RecursiveMakeBackend)
 
         manifest_path = os.path.join(env.topobjdir,
             'testing', 'xpcshell', 'xpcshell.ini')
         lines = [l.strip() for l in open(manifest_path, 'rt').readlines()]
         expected = ('aa', 'bb', 'cc', 'dd', 'valid_val')
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -1,15 +1,13 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-XPIDL_SOURCES += ['bar.idl', 'biz.idl', 'foo.idl']
-XPIDL_MODULE = 'module_name'
-XPIDL_FLAGS += ['-Idir1', '-Idir2', '-Idir3']
+MODULE = 'module_name'
 
 ASFILES += ['fans.asm', 'tans.s']
 
 DEFINES=['-Dfans', '-Dtans']
 
 EXTRA_COMPONENTS=['fans.js', 'tans.js']
 EXTRA_PP_COMPONENTS=['fans.pp.js', 'tans.pp.js']
 
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -139,24 +139,22 @@ class TestEmitterBasic(unittest.TestCase
             GTEST_CMMSRCS=['test1.mm', 'test2.mm'],
             GTEST_CPPSRCS=['test1.cpp', 'test2.cpp'],
             HOST_CPPSRCS=['fans.cpp', 'tans.cpp'],
             HOST_CSRCS=['fans.c', 'tans.c'],
             HOST_LIBRARY_NAME='host_fans',
             LIBRARY_NAME='lib_name',
             LIBS=['fans.lib', 'tans.lib'],
             NO_DIST_INSTALL='1',
+            MODULE='module_name',
             SDK_LIBRARY=['fans.sdk', 'tans.sdk'],
             SHARED_LIBRARY_LIBS=['fans.sll', 'tans.sll'],
             SIMPLE_PROGRAMS=['fans.x', 'tans.x'],
             SSRCS=['fans.S', 'tans.S'],
-            XPIDLSRCS=['bar.idl', 'biz.idl', 'foo.idl'],
-            XPIDL_MODULE='module_name',
-            XPIDL_FLAGS=['-Idir1', '-Idir2', '-Idir3'],
-            )
+        )
 
         variables = objs[1].variables
         self.assertEqual(len(variables), len(wanted))
 
         for var, val in wanted.items():
             # print("test_variable_passthru[%s]" % var)
             self.assertIn(var, variables)
             self.assertEqual(variables[var], val)
--- a/toolkit/crashreporter/test/Makefile.in
+++ b/toolkit/crashreporter/test/Makefile.in
@@ -15,17 +15,16 @@ FORCE_SHARED_LIB = 1
 
 VPATH += \
   $(srcdir)/../google-breakpad/src/processor/ \
   $(srcdir)/../google-breakpad/src/common/ \
   $(topsrcdir)/build/ \
   $(NULL)
 
 LOCAL_INCLUDES += \
-  -I$(XPIDL_GEN_DIR) \
   -I$(srcdir)/../google-breakpad/src/ \
   $(NULL)
 EXTRA_DSO_LDOPTS += $(LIBS_DIR) $(MOZ_COMPONENT_LIBS) $(XPCOM_GLUE_LDOPTS)
 
 MOCHITEST_BROWSER_FILES = \
   browser/head.js \
   browser/crashreport.sjs \
   browser/browser_aboutCrashes.js \
--- a/xpcom/idl-parser/Makefile.in
+++ b/xpcom/idl-parser/Makefile.in
@@ -13,18 +13,18 @@ include $(DEPTH)/config/autoconf.mk
 PARSER_SRCS = \
   header.py \
   typelib.py \
   xpidl.py \
   $(NULL)
 
 SDK_BINARY = \
   $(PARSER_SRCS) \
-  xpidllex.py \
-  xpidlyacc.py \
+  $(IDL_PARSER_CACHE_DIR)/xpidllex.py \
+  $(IDL_PARSER_CACHE_DIR)/xpidlyacc.py \
   $(NULL)
 
 SDK_BINARY_TARGET = xpidl-parser
 
 ifndef MOZ_SYSTEM_PLY
 PLY_FILES = \
   $(topsrcdir)/other-licenses/ply/ply/__init__.py \
   $(topsrcdir)/other-licenses/ply/ply/lex.py \
@@ -34,29 +34,31 @@ PLY_FILES = \
 PLY_DEST = $(SDK_BIN_DIR)/ply
 INSTALL_TARGETS += PLY
 PLY_TARGET = xpidl-parser
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 # Generate the PLY lexer and parser.
-xpidllex.py: $(PARSER_SRCS) $(PLY_FILES)
+$(IDL_PARSER_CACHE_DIR)/xpidllex.py: $(PARSER_SRCS) $(PLY_FILES)
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
-	  $(srcdir)/header.py --cachedir=. --regen
+	  $(srcdir)/header.py --cachedir=$(IDL_PARSER_CACHE_DIR) --regen
 
 # generating xpidllex.py generates xpidlyacc.py too
-xpidlyacc.py: xpidllex.py
+$(IDL_PARSER_CACHE_DIR)/xpidlyacc.py: $(IDL_PARSER_CACHE_DIR)/xpidllex.py
 
 check::
 	$(PYTHON_PATH) \
 	  $(PLY_INCLUDE) \
 	  -I. \
 	  $(srcdir)/runtests.py
 
-GARBAGE += \
+garbage_files := \
   xpidllex.py \
   xpidllex.pyc \
   xpidlyacc.py \
   xpidlyacc.pyc \
   xpidl_debug \
   $(NULL)
+
+GARBAGE += $(addprefix $(IDL_PARSER_CACHE_DIR)/,$(garbage_files))