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
13 def log(minv
, fmt
, *args
):
14 if _verbosity
>= minv
:
18 # process command line
21 op
= optparse
.OptionParser(usage
="ipdl.py [options] IPDLfiles...")
28 help="Additional directory to search for included protocol specifications",
34 default
="sync-messages.ini",
35 help="Config file listing allowed sync messages",
41 default
="message-metadata.ini",
42 help="Predicted message sizes for reducing serialization malloc overhead.",
50 help="Verbose logging (specify -vv or -vvv for very verbose logging)",
58 help="Suppress logging output",
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
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
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
]
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
)
99 allmessageprognames
= []
103 def normalizedFilename(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
)
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
133 log(2, os
.path
.basename(f
))
134 filename
= normalizedFilename(f
)
140 specstring
= fd
.read()
143 ast
= ipdl
.parse(specstring
, filename
, includedirs
=includedirs
)
145 print("Specification could not be parsed.", file=sys
.stderr
)
148 log(2, "checking types")
149 if not ipdl
.typecheck(ast
):
150 print("Specification is not well typed.", file=sys
.stderr
)
153 if not ipdl
.checkSyncMessage(ast
, syncMsgList
):
155 "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
156 % options
.syncMsgList
,
161 if not ipdl
.checkFixedSyncMessages(parser
):
162 # Errors have alraedy been printed to stderr, just exit
165 # Second pass: generate code
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
)
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
))
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
)
189 ipcmsgstart
= StringIO()
193 // CODE GENERATED by ipdl.py. Do not edit.
195 #ifndef IPCMessageStart_h
196 #define IPCMessageStart_h
198 enum IPCMessageStart {
203 for name
in allprotocols
:
204 print(" %sMsgStart," % name
, file=ipcmsgstart
)
211 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
213 #endif // ifndef IPCMessageStart_h
218 ipc_msgtype_name
= StringIO()
221 // CODE GENERATED by ipdl.py. Do not edit.
224 #include "mozilla/ipc/ProtocolUtils.h"
225 #include "IPCMessageStart.h"
233 file=ipc_msgtype_name
,
236 for protocol
in sorted(allmessages
.keys()):
237 for msg
, num
in allmessages
[protocol
].idnums
:
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
)
247 } // anonymous namespace
251 const char* StringFromIPCMessageType(uint32_t aMessageType)
253 switch (aMessageType) {
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"):
266 % (protocol
, msg
, protocol
, msg
),
267 file=ipc_msgtype_name
,
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";
303 return "<unknown IPC msg name>";
312 const char* ProtocolIdToName(IPCMessageStart aId) {
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
)
325 return "<unknown protocol id>";
330 } // namespace mozilla
332 file=ipc_msgtype_name
,
335 ipdl
.writeifmodified(ipcmsgstart
.getvalue(), ipcmessagestartpath
)
336 ipdl
.writeifmodified(ipc_msgtype_name
.getvalue(), ipc_msgtype_name_path
)