Bug 1613457 [wpt PR 21606] - Update interfaces/cookie-store.idl, a=testonly
[gecko.git] / ipc / ipdl / ipdl.py
blobaacd90c3398f8a234c29220866ec0a56948ba7d8
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/.
4 from __future__ import print_function
6 import optparse
7 import os
8 import sys
9 from cStringIO import StringIO
10 from ConfigParser import RawConfigParser
12 import ipdl
15 def log(minv, fmt, *args):
16 if _verbosity >= minv:
17 print(fmt % args)
19 # process command line
22 op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
23 op.add_option('-I', '--include', dest='includedirs', default=[],
24 action='append',
25 help='Additional directory to search for included protocol specifications')
26 op.add_option('-s', '--sync-msg-list', dest='syncMsgList', default='sync-messages.ini',
27 help="Config file listing allowed sync messages")
28 op.add_option('-m', '--msg-metadata', dest='msgMetadata', default='message-metadata.ini',
29 help="Predicted message sizes for reducing serialization malloc overhead.")
30 op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
31 help='Verbose logging (specify -vv or -vvv for very verbose logging)')
32 op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
33 help="Suppress logging output")
34 op.add_option('-d', '--outheaders-dir', dest='headersdir', default='.',
35 help="""Directory into which C++ headers will be generated.
36 A protocol Foo in the namespace bar will cause the headers
37 dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
38 to be generated""")
39 op.add_option('-o', '--outcpp-dir', dest='cppdir', default='.',
40 help="""Directory into which C++ sources will be generated
41 A protocol Foo in the namespace bar will cause the sources
42 cppdir/FooParent.cpp, cppdir/FooChild.cpp
43 to be generated""")
45 options, files = op.parse_args()
46 _verbosity = options.verbosity
47 syncMsgList = options.syncMsgList
48 msgMetadata = options.msgMetadata
49 headersdir = options.headersdir
50 cppdir = options.cppdir
51 includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
53 if not len(files):
54 op.error("No IPDL files specified")
56 ipcmessagestartpath = os.path.join(headersdir, 'IPCMessageStart.h')
57 ipc_msgtype_name_path = os.path.join(cppdir, 'IPCMessageTypeName.cpp')
59 log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
60 log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
62 allmessages = {}
63 allmessageprognames = []
64 allprotocols = []
67 def normalizedFilename(f):
68 if f == '-':
69 return '<stdin>'
70 return f
73 log(2, 'Reading sync message list')
74 parser = RawConfigParser()
75 parser.readfp(open(options.syncMsgList))
76 syncMsgList = parser.sections()
78 for section in syncMsgList:
79 if not parser.get(section, "description"):
80 print('Error: Sync message %s lacks a description' % section, file=sys.stderr)
81 sys.exit(1)
83 # Read message metadata. Right now we only have 'segment_capacity'
84 # for the standard segment size used for serialization.
85 log(2, 'Reading message metadata...')
86 msgMetadataConfig = RawConfigParser()
87 msgMetadataConfig.readfp(open(options.msgMetadata))
89 segmentCapacityDict = {}
90 for msgName in msgMetadataConfig.sections():
91 if msgMetadataConfig.has_option(msgName, 'segment_capacity'):
92 capacity = msgMetadataConfig.get(msgName, 'segment_capacity')
93 segmentCapacityDict[msgName] = capacity
95 # First pass: parse and type-check all protocols
96 for f in files:
97 log(2, os.path.basename(f))
98 filename = normalizedFilename(f)
99 if f == '-':
100 fd = sys.stdin
101 else:
102 fd = open(f)
104 specstring = fd.read()
105 fd.close()
107 ast = ipdl.parse(specstring, filename, includedirs=includedirs)
108 if ast is None:
109 print('Specification could not be parsed.', file=sys.stderr)
110 sys.exit(1)
112 log(2, 'checking types')
113 if not ipdl.typecheck(ast):
114 print('Specification is not well typed.', file=sys.stderr)
115 sys.exit(1)
117 if not ipdl.checkSyncMessage(ast, syncMsgList):
118 print('Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s' % options.syncMsgList, file=sys.stderr) # NOQA: E501
119 sys.exit(1)
121 if not ipdl.checkFixedSyncMessages(parser):
122 # Errors have alraedy been printed to stderr, just exit
123 sys.exit(1)
125 # Second pass: generate code
126 for f in files:
127 # Read from parser cache
128 filename = normalizedFilename(f)
129 ast = ipdl.parse(None, filename, includedirs=includedirs)
130 ipdl.gencxx(filename, ast, headersdir, cppdir, segmentCapacityDict)
132 if ast.protocol:
133 allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
134 allprotocols.append(ast.protocol.name)
135 # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
136 for md in ast.protocol.messageDecls:
137 allmessageprognames.append('%s::%s' % (md.namespace, md.decl.progname))
139 allprotocols.sort()
141 # Check if we have undefined message names in segmentCapacityDict.
142 # This is a fool-proof of the 'message-metadata.ini' file.
143 undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
144 if len(undefinedMessages) > 0:
145 print('Error: Undefined message names in message-metadata.ini:', file=sys.stderr)
146 print(undefinedMessages, file=sys.stderr)
147 sys.exit(1)
149 ipcmsgstart = StringIO()
151 print("""
152 // CODE GENERATED by ipdl.py. Do not edit.
154 #ifndef IPCMessageStart_h
155 #define IPCMessageStart_h
157 enum IPCMessageStart {
158 """, file=ipcmsgstart)
160 for name in allprotocols:
161 print(" %sMsgStart," % name, file=ipcmsgstart)
163 print("""
164 LastMsgIndex
167 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
169 #endif // ifndef IPCMessageStart_h
170 """, file=ipcmsgstart)
172 ipc_msgtype_name = StringIO()
173 print("""
174 // CODE GENERATED by ipdl.py. Do not edit.
175 #include <cstdint>
177 #include "mozilla/ipc/ProtocolUtils.h"
178 #include "IPCMessageStart.h"
180 using std::uint32_t;
182 namespace {
184 enum IPCMessages {
185 """, file=ipc_msgtype_name)
187 for protocol in sorted(allmessages.keys()):
188 for (msg, num) in allmessages[protocol].idnums:
189 if num:
190 print(" %s = %s," % (msg, num), file=ipc_msgtype_name)
191 elif not msg.endswith('End'):
192 print(" %s__%s," % (protocol, msg), file=ipc_msgtype_name)
194 print("""
197 } // anonymous namespace
199 namespace IPC {
201 const char* StringFromIPCMessageType(uint32_t aMessageType)
203 switch (aMessageType) {
204 """, file=ipc_msgtype_name)
206 for protocol in sorted(allmessages.keys()):
207 for (msg, num) in allmessages[protocol].idnums:
208 if num or msg.endswith('End'):
209 continue
210 print("""
211 case %s__%s:
212 return "%s::%s";""" % (protocol, msg, protocol, msg), file=ipc_msgtype_name)
214 print("""
215 case CHANNEL_OPENED_MESSAGE_TYPE:
216 return "CHANNEL_OPENED_MESSAGE";
217 case SHMEM_DESTROYED_MESSAGE_TYPE:
218 return "SHMEM_DESTROYED_MESSAGE";
219 case SHMEM_CREATED_MESSAGE_TYPE:
220 return "SHMEM_CREATED_MESSAGE";
221 case GOODBYE_MESSAGE_TYPE:
222 return "GOODBYE_MESSAGE";
223 case CANCEL_MESSAGE_TYPE:
224 return "CANCEL_MESSAGE";
225 default:
226 return "<unknown IPC msg name>";
230 } // namespace IPC
232 namespace mozilla {
233 namespace ipc {
235 const char* ProtocolIdToName(IPCMessageStart aId) {
236 switch (aId) {
237 """, file=ipc_msgtype_name)
239 for name in allprotocols:
240 print(" case %sMsgStart:" % name, file=ipc_msgtype_name)
241 print(" return \"%s\";" % name, file=ipc_msgtype_name)
243 print("""
244 default:
245 return "<unknown protocol id>";
249 } // namespace ipc
250 } // namespace mozilla
251 """, file=ipc_msgtype_name)
253 ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
254 ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)