xpcom/idl-parser/header.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/idl-parser/header.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,542 @@
     1.4 +#!/usr/bin/env python
     1.5 +# header.py - Generate C++ header files from IDL.
     1.6 +#
     1.7 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.8 +# License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 +# file, You can obtain one at http://mozilla.org/MPL/2.0/.
    1.10 +
    1.11 +"""Print a C++ header file for the IDL files specified on the command line"""
    1.12 +
    1.13 +import sys, os.path, re, xpidl, itertools, glob
    1.14 +
    1.15 +printdoccomments = False
    1.16 +
    1.17 +if printdoccomments:
    1.18 +    def printComments(fd, clist, indent):
    1.19 +        for c in clist:
    1.20 +            fd.write("%s%s\n" % (indent, c))
    1.21 +else:
    1.22 +    def printComments(fd, clist, indent):
    1.23 +        pass
    1.24 +
    1.25 +def firstCap(str):
    1.26 +    return str[0].upper() + str[1:]
    1.27 +
    1.28 +def attributeParamName(a):
    1.29 +    return "a" + firstCap(a.name)
    1.30 +
    1.31 +def attributeParamNames(a):
    1.32 +    l = [attributeParamName(a)]
    1.33 +    if a.implicit_jscontext:
    1.34 +        l.insert(0, "cx")
    1.35 +    return ", ".join(l)
    1.36 +
    1.37 +def attributeNativeName(a, getter):
    1.38 +    binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
    1.39 +    return "%s%s" % (getter and 'Get' or 'Set', binaryname)
    1.40 +
    1.41 +def attributeReturnType(a, macro):
    1.42 +    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
    1.43 +    if (a.nostdcall):
    1.44 +        return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
    1.45 +    else:
    1.46 +        return macro
    1.47 +
    1.48 +def attributeParamlist(a, getter):
    1.49 +    l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
    1.50 +                   attributeParamName(a))]
    1.51 +    if a.implicit_jscontext:
    1.52 +        l.insert(0, "JSContext* cx")
    1.53 +
    1.54 +    return ", ".join(l)
    1.55 +
    1.56 +def attributeAsNative(a, getter):
    1.57 +        deprecated = a.deprecated and "NS_DEPRECATED " or ""
    1.58 +        params = {'deprecated': deprecated,
    1.59 +                  'returntype': attributeReturnType(a, 'NS_IMETHOD'),
    1.60 +                  'binaryname': attributeNativeName(a, getter),
    1.61 +                  'paramlist': attributeParamlist(a, getter)}
    1.62 +        return "%(deprecated)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
    1.63 +
    1.64 +def methodNativeName(m):
    1.65 +    return m.binaryname is not None and m.binaryname or firstCap(m.name)
    1.66 +
    1.67 +def methodReturnType(m, macro):
    1.68 +    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
    1.69 +    if m.nostdcall and m.notxpcom:
    1.70 +        return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
    1.71 +                         m.realtype.nativeType('in').strip())
    1.72 +    elif m.nostdcall:
    1.73 +        return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
    1.74 +    elif m.notxpcom:
    1.75 +        return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
    1.76 +    else:
    1.77 +        return macro
    1.78 +
    1.79 +def methodAsNative(m):
    1.80 +    return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'),
    1.81 +                          methodNativeName(m),
    1.82 +                          paramlistAsNative(m))
    1.83 +
    1.84 +def paramlistAsNative(m, empty='void'):
    1.85 +    l = [paramAsNative(p) for p in m.params]
    1.86 +
    1.87 +    if m.implicit_jscontext:
    1.88 +        l.append("JSContext* cx")
    1.89 +
    1.90 +    if m.optional_argc:
    1.91 +        l.append('uint8_t _argc')
    1.92 +
    1.93 +    if not m.notxpcom and m.realtype.name != 'void':
    1.94 +        l.append(paramAsNative(xpidl.Param(paramtype='out',
    1.95 +                                           type=None,
    1.96 +                                           name='_retval',
    1.97 +                                           attlist=[],
    1.98 +                                           location=None,
    1.99 +                                           realtype=m.realtype)))
   1.100 +
   1.101 +    if len(l) == 0:
   1.102 +        return empty
   1.103 +
   1.104 +    return ", ".join(l)
   1.105 +
   1.106 +def paramAsNative(p):
   1.107 +    return "%s%s" % (p.nativeType(),
   1.108 +                     p.name)
   1.109 +
   1.110 +def paramlistNames(m):
   1.111 +    names = [p.name for p in m.params]
   1.112 +
   1.113 +    if m.implicit_jscontext:
   1.114 +        names.append('cx')
   1.115 +
   1.116 +    if m.optional_argc:
   1.117 +        names.append('_argc')
   1.118 +
   1.119 +    if not m.notxpcom and m.realtype.name != 'void':
   1.120 +        names.append('_retval')
   1.121 +
   1.122 +    if len(names) == 0:
   1.123 +        return ''
   1.124 +    return ', '.join(names)
   1.125 +
   1.126 +header = """/*
   1.127 + * DO NOT EDIT.  THIS FILE IS GENERATED FROM %(filename)s
   1.128 + */
   1.129 +
   1.130 +#ifndef __gen_%(basename)s_h__
   1.131 +#define __gen_%(basename)s_h__
   1.132 +"""
   1.133 +
   1.134 +include = """
   1.135 +#ifndef __gen_%(basename)s_h__
   1.136 +#include "%(basename)s.h"
   1.137 +#endif
   1.138 +"""
   1.139 +
   1.140 +jsvalue_include = """
   1.141 +#include "js/Value.h"
   1.142 +"""
   1.143 +
   1.144 +infallible_includes = """
   1.145 +#include "mozilla/Assertions.h"
   1.146 +#include "mozilla/DebugOnly.h"
   1.147 +"""
   1.148 +
   1.149 +header_end = """/* For IDL files that don't want to include root IDL files. */
   1.150 +#ifndef NS_NO_VTABLE
   1.151 +#define NS_NO_VTABLE
   1.152 +#endif
   1.153 +"""
   1.154 +
   1.155 +footer = """
   1.156 +#endif /* __gen_%(basename)s_h__ */
   1.157 +"""
   1.158 +
   1.159 +forward_decl = """class %(name)s; /* forward declaration */
   1.160 +
   1.161 +"""
   1.162 +
   1.163 +def idl_basename(f):
   1.164 +    """returns the base name of a file with the last extension stripped"""
   1.165 +    return os.path.basename(f).rpartition('.')[0]
   1.166 +
   1.167 +def print_header(idl, fd, filename):
   1.168 +    fd.write(header % {'filename': filename,
   1.169 +                       'basename': idl_basename(filename)})
   1.170 +
   1.171 +    foundinc = False
   1.172 +    for inc in idl.includes():
   1.173 +        if not foundinc:
   1.174 +            foundinc = True
   1.175 +            fd.write('\n')
   1.176 +        fd.write(include % {'basename': idl_basename(inc.filename)})
   1.177 +
   1.178 +    if idl.needsJSTypes():
   1.179 +        fd.write(jsvalue_include)
   1.180 +
   1.181 +    # Include some extra files if any attributes are infallible.
   1.182 +    for iface in [p for p in idl.productions if p.kind == 'interface']:
   1.183 +        for attr in [m for m in iface.members if isinstance(m, xpidl.Attribute)]:
   1.184 +            if attr.infallible:
   1.185 +                fd.write(infallible_includes)
   1.186 +                break
   1.187 +
   1.188 +    fd.write('\n')
   1.189 +    fd.write(header_end)
   1.190 +
   1.191 +    for p in idl.productions:
   1.192 +        if p.kind == 'include': continue
   1.193 +        if p.kind == 'cdata':
   1.194 +            fd.write(p.data)
   1.195 +            continue
   1.196 +
   1.197 +        if p.kind == 'forward':
   1.198 +            fd.write(forward_decl % {'name': p.name})
   1.199 +            continue
   1.200 +        if p.kind == 'interface':
   1.201 +            write_interface(p, fd)
   1.202 +            continue
   1.203 +        if p.kind == 'typedef':
   1.204 +            printComments(fd, p.doccomments, '')
   1.205 +            fd.write("typedef %s %s;\n\n" % (p.realtype.nativeType('in'),
   1.206 +                                             p.name))
   1.207 +
   1.208 +    fd.write(footer % {'basename': idl_basename(filename)})
   1.209 +
   1.210 +iface_header = r"""
   1.211 +/* starting interface:    %(name)s */
   1.212 +#define %(defname)s_IID_STR "%(iid)s"
   1.213 +
   1.214 +#define %(defname)s_IID \
   1.215 +  {0x%(m0)s, 0x%(m1)s, 0x%(m2)s, \
   1.216 +    { %(m3joined)s }}
   1.217 +
   1.218 +"""
   1.219 +
   1.220 +uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
   1.221 +                              (?P<m1>[a-f0-9]{4})-
   1.222 +                              (?P<m2>[a-f0-9]{4})-
   1.223 +                              (?P<m3>[a-f0-9]{4})-
   1.224 +                              (?P<m4>[a-f0-9]{12})$""", re.X)
   1.225 +
   1.226 +iface_prolog = """ {
   1.227 + public: 
   1.228 +
   1.229 +  NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
   1.230 +
   1.231 +"""
   1.232 +
   1.233 +iface_epilog = """};
   1.234 +
   1.235 +  NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
   1.236 +
   1.237 +/* Use this macro when declaring classes that implement this interface. */
   1.238 +#define NS_DECL_%(macroname)s """
   1.239 +
   1.240 +
   1.241 +iface_forward = """
   1.242 +
   1.243 +/* Use this macro to declare functions that forward the behavior of this interface to another object. */
   1.244 +#define NS_FORWARD_%(macroname)s(_to) """
   1.245 +
   1.246 +iface_forward_safe = """
   1.247 +
   1.248 +/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
   1.249 +#define NS_FORWARD_SAFE_%(macroname)s(_to) """
   1.250 +
   1.251 +iface_template_prolog = """
   1.252 +
   1.253 +#if 0
   1.254 +/* Use the code below as a template for the implementation class for this interface. */
   1.255 +
   1.256 +/* Header file */
   1.257 +class %(implclass)s : public %(name)s
   1.258 +{
   1.259 +public:
   1.260 +  NS_DECL_ISUPPORTS
   1.261 +  NS_DECL_%(macroname)s
   1.262 +
   1.263 +  %(implclass)s();
   1.264 +
   1.265 +private:
   1.266 +  ~%(implclass)s();
   1.267 +
   1.268 +protected:
   1.269 +  /* additional members */
   1.270 +};
   1.271 +
   1.272 +/* Implementation file */
   1.273 +NS_IMPL_ISUPPORTS(%(implclass)s, %(name)s)
   1.274 +
   1.275 +%(implclass)s::%(implclass)s()
   1.276 +{
   1.277 +  /* member initializers and constructor code */
   1.278 +}
   1.279 +
   1.280 +%(implclass)s::~%(implclass)s()
   1.281 +{
   1.282 +  /* destructor code */
   1.283 +}
   1.284 +
   1.285 +"""
   1.286 +
   1.287 +example_tmpl = """%(returntype)s %(implclass)s::%(nativeName)s(%(paramList)s)
   1.288 +{
   1.289 +    return NS_ERROR_NOT_IMPLEMENTED;
   1.290 +}
   1.291 +"""
   1.292 +
   1.293 +iface_template_epilog = """/* End of implementation class template. */
   1.294 +#endif
   1.295 +
   1.296 +"""
   1.297 +
   1.298 +attr_infallible_tmpl = """\
   1.299 +  inline %(realtype)s%(nativename)s(%(args)s)
   1.300 +  {
   1.301 +    %(realtype)sresult;
   1.302 +    mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
   1.303 +    MOZ_ASSERT(NS_SUCCEEDED(rv));
   1.304 +    return result;
   1.305 +  }
   1.306 +"""
   1.307 +
   1.308 +def write_interface(iface, fd):
   1.309 +    if iface.namemap is None:
   1.310 +        raise Exception("Interface was not resolved.")
   1.311 +
   1.312 +    def write_const_decls(g):
   1.313 +        fd.write("  enum {\n")
   1.314 +        enums = []
   1.315 +        for c in g:
   1.316 +            printComments(fd, c.doccomments, '  ')
   1.317 +            basetype = c.basetype
   1.318 +            value = c.getValue()
   1.319 +            enums.append("    %(name)s = %(value)s%(signed)s" % {
   1.320 +                         'name': c.name,
   1.321 +                         'value': value,
   1.322 +                         'signed': (not basetype.signed) and 'U' or ''})
   1.323 +        fd.write(",\n".join(enums))
   1.324 +        fd.write("\n  };\n\n")
   1.325 +
   1.326 +    def write_method_decl(m):
   1.327 +        printComments(fd, m.doccomments, '  ')
   1.328 +
   1.329 +        fd.write("  /* %s */\n" % m.toIDL())
   1.330 +        fd.write("  %s = 0;\n\n" % methodAsNative(m))
   1.331 +                                                                           
   1.332 +    def write_attr_decl(a):
   1.333 +        printComments(fd, a.doccomments, '  ')
   1.334 +
   1.335 +        fd.write("  /* %s */\n" % a.toIDL());
   1.336 +
   1.337 +        fd.write("  %s = 0;\n" % attributeAsNative(a, True))
   1.338 +        if a.infallible:
   1.339 +            fd.write(attr_infallible_tmpl %
   1.340 +                     {'realtype': a.realtype.nativeType('in'),
   1.341 +                      'nativename': attributeNativeName(a, getter=True),
   1.342 +                      'args': '' if not a.implicit_jscontext else 'JSContext* cx',
   1.343 +                      'argnames': '' if not a.implicit_jscontext else 'cx, '})
   1.344 +
   1.345 +        if not a.readonly:
   1.346 +            fd.write("  %s = 0;\n" % attributeAsNative(a, False))
   1.347 +        fd.write("\n")
   1.348 +
   1.349 +    defname = iface.name.upper()
   1.350 +    if iface.name[0:2] == 'ns':
   1.351 +        defname = 'NS_' + defname[2:]
   1.352 +
   1.353 +    names = uuid_decoder.match(iface.attributes.uuid).groupdict()
   1.354 +    m3str = names['m3'] + names['m4']
   1.355 +    names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
   1.356 +
   1.357 +    if iface.name[2] == 'I':
   1.358 +        implclass = iface.name[:2] + iface.name[3:]
   1.359 +    else:
   1.360 +        implclass = '_MYCLASS_'
   1.361 +
   1.362 +    names.update({'defname': defname,
   1.363 +                  'macroname': iface.name.upper(),
   1.364 +                  'name': iface.name,
   1.365 +                  'iid': iface.attributes.uuid,
   1.366 +                  'implclass': implclass})
   1.367 +
   1.368 +    fd.write(iface_header % names)
   1.369 +
   1.370 +    printComments(fd, iface.doccomments, '')
   1.371 +
   1.372 +    fd.write("class ")
   1.373 +    foundcdata = False
   1.374 +    for m in iface.members:
   1.375 +        if isinstance(m, xpidl.CDATA):
   1.376 +            foundcdata = True
   1.377 +
   1.378 +    if not foundcdata:
   1.379 +        fd.write("NS_NO_VTABLE ")
   1.380 +
   1.381 +    if iface.attributes.deprecated:
   1.382 +        fd.write("MOZ_DEPRECATED ")
   1.383 +    fd.write(iface.name)
   1.384 +    if iface.base:
   1.385 +        fd.write(" : public %s" % iface.base)
   1.386 +    fd.write(iface_prolog % names)
   1.387 +
   1.388 +    for key, group in itertools.groupby(iface.members, key=type):
   1.389 +        if key == xpidl.ConstMember:
   1.390 +            write_const_decls(group) # iterator of all the consts
   1.391 +        else:
   1.392 +            for member in group:
   1.393 +                if key == xpidl.Attribute:
   1.394 +                    write_attr_decl(member)
   1.395 +                elif key == xpidl.Method:
   1.396 +                    write_method_decl(member)
   1.397 +                elif key == xpidl.CDATA:
   1.398 +                    fd.write(" %s" % member.data)
   1.399 +                else:
   1.400 +                    raise Exception("Unexpected interface member: %s" % member)
   1.401 +
   1.402 +    fd.write(iface_epilog % names)
   1.403 +
   1.404 +    for member in iface.members:
   1.405 +        if isinstance(member, xpidl.Attribute):
   1.406 +            fd.write("\\\n  %s; " % attributeAsNative(member, True))
   1.407 +            if not member.readonly:
   1.408 +                fd.write("\\\n  %s; " % attributeAsNative(member, False))
   1.409 +        elif isinstance(member, xpidl.Method):
   1.410 +            fd.write("\\\n  %s; " % methodAsNative(member))
   1.411 +    if len(iface.members) == 0:
   1.412 +        fd.write('\\\n  /* no methods! */')
   1.413 +    elif not member.kind in ('attribute', 'method'):
   1.414 +       fd.write('\\')
   1.415 +
   1.416 +    fd.write(iface_forward % names)
   1.417 +
   1.418 +    def emitTemplate(tmpl, tmpl_notxpcom=None):
   1.419 +        if tmpl_notxpcom == None:
   1.420 +            tmpl_notxpcom = tmpl
   1.421 +        for member in iface.members:
   1.422 +            if isinstance(member, xpidl.Attribute):
   1.423 +                fd.write(tmpl % {'asNative': attributeAsNative(member, True),
   1.424 +                                 'nativeName': attributeNativeName(member, True),
   1.425 +                                 'paramList': attributeParamNames(member)})
   1.426 +                if not member.readonly:
   1.427 +                    fd.write(tmpl % {'asNative': attributeAsNative(member, False),
   1.428 +                                     'nativeName': attributeNativeName(member, False),
   1.429 +                                     'paramList': attributeParamNames(member)})
   1.430 +            elif isinstance(member, xpidl.Method):
   1.431 +                if member.notxpcom:
   1.432 +                    fd.write(tmpl_notxpcom % {'asNative': methodAsNative(member),
   1.433 +                                              'nativeName': methodNativeName(member),
   1.434 +                                              'paramList': paramlistNames(member)})
   1.435 +                else:
   1.436 +                    fd.write(tmpl % {'asNative': methodAsNative(member),
   1.437 +                                     'nativeName': methodNativeName(member),
   1.438 +                                     'paramList': paramlistNames(member)})
   1.439 +        if len(iface.members) == 0:
   1.440 +            fd.write('\\\n  /* no methods! */')
   1.441 +        elif not member.kind in ('attribute', 'method'):
   1.442 +            fd.write('\\')
   1.443 +
   1.444 +    emitTemplate("\\\n  %(asNative)s { return _to %(nativeName)s(%(paramList)s); } ")
   1.445 +
   1.446 +    fd.write(iface_forward_safe % names)
   1.447 +
   1.448 +    # Don't try to safely forward notxpcom functions, because we have no
   1.449 +    # sensible default error return.  Instead, the caller will have to
   1.450 +    # implement them.
   1.451 +    emitTemplate("\\\n  %(asNative)s { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ",
   1.452 +                 "\\\n  %(asNative)s; ")
   1.453 +
   1.454 +    fd.write(iface_template_prolog % names)
   1.455 +
   1.456 +    for member in iface.members:
   1.457 +        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
   1.458 +        fd.write("/* %s */\n" % member.toIDL())
   1.459 +        if isinstance(member, xpidl.Attribute):
   1.460 +            fd.write(example_tmpl % {'implclass': implclass,
   1.461 +                                     'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
   1.462 +                                     'nativeName': attributeNativeName(member, True),
   1.463 +                                     'paramList': attributeParamlist(member, True)})
   1.464 +            if not member.readonly:
   1.465 +                fd.write(example_tmpl % {'implclass': implclass,
   1.466 +                                         'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
   1.467 +                                         'nativeName': attributeNativeName(member, False),
   1.468 +                                         'paramList': attributeParamlist(member, False)})
   1.469 +        elif isinstance(member, xpidl.Method):
   1.470 +            fd.write(example_tmpl % {'implclass': implclass,
   1.471 +                                     'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
   1.472 +                                     'nativeName': methodNativeName(member),
   1.473 +                                     'paramList': paramlistAsNative(member, empty='')})
   1.474 +        fd.write('\n')
   1.475 +
   1.476 +    fd.write(iface_template_epilog)
   1.477 +
   1.478 +if __name__ == '__main__':
   1.479 +    from optparse import OptionParser
   1.480 +    o = OptionParser()
   1.481 +    o.add_option('-I', action='append', dest='incdirs', default=['.'],
   1.482 +                 help="Directory to search for imported files")
   1.483 +    o.add_option('--cachedir', dest='cachedir', default=None,
   1.484 +                 help="Directory in which to cache lex/parse tables.")
   1.485 +    o.add_option('-o', dest='outfile', default=None,
   1.486 +                 help="Output file (default is stdout)")
   1.487 +    o.add_option('-d', dest='depfile', default=None,
   1.488 +                 help="Generate a make dependency file")
   1.489 +    o.add_option('--regen', action='store_true', dest='regen', default=False,
   1.490 +                 help="Regenerate IDL Parser cache")
   1.491 +    options, args = o.parse_args()
   1.492 +    file = args[0] if args else None
   1.493 +
   1.494 +    if options.cachedir is not None:
   1.495 +        if not os.path.isdir(options.cachedir):
   1.496 +            os.mkdir(options.cachedir)
   1.497 +        sys.path.append(options.cachedir)
   1.498 +
   1.499 +    # The only thing special about a regen is that there are no input files.
   1.500 +    if options.regen:
   1.501 +        if options.cachedir is None:
   1.502 +            print >>sys.stderr, "--regen useless without --cachedir"
   1.503 +        # Delete the lex/yacc files.  Ply is too stupid to regenerate them
   1.504 +        # properly
   1.505 +        for fileglobs in [os.path.join(options.cachedir, f) for f in ["xpidllex.py*", "xpidlyacc.py*"]]:
   1.506 +            for filename in glob.glob(fileglobs):
   1.507 +                os.remove(filename)
   1.508 +
   1.509 +    # Instantiate the parser.
   1.510 +    p = xpidl.IDLParser(outputdir=options.cachedir)
   1.511 +
   1.512 +    if options.regen:
   1.513 +        sys.exit(0)
   1.514 +
   1.515 +    if options.depfile is not None and options.outfile is None:
   1.516 +        print >>sys.stderr, "-d requires -o"
   1.517 +        sys.exit(1)
   1.518 +
   1.519 +    if options.outfile is not None:
   1.520 +        outfd = open(options.outfile, 'w')
   1.521 +        closeoutfd = True
   1.522 +    else:
   1.523 +        outfd = sys.stdout
   1.524 +        closeoutfd = False
   1.525 +
   1.526 +    idl = p.parse(open(file).read(), filename=file)
   1.527 +    idl.resolve(options.incdirs, p)
   1.528 +    print_header(idl, outfd, file)
   1.529 +
   1.530 +    if closeoutfd:
   1.531 +        outfd.close()
   1.532 +
   1.533 +    if options.depfile is not None:
   1.534 +        dirname = os.path.dirname(options.depfile)
   1.535 +        if dirname:
   1.536 +            try:
   1.537 +                os.makedirs(dirname)
   1.538 +            except:
   1.539 +                pass
   1.540 +        depfd = open(options.depfile, 'w')
   1.541 +        deps = [dep.replace('\\', '/') for dep in idl.deps]
   1.542 +
   1.543 +        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
   1.544 +        for dep in deps:
   1.545 +            print >>depfd, "%s:" % dep

mercurial