Bug 578478: Switch to pyxpidl for header generation. Parts by bsmedberg, with r=jorendorff,khuey, and parts by me, with r=bsmedberg
authorKyle Huey <khuey@kylehuey.com>
Tue, 19 Jul 2011 14:46:25 -0700
changeset 73947 85f7679fd5eb481ea62fa3a047136969c3660586
parent 73946 398402eabdb09416fb7d9755f5cb06af15e73c1d
child 73948 e5a6f94154c746e05dbd9404595a6746467e257b
push id235
push userbzbarsky@mozilla.com
push dateTue, 27 Sep 2011 17:13:04 +0000
treeherdermozilla-beta@2d1e082d176a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff, khuey, and, bsmedberg
bugs578478
milestone8.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 578478: Switch to pyxpidl for header generation. Parts by bsmedberg, with r=jorendorff,khuey, and parts by me, with r=bsmedberg
config/rules.mk
embedding/browser/webBrowser/nsIWebBrowserChrome3.idl
js/src/config/rules.mk
xpcom/idl-parser/header.py
xpcom/idl-parser/xpidl.py
xpcom/idl-parser/xpidllex.py
xpcom/idl-parser/xpidlyacc.py
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -377,17 +377,17 @@ endif
 
 LIBOBJS			:= $(addprefix \", $(OBJS))
 LIBOBJS			:= $(addsuffix \", $(LIBOBJS))
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPFILES		= $(addprefix $(MDDEPDIR)/,$(OBJS:.$(OBJ_SUFFIX)=.pp))
 ifndef NO_GEN_XPT
-MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.xpt))
+MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.h.pp) $(XPIDLSRCS:.idl=.xpt.pp))
 endif
 endif
 endif
 
 ALL_TRASH = \
 	$(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \
 	$(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \
 	$(OBJS:.$(OBJ_SUFFIX)=.i) \
@@ -1525,28 +1525,36 @@ endif
 # warn against overriding existing .h file. 
 $(XPIDL_GEN_DIR)/.done:
 	$(MKDIR) -p $(XPIDL_GEN_DIR)
 	@$(TOUCH) $@
 
 # don't depend on $(XPIDL_GEN_DIR), because the modification date changes
 # with any addition to the directory, regenerating all .h files -> everything.
 
-$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done
+XPIDL_DEPS = \
+  $(topsrcdir)/xpcom/idl-parser/header.py \
+  $(topsrcdir)/xpcom/idl-parser/xpidl.py \
+  $(NULL)
+
+$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
-	$(ELOG) $(XPIDL_COMPILE) -m header -w $(XPIDL_FLAGS) -o $(XPIDL_GEN_DIR)/$* $(_VPATH_SRCS)
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/other-licenses/ply \
+	  -I$(topsrcdir)/xpcom/idl-parser \
+	  $(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(topsrcdir)/xpcom/idl-parser $(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
 
 ifndef NO_GEN_XPT
 # 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_COMPILE) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
-	$(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$*.pp $(_VPATH_SRCS)
+	$(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$(@F).pp $(_VPATH_SRCS)
 
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
 libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
--- a/embedding/browser/webBrowser/nsIWebBrowserChrome3.idl
+++ b/embedding/browser/webBrowser/nsIWebBrowserChrome3.idl
@@ -1,65 +1,66 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Margaret Leibovic <margaret.leibovic@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-#include "nsIWebBrowserChrome2.idl"
-#include "nsIURI.idl"
-#include "nsIDOMNode.idl"
-
-/**
- * nsIWebBrowserChrome3 is an extension to nsIWebBrowserChrome2.
- */
-[scriptable, uuid(7f2aa813-b250-4e46-afeb-97b1e91bc9a5)]
-interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
-{
-  /**
-   * Determines the appropriate target for a link.
-   *
-   * @param originalTarget
-   *        The original link target.
-   * @param linkURI
-   *        Link destination URI.
-   * @param aDOMNode
-   *        Link DOM node.
-   * @param isAppTab
-   *        Whether or not the link is in an app tab.
-   * @returns A new link target, if appropriate.
-   *          Otherwise returns originalTarget.
-   */
-  AString onBeforeLinkTraversal(in AString originalTarget,
-                                in nsIURI linkURI,
-                                in nsIDOMNode linkNode,
-                                in PRBool isAppTab);
-};
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Margaret Leibovic <margaret.leibovic@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIWebBrowserChrome2.idl"
+#include "nsIURI.idl"
+#include "nsIDOMNode.idl"
+
+/**
+ * nsIWebBrowserChrome3 is an extension to nsIWebBrowserChrome2.
+ */
+[scriptable, uuid(7f2aa813-b250-4e46-afeb-97b1e91bc9a5)]
+interface nsIWebBrowserChrome3 : nsIWebBrowserChrome2
+{
+  /**
+   * Determines the appropriate target for a link.
+   *
+   * @param originalTarget
+   *        The original link target.
+   * @param linkURI
+   *        Link destination URI.
+   * @param aDOMNode
+   *        Link DOM node.
+   * @param isAppTab
+   *        Whether or not the link is in an app tab.
+   * @returns A new link target, if appropriate.
+   *          Otherwise returns originalTarget.
+   */
+  AString onBeforeLinkTraversal(in AString originalTarget,
+                                in nsIURI linkURI,
+                                in nsIDOMNode linkNode,
+                                in PRBool isAppTab);
+};
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -377,17 +377,17 @@ endif
 
 LIBOBJS			:= $(addprefix \", $(OBJS))
 LIBOBJS			:= $(addsuffix \", $(LIBOBJS))
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPFILES		= $(addprefix $(MDDEPDIR)/,$(OBJS:.$(OBJ_SUFFIX)=.pp))
 ifndef NO_GEN_XPT
-MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.xpt))
+MDDEPFILES		+= $(addprefix $(MDDEPDIR)/,$(XPIDLSRCS:.idl=.h.pp) $(XPIDLSRCS:.idl=.xpt.pp))
 endif
 endif
 endif
 
 ALL_TRASH = \
 	$(GARBAGE) $(TARGETS) $(OBJS) $(PROGOBJS) LOGS TAGS a.out \
 	$(filter-out $(ASFILES),$(OBJS:.$(OBJ_SUFFIX)=.s)) $(OBJS:.$(OBJ_SUFFIX)=.ii) \
 	$(OBJS:.$(OBJ_SUFFIX)=.i) \
@@ -1525,28 +1525,36 @@ endif
 # warn against overriding existing .h file. 
 $(XPIDL_GEN_DIR)/.done:
 	$(MKDIR) -p $(XPIDL_GEN_DIR)
 	@$(TOUCH) $@
 
 # don't depend on $(XPIDL_GEN_DIR), because the modification date changes
 # with any addition to the directory, regenerating all .h files -> everything.
 
-$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_COMPILE) $(XPIDL_GEN_DIR)/.done
+XPIDL_DEPS = \
+  $(topsrcdir)/xpcom/idl-parser/header.py \
+  $(topsrcdir)/xpcom/idl-parser/xpidl.py \
+  $(NULL)
+
+$(XPIDL_GEN_DIR)/%.h: %.idl $(XPIDL_DEPS) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
-	$(ELOG) $(XPIDL_COMPILE) -m header -w $(XPIDL_FLAGS) -o $(XPIDL_GEN_DIR)/$* $(_VPATH_SRCS)
+	$(PYTHON) $(topsrcdir)/config/pythonpath.py \
+	  -I$(topsrcdir)/other-licenses/ply \
+	  -I$(topsrcdir)/xpcom/idl-parser \
+	  $(topsrcdir)/xpcom/idl-parser/header.py --cachedir=$(DEPTH)/xpcom/idl-parser $(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
 
 ifndef NO_GEN_XPT
 # 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_COMPILE) $(XPIDL_GEN_DIR)/.done
 	$(REPORT_BUILD)
-	$(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$*.pp $(_VPATH_SRCS)
+	$(ELOG) $(XPIDL_COMPILE) -m typelib -w $(XPIDL_FLAGS) -e $@ -d $(MDDEPDIR)/$(@F).pp $(_VPATH_SRCS)
 
 # no need to link together if XPIDLSRCS contains only XPIDL_MODULE
 ifneq ($(XPIDL_MODULE).idl,$(strip $(XPIDLSRCS)))
 $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt: $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS)) $(GLOBAL_DEPS)
 	$(XPIDL_LINK) $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt $(patsubst %.idl,$(XPIDL_GEN_DIR)/%.xpt,$(XPIDLSRCS))
 endif # XPIDL_MODULE.xpt != XPIDLSRCS
 
 libs:: $(XPIDL_GEN_DIR)/$(XPIDL_MODULE).xpt
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -53,38 +53,50 @@ else:
         pass
 
 def firstCap(str):
     return str[0].upper() + str[1:]
 
 def attributeParamName(a):
     return "a" + firstCap(a.name)
 
+def attributeParamNames(a):
+    l = [attributeParamName(a)]
+    if a.implicit_jscontext:
+        l.insert(0, "cx")
+    return ", ".join(l)
+
 def attributeNativeName(a, getter):
     binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
     return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
 def attributeReturnType(a, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if (a.nostdcall):
         return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
     else:
         return macro
 
 def attributeParamlist(a, getter):
-    return "%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
-                     attributeParamName(a))
+    l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
+                   attributeParamName(a))]
+    if a.implicit_jscontext:
+        l.insert(0, "JSContext* cx")
+
+    return ", ".join(l)
 
 def attributeAsNative(a, getter):
         scriptable = a.isScriptable() and "NS_SCRIPTABLE " or ""
+        deprecated = a.deprecated and "NS_DEPRECATED " or ""
         params = {'scriptable': scriptable,
+                  'deprecated': deprecated,
                   'returntype': attributeReturnType(a, 'NS_IMETHOD'),
                   'binaryname': attributeNativeName(a, getter),
                   'paramlist': attributeParamlist(a, getter)}
-        return "%(scriptable)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
+        return "%(deprecated)s%(scriptable)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
 def methodNativeName(m):
     return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
 def methodReturnType(m, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if m.nostdcall and m.notxpcom:
         return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
@@ -97,49 +109,62 @@ def methodReturnType(m, macro):
         return macro
 
 def methodAsNative(m):
     scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
 
     return "%s%s %s(%s)" % (scriptable,
                             methodReturnType(m, 'NS_IMETHOD'),
                             methodNativeName(m),
-                            paramlistAsNative(m.params,
-                                              m.realtype,
-                                              notxpcom=m.notxpcom))
+                            paramlistAsNative(m))
+
+def paramlistAsNative(m, empty='void'):
+    l = [paramAsNative(p) for p in m.params]
+
+    if m.implicit_jscontext:
+        l.append("JSContext* cx")
 
-def paramlistAsNative(l, rettype, notxpcom, empty='void'):
-    l = list(l)
-    if not notxpcom and rettype.name != 'void':
-        l.append(xpidl.Param(paramtype='out',
-                             type=None,
-                             name='_retval',
-                             attlist=[],
-                             location=None,
-                             realtype=rettype))
+    if m.optional_argc:
+        l.append('PRUint8 _argc')
+
+    if not m.notxpcom and m.realtype.name != 'void':
+        l.append(paramAsNative(xpidl.Param(paramtype='out',
+                                           type=None,
+                                           name='_retval',
+                                           attlist=[],
+                                           location=None,
+                                           realtype=m.realtype)))
 
     if len(l) == 0:
         return empty
 
-    return ", ".join([paramAsNative(p) for p in l])
+    return ", ".join(l)
 
 def paramAsNative(p):
     if p.paramtype == 'in':
         typeannotate = ''
     else:
         typeannotate = ' NS_%sPARAM' % p.paramtype.upper()
 
     return "%s%s%s" % (p.nativeType(),
                        p.name,
                        typeannotate)
 
-def paramlistNames(l, rettype, notxpcom):
-    names = [p.name for p in l]
-    if not notxpcom and rettype.name != 'void':
+def paramlistNames(m):
+    names = [p.name for p in m.params]
+
+    if m.implicit_jscontext:
+        names.append('cx')
+
+    if m.optional_argc:
+        names.append('_argc')
+
+    if not m.notxpcom and m.realtype.name != 'void':
         names.append('_retval')
+
     if len(names) == 0:
         return ''
     return ', '.join(names)
 
 header = """/*
  * DO NOT EDIT.  THIS FILE IS GENERATED FROM %(filename)s
  */
 
@@ -391,25 +416,25 @@ def write_interface(iface, fd):
 
     fd.write(iface_forward % names)
 
     def emitTemplate(tmpl):
         for member in iface.members:
             if isinstance(member, xpidl.Attribute):
                 fd.write(tmpl % {'asNative': attributeAsNative(member, True),
                                  'nativeName': attributeNativeName(member, True),
-                                 'paramList': attributeParamName(member)})
+                                 'paramList': attributeParamNames(member)})
                 if not member.readonly:
                     fd.write(tmpl % {'asNative': attributeAsNative(member, False),
                                      'nativeName': attributeNativeName(member, False),
-                                     'paramList': attributeParamName(member)})
+                                     'paramList': attributeParamNames(member)})
             elif isinstance(member, xpidl.Method):
                 fd.write(tmpl % {'asNative': methodAsNative(member),
                                  'nativeName': methodNativeName(member),
-                                 'paramList': paramlistNames(member.params, member.realtype, member.notxpcom)})
+                                 'paramList': paramlistNames(member)})
         if len(iface.members) == 0:
             fd.write('\\\n  /* no methods! */')
         elif not member.kind in ('attribute', 'method'):
             fd.write('\\')
 
     emitTemplate("\\\n  %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
 
     fd.write(iface_forward_safe % names)
@@ -430,28 +455,56 @@ def write_interface(iface, fd):
                 fd.write(example_tmpl % {'implclass': implclass,
                                          'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                          'nativeName': attributeNativeName(member, False),
                                          'paramList': attributeParamlist(member, False)})
         elif isinstance(member, xpidl.Method):
             fd.write(example_tmpl % {'implclass': implclass,
                                      'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': methodNativeName(member),
-                                     'paramList': paramlistAsNative(member.params, member.realtype, notxpcom=member.notxpcom, empty='')})
+                                     'paramList': paramlistAsNative(member, empty='')})
         fd.write('\n')
 
     fd.write(iface_template_epilog)
 
 if __name__ == '__main__':
     from optparse import OptionParser
     o = OptionParser()
-    o.add_option('-I', action='append', dest='incdirs', help="Directory to search for imported files", default=[])
-    o.add_option('--cachedir', dest='cachedir', help="Directory in which to cache lex/parse tables.", default='')
+    o.add_option('-I', action='append', dest='incdirs', default=['.'],
+                 help="Directory to search for imported files")
+    o.add_option('--cachedir', dest='cachedir', default=None,
+                 help="Directory in which to cache lex/parse tables.")
+    o.add_option('-o', dest='outfile', default=None,
+                 help="Output file (default is stdout)")
+    o.add_option('-d', dest='depfile', default=None,
+                 help="Generate a make dependency file")
     options, args = o.parse_args()
     file, = args
 
-    if options.cachedir != '':
+    if options.cachedir is not None:
+        if not os.path.isdir(options.cachedir):
+            os.mkdir(options.cachedir)
         sys.path.append(options.cachedir)
 
+    if options.depfile is not None and options.outfile is None:
+        print >>sys.stderr, "-d requires -o"
+        sys.exit(1)
+
+    if options.outfile is not None:
+        outfd = open(options.outfile, 'w')
+        closeoutfd = True
+    else:
+        outfd = sys.stdout
+        closeoutfd = False
+
     p = xpidl.IDLParser(outputdir=options.cachedir)
     idl = p.parse(open(file).read(), filename=file)
     idl.resolve(options.incdirs, p)
-    print_header(idl, sys.stdout, file)
+    print_header(idl, outfd, file)
+
+    if closeoutfd:
+        outfd.close()
+
+    if options.depfile is not None:
+        depfd = open(options.depfile, 'w')
+        deps = [dep.replace('\\', '/') for dep in idl.deps]
+
+        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -277,23 +277,25 @@ class Include(object):
 
         for file in incfiles():
             if not os.path.exists(file): continue
 
             self.IDL = parent.parser.parse(open(file).read(), filename=file)
             self.IDL.resolve(parent.incdirs, parent.parser)
             for type in self.IDL.getNames():
                 parent.setName(type)
+            parent.deps.extend(self.IDL.deps)
             return
 
         raise IDLError("File '%s' not found" % self.filename, self.location)
 
 class IDL(object):
     def __init__(self, productions):
         self.productions = productions
+        self.deps = []
 
     def setName(self, object):
         self.namemap.set(object)
 
     def getName(self, id, location):
         try:
             return self.namemap[id]
         except KeyError:
@@ -455,17 +457,21 @@ class Native(object):
             const = True
 
         if self.specialtype is not None and calltype == 'in':
             const = True
 
         if self.modifier == 'ptr':
             m = '*' + (calltype != 'in' and '*' or '')
         elif self.modifier == 'ref':
-            m = '& '
+            # jsval outparams are odd, for compatibility with existing code
+            if self.specialtype == 'jsval' and calltype == 'out':
+                m = '*'
+            else:
+                m = '& '
         else:
             m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
 class Interface(object):
@@ -647,16 +653,17 @@ class Attribute(object):
     noscript = False
     notxpcom = False
     readonly = False
     implicit_jscontext = False
     nostdcall = False
     binaryname = None
     null = None
     undefined = None
+    deprecated = False
 
     def __init__(self, type, name, attlist, readonly, location, doccomments):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.readonly = readonly
         self.location = location
         self.doccomments = doccomments
@@ -695,16 +702,18 @@ class Attribute(object):
                     raise IDLError("Unexpected attribute value", aloc)
 
                 if name == 'noscript':
                     self.noscript = True
                 elif name == 'notxpcom':
                     self.notxpcom = True
                 elif name == 'implicit_jscontext':
                     self.implicit_jscontext = True
+                elif name == 'deprecated':
+                    self.deprecated = True
                 elif name == 'nostdcall':
                     self.nostdcall = True
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = iface.idl.getName(self.type, self.location)
@@ -733,16 +742,17 @@ class Attribute(object):
 class Method(object):
     kind = 'method'
     noscript = False
     notxpcom = False
     binaryname = None
     implicit_jscontext = False
     nostdcall = False
     optional_argc = False
+    deprecated = False
 
     def __init__(self, type, name, attlist, paramlist, location, doccomments, raises):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.params = paramlist
         self.location = location
         self.doccomments = doccomments
@@ -763,16 +773,18 @@ class Method(object):
             if name == 'noscript':
                 self.noscript = True
             elif name == 'notxpcom':
                 self.notxpcom = True
             elif name == 'implicit_jscontext':
                 self.implicit_jscontext = True
             elif name == 'optional_argc':
                 self.optional_argc = True
+            elif name == 'deprecated':
+                self.deprecated = True
             elif name == 'nostdcall':
                 self.nostdcall = True
             else:
                 raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
         self.namemap = NameMap()
         for p in paramlist:
             self.namemap.set(p)
@@ -1322,17 +1334,20 @@ class IDLParser(object):
             self._doccomments = []
         return t
 
     def parse(self, data, filename=None):
         if filename is not None:
             self.lexer.filename = filename
         self.lexer.lineno = 1
         self.lexer.input(data)
-        return self.parser.parse(lexer=self)
+        idl = self.parser.parse(lexer=self)
+        if filename is not None:
+            idl.deps.append(filename)
+        return idl
 
     def getLocation(self, p, i):
         return Location(self.lexer, p.lineno(i), p.lexpos(i))
 
 if __name__ == '__main__':
     p = IDLParser()
     for f in sys.argv[1:]:
         print "Parsing %s" % f
new file mode 100644
--- /dev/null
+++ b/xpcom/idl-parser/xpidllex.py
@@ -0,0 +1,9 @@
+# xpidllex.py. This file automatically created by PLY (version 3.3). Don't edit!
+_tabversion   = '3.3'
+_lextokens    = {'TYPEDEF': 1, 'INCLUDE': 1, 'RSHIFT': 1, 'LSHIFT': 1, 'ATTRIBUTE': 1, 'NATIVEID': 1, 'NUMBER': 1, 'NATIVE': 1, 'IID': 1, 'READONLY': 1, 'RAISES': 1, 'CDATA': 1, 'IN': 1, 'INTERFACE': 1, 'CONST': 1, 'IDENTIFIER': 1, 'OUT': 1, 'INOUT': 1, 'HEXNUM': 1}
+_lexreflags   = 0
+_lexliterals  = '"(){}[],;:=|+-*'
+_lexstateinfo = {'nativeid': 'exclusive', 'INITIAL': 'inclusive'}
+_lexstatere   = {'nativeid': [('(?P<t_nativeid_NATIVEID>[^()\\n]+(?=\\)))', [None, ('t_nativeid_NATIVEID', 'NATIVEID')])], 'INITIAL': [('(?P<t_multilinecomment>/\\*(?s).*?\\*/)|(?P<t_singlelinecomment>(?m)//.*?$)|(?P<t_IID>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})|(?P<t_IDENTIFIER>unsigned\\ long\\ long|unsigned\\ short|unsigned\\ long|long\\ long|[A-Za-z][A-Za-z_0-9]*)|(?P<t_LCDATA>(?s)%\\{[ ]*C\\+\\+[ ]*\\n(?P<cdata>.*?\\n?)%\\}[ ]*(C\\+\\+)?)|(?P<t_INCLUDE>\\#include[ \\t]+"[^"\\n]+")|(?P<t_directive>\\#(?P<directive>[a-zA-Z]+)[^\\n]+)|(?P<t_newline>\\n+)|(?P<t_HEXNUM>0x[a-fA-F0-9]+)|(?P<t_NUMBER>-?\\d+)|(?P<t_LSHIFT><<)|(?P<t_RSHIFT>>>)', [None, ('t_multilinecomment', 'multilinecomment'), ('t_singlelinecomment', 'singlelinecomment'), ('t_IID', 'IID'), ('t_IDENTIFIER', 'IDENTIFIER'), ('t_LCDATA', 'LCDATA'), None, None, ('t_INCLUDE', 'INCLUDE'), ('t_directive', 'directive'), None, ('t_newline', 'newline'), (None, 'HEXNUM'), (None, 'NUMBER'), (None, 'LSHIFT'), (None, 'RSHIFT')])]}
+_lexstateignore = {'nativeid': '', 'INITIAL': ' \t'}
+_lexstateerrorf = {'nativeid': 't_ANY_error', 'INITIAL': 't_ANY_error'}
new file mode 100644
--- /dev/null
+++ b/xpcom/idl-parser/xpidlyacc.py
@@ -0,0 +1,85 @@
+
+# /home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidlyacc.py
+# This file is automatically generated. Do not edit.
+_tabversion = '3.2'
+
+_lr_method = 'LALR'
+
+_lr_signature = ',Q\xe7:m\xcf|\xa4\x8ad\x0f\x06\xc1Q\x1f\x99'
+    
+_lr_action_items = {'CONST':([6,25,42,47,48,82,84,104,],[14,14,45,45,-28,-29,-41,-42,]),'NATIVEID':([43,],[50,]),'NUMBER':([62,65,66,77,78,79,80,81,83,],[68,68,68,68,68,68,68,68,68,]),'LSHIFT':([67,68,69,70,75,76,92,93,94,95,96,97,98,],[80,-30,-32,-31,80,-34,-33,-35,-37,-36,-38,-39,80,]),'RSHIFT':([67,68,69,70,75,76,92,93,94,95,96,97,98,],[81,-30,-32,-31,81,-34,-33,-35,-37,-36,-38,-39,81,]),'INOUT':([28,64,74,85,],[-13,-14,90,-14,]),'NATIVE':([0,2,5,7,8,9,10,28,31,44,61,],[-14,-14,-14,-14,-14,-14,23,-13,-8,-21,-9,]),')':([33,34,50,64,68,69,70,72,73,75,76,86,92,93,94,95,96,97,98,99,103,106,107,108,111,],[38,39,57,-44,-30,-32,-31,-45,87,92,-34,-43,-33,-35,-37,-36,-38,-39,-40,-45,-46,-47,109,-55,-56,]),'(':([14,16,17,30,37,60,62,65,66,77,78,79,80,81,83,101,],[-12,27,-11,-10,43,64,65,65,65,65,65,65,65,65,65,105,]),'+':([67,68,69,70,75,76,92,93,94,95,96,97,98,],[77,-30,-32,-31,77,-34,-33,-35,-37,-36,77,77,77,]),'*':([67,68,69,70,75,76,92,93,94,95,96,97,98,],[78,-30,-32,-31,78,-34,-33,78,-37,78,78,78,78,]),'-':([62,65,66,67,68,69,70,75,76,77,78,79,80,81,83,92,93,94,95,96,97,98,],[66,66,66,79,-30,-32,-31,79,-34,66,66,66,66,66,66,-33,-35,-37,-36,79,79,79,]),',':([14,15,16,17,26,38,39,72,99,106,108,],[-12,25,-20,-11,-17,-18,-19,85,85,-47,110,]),'IID':([27,],[34,]),'READONLY':([28,42,47,48,49,82,84,104,],[-13,-14,-14,-28,55,-29,-41,-42,]),';':([24,29,36,40,41,52,57,67,68,69,70,71,76,87,92,93,94,95,96,97,98,100,109,],[31,-25,-23,-24,44,-22,61,82,-30,-32,-31,84,-34,-54,-33,-35,-37,-36,-38,-39,-40,104,-53,]),'IDENTIFIER':([3,6,12,22,23,25,27,28,35,42,45,47,48,49,51,56,59,62,63,65,66,77,78,79,80,81,82,83,84,88,89,90,91,102,104,105,110,],[12,17,24,29,30,17,33,-13,40,-14,51,-14,-28,56,58,60,63,69,71,69,69,69,69,69,69,69,-29,69,-41,102,-48,-49,-50,106,-42,108,108,]),'=':([58,],[62,]),'OUT':([28,64,74,85,],[-13,-14,91,-14,]),'TYPEDEF':([0,2,5,7,8,9,31,44,61,],[3,3,3,3,3,3,-8,-21,-9,]),'RAISES':([87,],[101,]),'IN':([28,64,74,85,],[-13,-14,89,-14,]),'[':([0,2,5,7,8,9,31,42,44,47,48,61,64,82,84,85,104,],[6,6,6,6,6,6,-8,6,-21,6,-28,-9,6,-29,-41,6,-42,]),'INCLUDE':([0,2,5,7,8,9,31,44,61,],[7,7,7,7,7,7,-8,-21,-9,]),']':([14,15,16,17,18,26,32,38,39,],[-12,-15,-20,-11,28,-17,-16,-18,-19,]),':':([29,],[35,]),'ATTRIBUTE':([28,42,47,48,49,54,55,82,84,104,],[-13,-14,-14,-28,-52,59,-51,-29,-41,-42,]),'CDATA':([0,2,5,7,8,9,31,42,44,47,48,61,82,84,104,],[9,9,9,9,9,9,-8,48,-21,48,-28,-9,-29,-41,-42,]),'INTERFACE':([0,2,5,7,8,9,10,28,31,44,61,],[-14,-14,-14,-14,-14,-14,22,-13,-8,-21,-9,]),'{':([29,36,40,],[-25,42,-24,]),'$end':([0,1,2,4,5,7,8,9,11,13,19,20,21,31,44,61,],[-2,-1,-2,0,-2,-2,-2,-2,-6,-5,-4,-7,-3,-8,-21,-9,]),'}':([42,46,47,48,53,82,84,104,],[-26,52,-26,-28,-27,-29,-41,-42,]),'|':([67,68,69,70,75,76,92,93,94,95,96,97,98,],[83,-30,-32,-31,83,-34,-33,-35,-37,-36,-38,-39,-40,]),'HEXNUM':([62,65,66,77,78,79,80,81,83,],[70,70,70,70,70,70,70,70,70,]),}
+
+_lr_action = { }
+for _k, _v in _lr_action_items.items():
+   for _x,_y in zip(_v[0],_v[1]):
+      if not _x in _lr_action:  _lr_action[_x] = { }
+      _lr_action[_x][_k] = _y
+del _lr_action_items
+
+_lr_goto_items = {'members':([42,47,],[46,53,]),'attribute':([6,25,],[15,15,]),'number':([62,65,66,77,78,79,80,81,83,],[67,75,76,93,94,95,96,97,98,]),'productions':([0,2,5,7,8,9,],[1,11,13,19,20,21,]),'raises':([87,],[100,]),'ifacebody':([36,],[41,]),'attlist':([6,25,],[18,32,]),'native':([0,2,5,7,8,9,],[8,8,8,8,8,8,]),'typedef':([0,2,5,7,8,9,],[2,2,2,2,2,2,]),'attributeval':([16,],[26,]),'optreadonly':([49,],[54,]),'ifacebase':([29,],[36,]),'afternativeid':([30,],[37,]),'param':([64,85,],[72,99,]),'member':([42,47,],[47,47,]),'idlfile':([0,],[4,]),'paramlist':([64,],[73,]),'moreparams':([72,99,],[86,103,]),'interface':([0,2,5,7,8,9,],[5,5,5,5,5,5,]),'idlist':([105,110,],[107,111,]),'paramtype':([74,],[88,]),'anyident':([6,25,],[16,16,]),'attributes':([0,2,5,7,8,9,42,47,64,85,],[10,10,10,10,10,10,49,49,74,74,]),}
+
+_lr_goto = { }
+for _k, _v in _lr_goto_items.items():
+   for _x,_y in zip(_v[0],_v[1]):
+       if not _x in _lr_goto: _lr_goto[_x] = { }
+       _lr_goto[_x][_k] = _y
+del _lr_goto_items
+_lr_productions = [
+  ("S' -> idlfile","S'",1,None,None,None),
+  ('idlfile -> productions','idlfile',1,'p_idlfile','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1028),
+  ('productions -> <empty>','productions',0,'p_productions_start','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1032),
+  ('productions -> CDATA productions','productions',2,'p_productions_cdata','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1036),
+  ('productions -> INCLUDE productions','productions',2,'p_productions_include','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1041),
+  ('productions -> interface productions','productions',2,'p_productions_interface','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1046),
+  ('productions -> typedef productions','productions',2,'p_productions_interface','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1047),
+  ('productions -> native productions','productions',2,'p_productions_interface','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1048),
+  ('typedef -> TYPEDEF IDENTIFIER IDENTIFIER ;','typedef',4,'p_typedef','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1053),
+  ('native -> attributes NATIVE IDENTIFIER afternativeid ( NATIVEID ) ;','native',8,'p_native','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1060),
+  ('afternativeid -> <empty>','afternativeid',0,'p_afternativeid','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1067),
+  ('anyident -> IDENTIFIER','anyident',1,'p_anyident','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1073),
+  ('anyident -> CONST','anyident',1,'p_anyident','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1074),
+  ('attributes -> [ attlist ]','attributes',3,'p_attributes','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1079),
+  ('attributes -> <empty>','attributes',0,'p_attributes','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1080),
+  ('attlist -> attribute','attlist',1,'p_attlist_start','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1088),
+  ('attlist -> attribute , attlist','attlist',3,'p_attlist_continue','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1092),
+  ('attribute -> anyident attributeval','attribute',2,'p_attribute','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1097),
+  ('attributeval -> ( IDENTIFIER )','attributeval',3,'p_attributeval','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1101),
+  ('attributeval -> ( IID )','attributeval',3,'p_attributeval','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1102),
+  ('attributeval -> <empty>','attributeval',0,'p_attributeval','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1103),
+  ('interface -> attributes INTERFACE IDENTIFIER ifacebase ifacebody ;','interface',6,'p_interface','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1108),
+  ('ifacebody -> { members }','ifacebody',3,'p_ifacebody','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1137),
+  ('ifacebody -> <empty>','ifacebody',0,'p_ifacebody','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1138),
+  ('ifacebase -> : IDENTIFIER','ifacebase',2,'p_ifacebase','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1143),
+  ('ifacebase -> <empty>','ifacebase',0,'p_ifacebase','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1144),
+  ('members -> <empty>','members',0,'p_members_start','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1149),
+  ('members -> member members','members',2,'p_members_continue','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1153),
+  ('member -> CDATA','member',1,'p_member_cdata','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1158),
+  ('member -> CONST IDENTIFIER IDENTIFIER = number ;','member',6,'p_member_const','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1162),
+  ('number -> NUMBER','number',1,'p_number_decimal','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1170),
+  ('number -> HEXNUM','number',1,'p_number_hex','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1175),
+  ('number -> IDENTIFIER','number',1,'p_number_identifier','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1180),
+  ('number -> ( number )','number',3,'p_number_paren','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1186),
+  ('number -> - number','number',2,'p_number_neg','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1190),
+  ('number -> number + number','number',3,'p_number_add','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1195),
+  ('number -> number - number','number',3,'p_number_add','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1196),
+  ('number -> number * number','number',3,'p_number_add','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1197),
+  ('number -> number LSHIFT number','number',3,'p_number_shift','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1208),
+  ('number -> number RSHIFT number','number',3,'p_number_shift','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1209),
+  ('number -> number | number','number',3,'p_number_bitor','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1218),
+  ('member -> attributes optreadonly ATTRIBUTE IDENTIFIER IDENTIFIER ;','member',6,'p_member_att','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1224),
+  ('member -> attributes IDENTIFIER IDENTIFIER ( paramlist ) raises ;','member',8,'p_member_method','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1240),
+  ('paramlist -> param moreparams','paramlist',2,'p_paramlist','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1255),
+  ('paramlist -> <empty>','paramlist',0,'p_paramlist','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1256),
+  ('moreparams -> <empty>','moreparams',0,'p_moreparams_start','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1264),
+  ('moreparams -> , param moreparams','moreparams',3,'p_moreparams_continue','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1268),
+  ('param -> attributes paramtype IDENTIFIER IDENTIFIER','param',4,'p_param','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1273),
+  ('paramtype -> IN','paramtype',1,'p_paramtype','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1281),
+  ('paramtype -> INOUT','paramtype',1,'p_paramtype','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1282),
+  ('paramtype -> OUT','paramtype',1,'p_paramtype','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1283),
+  ('optreadonly -> READONLY','optreadonly',1,'p_optreadonly','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1287),
+  ('optreadonly -> <empty>','optreadonly',0,'p_optreadonly','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1288),
+  ('raises -> RAISES ( idlist )','raises',4,'p_raises','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1295),
+  ('raises -> <empty>','raises',0,'p_raises','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1296),
+  ('idlist -> IDENTIFIER','idlist',1,'p_idlist','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1303),
+  ('idlist -> IDENTIFIER , idlist','idlist',3,'p_idlist_continue','/home/khuey/dev/mozilla-central/xpcom/idl-parser/xpidl.py',1307),
+]