ipc/ipdl/ipdl.py

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rwxr-xr-x

Ignore runtime configuration files generated during quality assurance.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 import optparse, os, re, sys
     6 from cStringIO import StringIO
     7 from mozbuild.pythonutil import iter_modules_in_path
     8 import mozpack.path as mozpath
     9 import itertools
    11 import ipdl
    13 def log(minv, fmt, *args):
    14     if _verbosity >= minv:
    15         print fmt % args
    17 # process command line
    19 op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
    20 op.add_option('-I', '--include', dest='includedirs', default=[ ],
    21               action='append',
    22               help='Additional directory to search for included protocol specifications')
    23 op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
    24               help='Verbose logging (specify -vv or -vvv for very verbose logging)')
    25 op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
    26               help="Suppress logging output")
    27 op.add_option('-d', '--outheaders-dir', dest='headersdir', default='.',
    28               help="""Directory into which C++ headers will be generated.
    29 A protocol Foo in the namespace bar will cause the headers
    30   dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
    31 to be generated""")
    32 op.add_option('-o', '--outcpp-dir', dest='cppdir', default='.',
    33               help="""Directory into which C++ sources will be generated
    34 A protocol Foo in the namespace bar will cause the sources
    35   cppdir/FooParent.cpp, cppdir/FooChild.cpp
    36 to be generated""")
    39 options, files = op.parse_args()
    40 _verbosity = options.verbosity
    41 headersdir = options.headersdir
    42 cppdir = options.cppdir
    43 includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
    45 if not len(files):
    46     op.error("No IPDL files specified")
    48 ipcmessagestartpath = os.path.join(headersdir, 'IPCMessageStart.h')
    50 # Compiling the IPDL files can take a long time, even on a fast machine.
    51 # Check to see whether we need to do any work.
    52 latestipdlmod = max(os.stat(f).st_mtime
    53                     for f in itertools.chain(files,
    54                                              iter_modules_in_path(mozpath.dirname(__file__))))
    56 def outputModTime(f):
    57     # A non-existant file is newer than everything.
    58     if not os.path.exists(f):
    59         return 0
    60     return os.stat(f).st_mtime
    62 # Because the IPDL headers are placed into directories reflecting their
    63 # namespace, collect a list here so we can easily map output names without
    64 # parsing the actual IPDL files themselves.
    65 headersmap = {}
    66 for (path, dirs, headers) in os.walk(headersdir):
    67     for h in headers:
    68         base = os.path.basename(h)
    69         if base in headersmap:
    70             root, ext = os.path.splitext(base)
    71             print >>sys.stderr, 'A protocol named', root, 'exists in multiple namespaces'
    72             sys.exit(1)
    73         headersmap[base] = os.path.join(path, h)
    75 def outputfiles(f):
    76     base = os.path.basename(f)
    77     root, ext = os.path.splitext(base)
    79     suffixes = ['']
    80     if ext == '.ipdl':
    81         suffixes += ['Child', 'Parent']
    83     for suffix in suffixes:
    84         yield os.path.join(cppdir, "%s%s.cpp" % (root, suffix))
    85         header = "%s%s.h" % (root, suffix)
    86         # If the header already exists on disk, use that.  Otherwise,
    87         # just claim that the header is found in headersdir.
    88         if header in headersmap:
    89             yield headersmap[header]
    90         else:
    91             yield os.path.join(headersdir, header)
    93 def alloutputfiles():
    94     for f in files:
    95         for s in outputfiles(f):
    96             yield s
    97     yield ipcmessagestartpath
    99 earliestoutputmod = min(outputModTime(f) for f in alloutputfiles())
   101 if latestipdlmod < earliestoutputmod:
   102     sys.exit(0)
   104 log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
   105 log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
   107 allprotocols = []
   109 def normalizedFilename(f):
   110     if f == '-':
   111         return '<stdin>'
   112     return f
   114 # First pass: parse and type-check all protocols
   115 for f in files:
   116     log(2, os.path.basename(f))
   117     filename = normalizedFilename(f)
   118     if f == '-':
   119         fd = sys.stdin
   120     else:
   121         fd = open(f)
   123     specstring = fd.read()
   124     fd.close()
   126     ast = ipdl.parse(specstring, filename, includedirs=includedirs)
   127     if ast is None:
   128         print >>sys.stderr, 'Specification could not be parsed.'
   129         sys.exit(1)
   131     log(2, 'checking types')
   132     if not ipdl.typecheck(ast):
   133         print >>sys.stderr, 'Specification is not well typed.'
   134         sys.exit(1)
   136     if _verbosity > 2:
   137         log(3, '  pretty printed code:')
   138         ipdl.genipdl(ast, codedir)
   140 # Second pass: generate code
   141 for f in files:
   142     # Read from parser cache
   143     filename = normalizedFilename(f)
   144     ast = ipdl.parse(None, filename, includedirs=includedirs)
   145     ipdl.gencxx(filename, ast, headersdir, cppdir)
   147     if ast.protocol:
   148         allprotocols.append('%sMsgStart' % ast.protocol.name)
   151 allprotocols.sort()
   153 ipcmsgstart = StringIO()
   155 print >>ipcmsgstart, """
   156 // CODE GENERATED by ipdl.py. Do not edit.
   158 #ifndef IPCMessageStart_h
   159 #define IPCMessageStart_h
   161 enum IPCMessageStart {
   162 """
   164 for name in allprotocols:
   165     print >>ipcmsgstart, "  %s," % name
   166     print >>ipcmsgstart, "  %sChild," % name
   168 print >>ipcmsgstart, """
   169   LastMsgIndex
   170 };
   172 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
   174 #endif // ifndef IPCMessageStart_h
   175 """
   177 ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)

mercurial