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/.
7 from configparser
import RawConfigParser
8 from io
import StringIO
11 from ipdl
.ast
import SYNC
14 def log(minv
, fmt
, *args
):
15 if _verbosity
>= minv
:
19 # process command line
22 op
= optparse
.OptionParser(usage
="ipdl.py [options] IPDLfiles...")
29 help="Additional directory to search for included protocol specifications",
35 default
="sync-messages.ini",
36 help="Config file listing allowed sync messages",
42 default
="message-metadata.ini",
43 help="Predicted message sizes for reducing serialization malloc overhead.",
51 help="Verbose logging (specify -vv or -vvv for very verbose logging)",
59 help="Suppress logging output",
66 help="""Directory into which C++ headers will be generated.
67 A protocol Foo in the namespace bar will cause the headers
68 dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
76 help="""Directory into which C++ sources will be generated
77 A protocol Foo in the namespace bar will cause the sources
78 cppdir/FooParent.cpp, cppdir/FooChild.cpp
84 dest
="file_list_file",
86 help="""A file containing IPDL files to parse. This will be
87 merged with files provided on the commandline.""",
90 options
, cmdline_files
= op
.parse_args()
91 _verbosity
= options
.verbosity
92 syncMsgList
= options
.syncMsgList
93 msgMetadata
= options
.msgMetadata
94 headersdir
= options
.headersdir
95 cppdir
= options
.cppdir
96 includedirs
= [os
.path
.abspath(incdir
) for incdir
in options
.includedirs
]
100 if options
.file_list_file
is not None:
101 with
open(options
.file_list_file
) as f
:
102 files
.extend(f
.read().splitlines())
104 files
.extend(cmdline_files
)
107 op
.error("No IPDL files specified")
109 ipcmessagestartpath
= os
.path
.join(headersdir
, "IPCMessageStart.h")
110 ipc_msgtype_name_path
= os
.path
.join(cppdir
, "IPCMessageTypeName.cpp")
112 log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir
)
113 log(2, 'Generated C++ sources will be generated in "%s"', cppdir
)
117 allmessageprognames
= []
121 def normalizedFilename(f
):
127 log(2, "Reading sync message list")
128 parser
= RawConfigParser()
129 parser
.read_file(open(options
.syncMsgList
))
130 syncMsgList
= parser
.sections()
132 for section
in syncMsgList
:
133 if not parser
.get(section
, "description"):
134 print("Error: Sync message %s lacks a description" % section
, file=sys
.stderr
)
137 # Read message metadata. Right now we only have 'segment_capacity'
138 # for the standard segment size used for serialization.
139 log(2, "Reading message metadata...")
140 msgMetadataConfig
= RawConfigParser()
141 msgMetadataConfig
.read_file(open(options
.msgMetadata
))
143 segmentCapacityDict
= {}
144 for msgName
in msgMetadataConfig
.sections():
145 if msgMetadataConfig
.has_option(msgName
, "segment_capacity"):
146 capacity
= msgMetadataConfig
.get(msgName
, "segment_capacity")
147 segmentCapacityDict
[msgName
] = capacity
149 # First pass: parse and type-check all protocols
151 log(2, os
.path
.basename(f
))
152 filename
= normalizedFilename(f
)
158 specstring
= fd
.read()
161 ast
= ipdl
.parse(specstring
, filename
, includedirs
=includedirs
)
163 print("Specification could not be parsed.", file=sys
.stderr
)
166 log(2, "checking types")
167 if not ipdl
.typecheck(ast
):
168 print("Specification is not well typed.", file=sys
.stderr
)
171 if not ipdl
.checkSyncMessage(ast
, syncMsgList
):
173 "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
174 % options
.syncMsgList
,
179 if not ipdl
.checkFixedSyncMessages(parser
):
180 # Errors have alraedy been printed to stderr, just exit
183 # Second pass: generate code
185 # Read from parser cache
186 filename
= normalizedFilename(f
)
187 ast
= ipdl
.parse(None, filename
, includedirs
=includedirs
)
188 ipdl
.gencxx(filename
, ast
, headersdir
, cppdir
, segmentCapacityDict
)
191 allmessages
[ast
.protocol
.name
] = ipdl
.genmsgenum(ast
)
192 allprotocols
.append(ast
.protocol
.name
)
194 # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
195 for md
in ast
.protocol
.messageDecls
:
196 allmessageprognames
.append("%s::%s" % (md
.namespace
, md
.decl
.progname
))
198 if md
.sendSemantics
is SYNC
:
199 allsyncmessages
.append(
200 "%s__%s" % (ast
.protocol
.name
, md
.prettyMsgName())
205 # Check if we have undefined message names in segmentCapacityDict.
206 # This is a fool-proof of the 'message-metadata.ini' file.
207 undefinedMessages
= set(segmentCapacityDict
.keys()) - set(allmessageprognames
)
208 if len(undefinedMessages
) > 0:
209 print("Error: Undefined message names in message-metadata.ini:", file=sys
.stderr
)
210 print(undefinedMessages
, file=sys
.stderr
)
213 ipcmsgstart
= StringIO()
217 // CODE GENERATED by ipdl.py. Do not edit.
219 #ifndef IPCMessageStart_h
220 #define IPCMessageStart_h
222 enum IPCMessageStart {
227 for name
in allprotocols
:
228 print(" %sMsgStart," % name
, file=ipcmsgstart
)
235 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
237 #endif // ifndef IPCMessageStart_h
242 ipc_msgtype_name
= StringIO()
245 // CODE GENERATED by ipdl.py. Do not edit.
248 #include "mozilla/ipc/ProtocolUtils.h"
249 #include "IPCMessageStart.h"
257 file=ipc_msgtype_name
,
260 for protocol
in sorted(allmessages
.keys()):
261 for msg
, num
in allmessages
[protocol
].idnums
:
263 print(" %s = %s," % (msg
, num
), file=ipc_msgtype_name
)
264 elif not msg
.endswith("End"):
265 print(" %s__%s," % (protocol
, msg
), file=ipc_msgtype_name
)
271 } // anonymous namespace
275 bool IPCMessageTypeIsSync(uint32_t aMessageType)
277 switch (aMessageType) {
279 file=ipc_msgtype_name
,
282 for msg
in allsyncmessages
:
283 print(" case %s:" % msg
, file=ipc_msgtype_name
)
292 const char* StringFromIPCMessageType(uint32_t aMessageType)
294 switch (aMessageType) {
296 file=ipc_msgtype_name
,
299 for protocol
in sorted(allmessages
.keys()):
300 for msg
, num
in allmessages
[protocol
].idnums
:
301 if num
or msg
.endswith("End"):
307 % (protocol
, msg
, protocol
, msg
),
308 file=ipc_msgtype_name
,
313 case DATA_PIPE_CLOSED_MESSAGE_TYPE:
314 return "DATA_PIPE_CLOSED_MESSAGE";
315 case DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE:
316 return "DATA_PIPE_BYTES_CONSUMED_MESSAGE";
317 case ACCEPT_INVITE_MESSAGE_TYPE:
318 return "ACCEPT_INVITE_MESSAGE";
319 case REQUEST_INTRODUCTION_MESSAGE_TYPE:
320 return "REQUEST_INTRODUCTION_MESSAGE";
321 case INTRODUCE_MESSAGE_TYPE:
322 return "INTRODUCE_MESSAGE";
323 case BROADCAST_MESSAGE_TYPE:
324 return "BROADCAST_MESSAGE";
325 case EVENT_MESSAGE_TYPE:
326 return "EVENT_MESSAGE";
327 case IMPENDING_SHUTDOWN_MESSAGE_TYPE:
328 return "IMPENDING_SHUTDOWN";
329 case BUILD_IDS_MATCH_MESSAGE_TYPE:
330 return "BUILD_IDS_MATCH_MESSAGE";
331 case BUILD_ID_MESSAGE_TYPE:
332 return "BUILD_ID_MESSAGE";
333 case CHANNEL_OPENED_MESSAGE_TYPE:
334 return "CHANNEL_OPENED_MESSAGE";
335 case SHMEM_DESTROYED_MESSAGE_TYPE:
336 return "SHMEM_DESTROYED_MESSAGE";
337 case SHMEM_CREATED_MESSAGE_TYPE:
338 return "SHMEM_CREATED_MESSAGE";
339 case GOODBYE_MESSAGE_TYPE:
340 return "GOODBYE_MESSAGE";
341 case CANCEL_MESSAGE_TYPE:
342 return "CANCEL_MESSAGE";
344 return "<unknown IPC msg name>";
353 const char* ProtocolIdToName(IPCMessageStart aId) {
356 file=ipc_msgtype_name
,
359 for name
in allprotocols
:
360 print(" case %sMsgStart:" % name
, file=ipc_msgtype_name
)
361 print(' return "%s";' % name
, file=ipc_msgtype_name
)
366 return "<unknown protocol id>";
371 } // namespace mozilla
373 file=ipc_msgtype_name
,
376 ipdl
.writeifmodified(ipcmsgstart
.getvalue(), ipcmessagestartpath
)
377 ipdl
.writeifmodified(ipc_msgtype_name
.getvalue(), ipc_msgtype_name_path
)