1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/ipdl/ipdl.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,177 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +import optparse, os, re, sys 1.9 +from cStringIO import StringIO 1.10 +from mozbuild.pythonutil import iter_modules_in_path 1.11 +import mozpack.path as mozpath 1.12 +import itertools 1.13 + 1.14 +import ipdl 1.15 + 1.16 +def log(minv, fmt, *args): 1.17 + if _verbosity >= minv: 1.18 + print fmt % args 1.19 + 1.20 +# process command line 1.21 + 1.22 +op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...') 1.23 +op.add_option('-I', '--include', dest='includedirs', default=[ ], 1.24 + action='append', 1.25 + help='Additional directory to search for included protocol specifications') 1.26 +op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count', 1.27 + help='Verbose logging (specify -vv or -vvv for very verbose logging)') 1.28 +op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0, 1.29 + help="Suppress logging output") 1.30 +op.add_option('-d', '--outheaders-dir', dest='headersdir', default='.', 1.31 + help="""Directory into which C++ headers will be generated. 1.32 +A protocol Foo in the namespace bar will cause the headers 1.33 + dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h 1.34 +to be generated""") 1.35 +op.add_option('-o', '--outcpp-dir', dest='cppdir', default='.', 1.36 + help="""Directory into which C++ sources will be generated 1.37 +A protocol Foo in the namespace bar will cause the sources 1.38 + cppdir/FooParent.cpp, cppdir/FooChild.cpp 1.39 +to be generated""") 1.40 + 1.41 + 1.42 +options, files = op.parse_args() 1.43 +_verbosity = options.verbosity 1.44 +headersdir = options.headersdir 1.45 +cppdir = options.cppdir 1.46 +includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ] 1.47 + 1.48 +if not len(files): 1.49 + op.error("No IPDL files specified") 1.50 + 1.51 +ipcmessagestartpath = os.path.join(headersdir, 'IPCMessageStart.h') 1.52 + 1.53 +# Compiling the IPDL files can take a long time, even on a fast machine. 1.54 +# Check to see whether we need to do any work. 1.55 +latestipdlmod = max(os.stat(f).st_mtime 1.56 + for f in itertools.chain(files, 1.57 + iter_modules_in_path(mozpath.dirname(__file__)))) 1.58 + 1.59 +def outputModTime(f): 1.60 + # A non-existant file is newer than everything. 1.61 + if not os.path.exists(f): 1.62 + return 0 1.63 + return os.stat(f).st_mtime 1.64 + 1.65 +# Because the IPDL headers are placed into directories reflecting their 1.66 +# namespace, collect a list here so we can easily map output names without 1.67 +# parsing the actual IPDL files themselves. 1.68 +headersmap = {} 1.69 +for (path, dirs, headers) in os.walk(headersdir): 1.70 + for h in headers: 1.71 + base = os.path.basename(h) 1.72 + if base in headersmap: 1.73 + root, ext = os.path.splitext(base) 1.74 + print >>sys.stderr, 'A protocol named', root, 'exists in multiple namespaces' 1.75 + sys.exit(1) 1.76 + headersmap[base] = os.path.join(path, h) 1.77 + 1.78 +def outputfiles(f): 1.79 + base = os.path.basename(f) 1.80 + root, ext = os.path.splitext(base) 1.81 + 1.82 + suffixes = [''] 1.83 + if ext == '.ipdl': 1.84 + suffixes += ['Child', 'Parent'] 1.85 + 1.86 + for suffix in suffixes: 1.87 + yield os.path.join(cppdir, "%s%s.cpp" % (root, suffix)) 1.88 + header = "%s%s.h" % (root, suffix) 1.89 + # If the header already exists on disk, use that. Otherwise, 1.90 + # just claim that the header is found in headersdir. 1.91 + if header in headersmap: 1.92 + yield headersmap[header] 1.93 + else: 1.94 + yield os.path.join(headersdir, header) 1.95 + 1.96 +def alloutputfiles(): 1.97 + for f in files: 1.98 + for s in outputfiles(f): 1.99 + yield s 1.100 + yield ipcmessagestartpath 1.101 + 1.102 +earliestoutputmod = min(outputModTime(f) for f in alloutputfiles()) 1.103 + 1.104 +if latestipdlmod < earliestoutputmod: 1.105 + sys.exit(0) 1.106 + 1.107 +log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir) 1.108 +log(2, 'Generated C++ sources will be generated in "%s"', cppdir) 1.109 + 1.110 +allprotocols = [] 1.111 + 1.112 +def normalizedFilename(f): 1.113 + if f == '-': 1.114 + return '<stdin>' 1.115 + return f 1.116 + 1.117 +# First pass: parse and type-check all protocols 1.118 +for f in files: 1.119 + log(2, os.path.basename(f)) 1.120 + filename = normalizedFilename(f) 1.121 + if f == '-': 1.122 + fd = sys.stdin 1.123 + else: 1.124 + fd = open(f) 1.125 + 1.126 + specstring = fd.read() 1.127 + fd.close() 1.128 + 1.129 + ast = ipdl.parse(specstring, filename, includedirs=includedirs) 1.130 + if ast is None: 1.131 + print >>sys.stderr, 'Specification could not be parsed.' 1.132 + sys.exit(1) 1.133 + 1.134 + log(2, 'checking types') 1.135 + if not ipdl.typecheck(ast): 1.136 + print >>sys.stderr, 'Specification is not well typed.' 1.137 + sys.exit(1) 1.138 + 1.139 + if _verbosity > 2: 1.140 + log(3, ' pretty printed code:') 1.141 + ipdl.genipdl(ast, codedir) 1.142 + 1.143 +# Second pass: generate code 1.144 +for f in files: 1.145 + # Read from parser cache 1.146 + filename = normalizedFilename(f) 1.147 + ast = ipdl.parse(None, filename, includedirs=includedirs) 1.148 + ipdl.gencxx(filename, ast, headersdir, cppdir) 1.149 + 1.150 + if ast.protocol: 1.151 + allprotocols.append('%sMsgStart' % ast.protocol.name) 1.152 + 1.153 + 1.154 +allprotocols.sort() 1.155 + 1.156 +ipcmsgstart = StringIO() 1.157 + 1.158 +print >>ipcmsgstart, """ 1.159 +// CODE GENERATED by ipdl.py. Do not edit. 1.160 + 1.161 +#ifndef IPCMessageStart_h 1.162 +#define IPCMessageStart_h 1.163 + 1.164 +enum IPCMessageStart { 1.165 +""" 1.166 + 1.167 +for name in allprotocols: 1.168 + print >>ipcmsgstart, " %s," % name 1.169 + print >>ipcmsgstart, " %sChild," % name 1.170 + 1.171 +print >>ipcmsgstart, """ 1.172 + LastMsgIndex 1.173 +}; 1.174 + 1.175 +static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO"); 1.176 + 1.177 +#endif // ifndef IPCMessageStart_h 1.178 +""" 1.179 + 1.180 +ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)