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 from io
import StringIO
10 from configparser
import RawConfigParser
15 def log(minv
, fmt
, *args
):
16 if _verbosity
>= minv
:
20 # process command line
23 op
= optparse
.OptionParser(usage
="ipdl.py [options] IPDLfiles...")
30 help="Additional directory to search for included protocol specifications",
36 default
="sync-messages.ini",
37 help="Config file listing allowed sync messages",
43 default
="message-metadata.ini",
44 help="Predicted message sizes for reducing serialization malloc overhead.",
52 help="Verbose logging (specify -vv or -vvv for very verbose logging)",
60 help="Suppress logging output",
67 help="""Directory into which C++ headers will be generated.
68 A protocol Foo in the namespace bar will cause the headers
69 dir/bar/Foo.h, dir/bar/FooParent.h, and dir/bar/FooParent.h
77 help="""Directory into which C++ sources will be generated
78 A protocol Foo in the namespace bar will cause the sources
79 cppdir/FooParent.cpp, cppdir/FooChild.cpp
83 options
, files
= op
.parse_args()
84 _verbosity
= options
.verbosity
85 syncMsgList
= options
.syncMsgList
86 msgMetadata
= options
.msgMetadata
87 headersdir
= options
.headersdir
88 cppdir
= options
.cppdir
89 includedirs
= [os
.path
.abspath(incdir
) for incdir
in options
.includedirs
]
92 op
.error("No IPDL files specified")
94 ipcmessagestartpath
= os
.path
.join(headersdir
, "IPCMessageStart.h")
95 ipc_msgtype_name_path
= os
.path
.join(cppdir
, "IPCMessageTypeName.cpp")
97 log(2, 'Generated C++ headers will be generated relative to "%s"', headersdir
)
98 log(2, 'Generated C++ sources will be generated in "%s"', cppdir
)
101 allmessageprognames
= []
105 def normalizedFilename(f
):
111 log(2, "Reading sync message list")
112 parser
= RawConfigParser()
113 parser
.read_file(open(options
.syncMsgList
))
114 syncMsgList
= parser
.sections()
116 for section
in syncMsgList
:
117 if not parser
.get(section
, "description"):
118 print("Error: Sync message %s lacks a description" % section
, file=sys
.stderr
)
121 # Read message metadata. Right now we only have 'segment_capacity'
122 # for the standard segment size used for serialization.
123 log(2, "Reading message metadata...")
124 msgMetadataConfig
= RawConfigParser()
125 msgMetadataConfig
.read_file(open(options
.msgMetadata
))
127 segmentCapacityDict
= {}
128 for msgName
in msgMetadataConfig
.sections():
129 if msgMetadataConfig
.has_option(msgName
, "segment_capacity"):
130 capacity
= msgMetadataConfig
.get(msgName
, "segment_capacity")
131 segmentCapacityDict
[msgName
] = capacity
133 # First pass: parse and type-check all protocols
135 log(2, os
.path
.basename(f
))
136 filename
= normalizedFilename(f
)
142 specstring
= fd
.read()
145 ast
= ipdl
.parse(specstring
, filename
, includedirs
=includedirs
)
147 print("Specification could not be parsed.", file=sys
.stderr
)
150 log(2, "checking types")
151 if not ipdl
.typecheck(ast
):
152 print("Specification is not well typed.", file=sys
.stderr
)
155 if not ipdl
.checkSyncMessage(ast
, syncMsgList
):
157 "Error: New sync IPC messages must be reviewed by an IPC peer and recorded in %s"
158 % options
.syncMsgList
,
163 if not ipdl
.checkFixedSyncMessages(parser
):
164 # Errors have alraedy been printed to stderr, just exit
167 # Second pass: generate code
169 # Read from parser cache
170 filename
= normalizedFilename(f
)
171 ast
= ipdl
.parse(None, filename
, includedirs
=includedirs
)
172 ipdl
.gencxx(filename
, ast
, headersdir
, cppdir
, segmentCapacityDict
)
175 allmessages
[ast
.protocol
.name
] = ipdl
.genmsgenum(ast
)
176 allprotocols
.append(ast
.protocol
.name
)
177 # e.g. PContent::RequestMemoryReport (not prefixed or suffixed.)
178 for md
in ast
.protocol
.messageDecls
:
179 allmessageprognames
.append("%s::%s" % (md
.namespace
, md
.decl
.progname
))
183 # Check if we have undefined message names in segmentCapacityDict.
184 # This is a fool-proof of the 'message-metadata.ini' file.
185 undefinedMessages
= set(segmentCapacityDict
.keys()) - set(allmessageprognames
)
186 if len(undefinedMessages
) > 0:
187 print("Error: Undefined message names in message-metadata.ini:", file=sys
.stderr
)
188 print(undefinedMessages
, file=sys
.stderr
)
191 ipcmsgstart
= StringIO()
195 // CODE GENERATED by ipdl.py. Do not edit.
197 #ifndef IPCMessageStart_h
198 #define IPCMessageStart_h
200 enum IPCMessageStart {
205 for name
in allprotocols
:
206 print(" %sMsgStart," % name
, file=ipcmsgstart
)
213 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
215 #endif // ifndef IPCMessageStart_h
220 ipc_msgtype_name
= StringIO()
223 // CODE GENERATED by ipdl.py. Do not edit.
226 #include "mozilla/ipc/ProtocolUtils.h"
227 #include "IPCMessageStart.h"
235 file=ipc_msgtype_name
,
238 for protocol
in sorted(allmessages
.keys()):
239 for (msg
, num
) in allmessages
[protocol
].idnums
:
241 print(" %s = %s," % (msg
, num
), file=ipc_msgtype_name
)
242 elif not msg
.endswith("End"):
243 print(" %s__%s," % (protocol
, msg
), file=ipc_msgtype_name
)
249 } // anonymous namespace
253 const char* StringFromIPCMessageType(uint32_t aMessageType)
255 switch (aMessageType) {
257 file=ipc_msgtype_name
,
260 for protocol
in sorted(allmessages
.keys()):
261 for (msg
, num
) in allmessages
[protocol
].idnums
:
262 if num
or msg
.endswith("End"):
268 % (protocol
, msg
, protocol
, msg
),
269 file=ipc_msgtype_name
,
274 case DATA_PIPE_CLOSED_MESSAGE_TYPE:
275 return "DATA_PIPE_CLOSED_MESSAGE";
276 case DATA_PIPE_BYTES_CONSUMED_MESSAGE_TYPE:
277 return "DATA_PIPE_BYTES_CONSUMED_MESSAGE";
278 case ACCEPT_INVITE_MESSAGE_TYPE:
279 return "ACCEPT_INVITE_MESSAGE";
280 case REQUEST_INTRODUCTION_MESSAGE_TYPE:
281 return "REQUEST_INTRODUCTION_MESSAGE";
282 case INTRODUCE_MESSAGE_TYPE:
283 return "INTRODUCE_MESSAGE";
284 case BROADCAST_MESSAGE_TYPE:
285 return "BROADCAST_MESSAGE";
286 case EVENT_MESSAGE_TYPE:
287 return "EVENT_MESSAGE";
288 case IMPENDING_SHUTDOWN_MESSAGE_TYPE:
289 return "IMPENDING_SHUTDOWN";
290 case BUILD_IDS_MATCH_MESSAGE_TYPE:
291 return "BUILD_IDS_MATCH_MESSAGE";
292 case BUILD_ID_MESSAGE_TYPE:
293 return "BUILD_ID_MESSAGE";
294 case CHANNEL_OPENED_MESSAGE_TYPE:
295 return "CHANNEL_OPENED_MESSAGE";
296 case SHMEM_DESTROYED_MESSAGE_TYPE:
297 return "SHMEM_DESTROYED_MESSAGE";
298 case SHMEM_CREATED_MESSAGE_TYPE:
299 return "SHMEM_CREATED_MESSAGE";
300 case GOODBYE_MESSAGE_TYPE:
301 return "GOODBYE_MESSAGE";
302 case CANCEL_MESSAGE_TYPE:
303 return "CANCEL_MESSAGE";
305 return "<unknown IPC msg name>";
314 const char* ProtocolIdToName(IPCMessageStart aId) {
317 file=ipc_msgtype_name
,
320 for name
in allprotocols
:
321 print(" case %sMsgStart:" % name
, file=ipc_msgtype_name
)
322 print(' return "%s";' % name
, file=ipc_msgtype_name
)
327 return "<unknown protocol id>";
332 } // namespace mozilla
334 file=ipc_msgtype_name
,
337 ipdl
.writeifmodified(ipcmsgstart
.getvalue(), ipcmessagestartpath
)
338 ipdl
.writeifmodified(ipc_msgtype_name
.getvalue(), ipc_msgtype_name_path
)