Backed out changeset b858a0740582 (bug 1848694) for causing build bustages on dom...
[gecko.git] / ipc / ipdl / ipdl.py
blob230e0a213f7294e9b48b8fd33e5d9e66acc3d9a9
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 import optparse
5 import os
6 import sys
7 from configparser import RawConfigParser
8 from io import StringIO
10 import ipdl
13 def log(minv, fmt, *args):
14 if _verbosity >= minv:
15 print(fmt % args)
18 # process command line
21 op = optparse.OptionParser(usage="ipdl.py [options] IPDLfiles...")
22 op.add_option(
23 "-I",
24 "--include",
25 dest="includedirs",
26 default=[],
27 action="append",
28 help="Additional directory to search for included protocol specifications",
30 op.add_option(
31 "-s",
32 "--sync-msg-list",
33 dest="syncMsgList",
34 default="sync-messages.ini",
35 help="Config file listing allowed sync messages",
37 op.add_option(
38 "-m",
39 "--msg-metadata",
40 dest="msgMetadata",
41 default="message-metadata.ini",
42 help="Predicted message sizes for reducing serialization malloc overhead.",
44 op.add_option(
45 "-v",
46 "--verbose",
47 dest="verbosity",
48 default=1,
49 action="count",
50 help="Verbose logging (specify -vv or -vvv for very verbose logging)",
52 op.add_option(
53 "-q",
54 "--quiet",
55 dest="verbosity",
56 action="store_const",
57 const=0,
58 help="Suppress logging output",
60 op.add_option(
61 "-d",
62 "--outheaders-dir",
63 dest="headersdir",
64 default=".",
65 help="""Directory into which C++ headers will be generated.
66 A protocol Foo in the namespace bar will cause the headers
67 dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
68 to be generated""",
70 op.add_option(
71 "-o",
72 "--outcpp-dir",
73 dest="cppdir",
74 default=".",
75 help="""Directory into which C++ sources will be generated
76 A protocol Foo in the namespace bar will cause the sources
77 cppdir/FooParent.cpp, cppdir/FooChild.cpp
78 to be generated""",
81 options, files = op.parse_args()
82 _verbosity = options.verbosity
83 syncMsgList = options.syncMsgList
84 msgMetadata = options.msgMetadata
85 headersdir = options.headersdir
86 cppdir = options.cppdir
87 includedirs = [os.path.abspath(incdir) for incdir in options.includedirs]
89 if not len(files):
90 op.error("No IPDL files specified")
92 ipcmessagestartpath = os.path.join(headersdir, "IPCMessageStart.h")
93 ipc_msgtype_name_path = os.path.join(cppdir, "IPCMessageTypeName.cpp")
95 log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir)
96 log(2, 'Generated C++ sources will be generated in "%s"', cppdir)
98 allmessages = {}
99 allmessageprognames = []
100 allprotocols = []
103 def normalizedFilename(f):
104 if f == "-":
105 return "<stdin>"
106 return f
109 log(2, "Reading sync message list")
110 parser = RawConfigParser()
111 parser.read_file(open(options.syncMsgList))
112 syncMsgList = parser.sections()
114 for section in syncMsgList:
115 if not parser.get(section, "description"):
116 print("Error: Sync message %s lacks a description" % section, file=sys.stderr)
117 sys.exit(1)
119 # Read message metadata. Right now we only have 'segment_capacity'
120 # for the standard segment size used for serialization.
121 log(2, "Reading message metadata...")
122 msgMetadataConfig = RawConfigParser()
123 msgMetadataConfig.read_file(open(options.msgMetadata))
125 segmentCapacityDict = {}
126 for msgName in msgMetadataConfig.sections():
127 if msgMetadataConfig.has_option(msgName, "segment_capacity"):
128 capacity = msgMetadataConfig.get(msgName, "segment_capacity")
129 segmentCapacityDict[msgName] = capacity
131 # First pass: parse and type-check all protocols
132 for f in files:
133 log(2, os.path.basename(f))
134 filename = normalizedFilename(f)
135 if f == "-":
136 fd = sys.stdin
137 else:
138 fd = open(f)
140 specstring = fd.read()
141 fd.close()
143 ast = ipdl.parse(specstring, filename, includedirs=includedirs)
144 if ast is None:
145 print("Specification could not be parsed.", file=sys.stderr)
146 sys.exit(1)
148 log(2, "checking types")
149 if not ipdl.typecheck(ast):
150 print("Specification is not well typed.", file=sys.stderr)
151 sys.exit(1)
153 if not ipdl.checkSyncMessage(ast, syncMsgList):
154 print(
155 "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
156 % options.syncMsgList,
157 file=sys.stderr,
158 ) # NOQA: E501
159 sys.exit(1)
161 if not ipdl.checkFixedSyncMessages(parser):
162 # Errors have alraedy been printed to stderr, just exit
163 sys.exit(1)
165 # Second pass: generate code
166 for f in files:
167 # Read from parser cache
168 filename = normalizedFilename(f)
169 ast = ipdl.parse(None, filename, includedirs=includedirs)
170 ipdl.gencxx(filename, ast, headersdir, cppdir, segmentCapacityDict)
172 if ast.protocol:
173 allmessages[ast.protocol.name] = ipdl.genmsgenum(ast)
174 allprotocols.append(ast.protocol.name)
175 # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
176 for md in ast.protocol.messageDecls:
177 allmessageprognames.append("%s::%s" % (md.namespace, md.decl.progname))
179 allprotocols.sort()
181 # Check if we have undefined message names in segmentCapacityDict.
182 # This is a fool-proof of the 'message-metadata.ini' file.
183 undefinedMessages = set(segmentCapacityDict.keys()) - set(allmessageprognames)
184 if len(undefinedMessages) > 0:
185 print("Error: Undefined message names in message-metadata.ini:", file=sys.stderr)
186 print(undefinedMessages, file=sys.stderr)
187 sys.exit(1)
189 ipcmsgstart = StringIO()
191 print(
193 // CODE GENERATED by ipdl.py. Do not edit.
195 #ifndef IPCMessageStart_h
196 #define IPCMessageStart_h
198 enum IPCMessageStart {
199 """,
200 file=ipcmsgstart,
203 for name in allprotocols:
204 print(" %sMsgStart," % name, file=ipcmsgstart)
206 print(
208 LastMsgIndex
211 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
213 #endif // ifndef IPCMessageStart_h
214 """,
215 file=ipcmsgstart,
218 ipc_msgtype_name = StringIO()
219 print(
221 // CODE GENERATED by ipdl.py. Do not edit.
222 #include <cstdint>
224 #include "mozilla/ipc/ProtocolUtils.h"
225 #include "IPCMessageStart.h"
227 using std::uint32_t;
229 namespace {
231 enum IPCMessages {
232 """,
233 file=ipc_msgtype_name,
236 for protocol in sorted(allmessages.keys()):
237 for msg, num in allmessages[protocol].idnums:
238 if num:
239 print(" %s = %s," % (msg, num), file=ipc_msgtype_name)
240 elif not msg.endswith("End"):
241 print(" %s__%s," % (protocol, msg), file=ipc_msgtype_name)
243 print(
247 } // anonymous namespace
249 namespace IPC {
251 const char* StringFromIPCMessageType(uint32_t aMessageType)
253 switch (aMessageType) {
254 """,
255 file=ipc_msgtype_name,
258 for protocol in sorted(allmessages.keys()):
259 for msg, num in allmessages[protocol].idnums:
260 if num or msg.endswith("End"):
261 continue
262 print(
264 case %s__%s:
265 return "%s::%s";"""
266 % (protocol, msg, protocol, msg),
267 file=ipc_msgtype_name,
270 print(
272 case DATA_PIPE_CLOSED_MESSAGE_TYPE:
273 return "DATA_PIPE_CLOSED_MESSAGE";
274 case DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE:
275 return "DATA_PIPE_BYTES_CONSUMED_MESSAGE";
276 case ACCEPT_INVITE_MESSAGE_TYPE:
277 return "ACCEPT_INVITE_MESSAGE";
278 case REQUEST_INTRODUCTION_MESSAGE_TYPE:
279 return "REQUEST_INTRODUCTION_MESSAGE";
280 case INTRODUCE_MESSAGE_TYPE:
281 return "INTRODUCE_MESSAGE";
282 case BROADCAST_MESSAGE_TYPE:
283 return "BROADCAST_MESSAGE";
284 case EVENT_MESSAGE_TYPE:
285 return "EVENT_MESSAGE";
286 case IMPENDING_SHUTDOWN_MESSAGE_TYPE:
287 return "IMPENDING_SHUTDOWN";
288 case BUILD_IDS_MATCH_MESSAGE_TYPE:
289 return "BUILD_IDS_MATCH_MESSAGE";
290 case BUILD_ID_MESSAGE_TYPE:
291 return "BUILD_ID_MESSAGE";
292 case CHANNEL_OPENED_MESSAGE_TYPE:
293 return "CHANNEL_OPENED_MESSAGE";
294 case SHMEM_DESTROYED_MESSAGE_TYPE:
295 return "SHMEM_DESTROYED_MESSAGE";
296 case SHMEM_CREATED_MESSAGE_TYPE:
297 return "SHMEM_CREATED_MESSAGE";
298 case GOODBYE_MESSAGE_TYPE:
299 return "GOODBYE_MESSAGE";
300 case CANCEL_MESSAGE_TYPE:
301 return "CANCEL_MESSAGE";
302 default:
303 return "<unknown IPC msg name>";
307 } // namespace IPC
309 namespace mozilla {
310 namespace ipc {
312 const char* ProtocolIdToName(IPCMessageStart aId) {
313 switch (aId) {
314 """,
315 file=ipc_msgtype_name,
318 for name in allprotocols:
319 print(" case %sMsgStart:" % name, file=ipc_msgtype_name)
320 print(' return "%s";' % name, file=ipc_msgtype_name)
322 print(
324 default:
325 return "<unknown protocol id>";
329 } // namespace ipc
330 } // namespace mozilla
331 """,
332 file=ipc_msgtype_name,
335 ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
336 ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)