Add C++ API
[vpp.git] / src / vpp-api / vapi / vapi_c_gen.py
1 #!/usr/bin/env python3
2
3 import argparse
4 import os
5 import sys
6 import logging
7 from vapi_json_parser import Field, Struct, Message, JsonParser,\
8     SimpleType, StructType
9
10
11 class CField(Field):
12     def __init__(
13             self,
14             field_name,
15             field_type,
16             array_len=None,
17             nelem_field=None):
18         super().__init__(field_name, field_type, array_len, nelem_field)
19
20     def get_c_def(self):
21         if self.len is not None:
22             return "%s %s[%d]" % (self.type.get_c_name(), self.name, self.len)
23         else:
24             return "%s %s" % (self.type.get_c_name(), self.name)
25
26     def get_swap_to_be_code(self, struct, var):
27         if self.len is not None:
28             if self.len > 0:
29                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
30                     " while(0);" % (
31                         self.len,
32                         self.type.get_swap_to_be_code(struct, "%s[i]" % var))
33             else:
34                 if self.nelem_field.needs_byte_swap():
35                     nelem_field = "%s(%s%s)" % (
36                         self.nelem_field.type.get_swap_to_host_func_name(),
37                         struct, self.nelem_field.name)
38                 else:
39                     nelem_field = "%s%s" % (struct, self.nelem_field.name)
40                 return (
41                     "do { unsigned i; for (i = 0; i < %s; ++i) { %s } }"
42                     " while(0);" %
43                     (nelem_field, self.type.get_swap_to_be_code(
44                         struct, "%s[i]" % var)))
45         return self.type.get_swap_to_be_code(struct, "%s" % var)
46
47     def get_swap_to_host_code(self, struct, var):
48         if self.len is not None:
49             if self.len > 0:
50                 return "do { unsigned i; for (i = 0; i < %d; ++i) { %s } }"\
51                     " while(0);" % (
52                         self.len,
53                         self.type.get_swap_to_host_code(struct, "%s[i]" % var))
54             else:
55                 # nelem_field already swapped to host here...
56                 return (
57                     "do { unsigned i; for (i = 0; i < %s%s; ++i) { %s } }"
58                     " while(0);" %
59                     (struct, self.nelem_field.name,
60                      self.type.get_swap_to_host_code(
61                          struct, "%s[i]" % var)))
62         return self.type.get_swap_to_host_code(struct, "%s" % var)
63
64     def needs_byte_swap(self):
65         return self.type.needs_byte_swap()
66
67
68 class CStruct(Struct):
69     def __init__(self, name, fields):
70         super().__init__(name, fields)
71
72     def get_c_def(self):
73         return "\n".join([
74             "typedef struct __attribute__((__packed__)) {",
75             "%s;" % ";\n".join(["  %s" % x.get_c_def()
76                                 for x in self.fields]),
77             "} %s;" % self.get_c_name()])
78
79
80 class CSimpleType (SimpleType):
81
82     swap_to_be_dict = {
83         'i16': 'htobe16', 'u16': 'htobe16',
84         'i32': 'htobe32', 'u32': 'htobe32',
85         'i64': 'htobe64', 'u64': 'htobe64',
86     }
87
88     swap_to_host_dict = {
89         'i16': 'be16toh', 'u16': 'be16toh',
90         'i32': 'be32toh', 'u32': 'be32toh',
91         'i64': 'be64toh', 'u64': 'be64toh',
92     }
93
94     def __init__(self, name):
95         super().__init__(name)
96
97     def get_c_name(self):
98         return self.name
99
100     def get_swap_to_be_func_name(self):
101         return self.swap_to_be_dict[self.name]
102
103     def get_swap_to_host_func_name(self):
104         return self.swap_to_host_dict[self.name]
105
106     def get_swap_to_be_code(self, struct, var):
107         x = "%s%s" % (struct, var)
108         return "%s = %s(%s);" % (x, self.get_swap_to_be_func_name(), x)
109
110     def get_swap_to_host_code(self, struct, var):
111         x = "%s%s" % (struct, var)
112         return "%s = %s(%s);" % (x, self.get_swap_to_host_func_name(), x)
113
114     def needs_byte_swap(self):
115         try:
116             self.get_swap_to_host_func_name()
117             return True
118         except:
119             pass
120         return False
121
122
123 class CStructType (StructType, CStruct):
124     def __init__(self, definition, typedict, field_class):
125         super().__init__(definition, typedict, field_class)
126
127     def get_c_name(self):
128         return "vapi_type_%s" % self.name
129
130     def get_swap_to_be_func_name(self):
131         return "%s_hton" % self.get_c_name()
132
133     def get_swap_to_host_func_name(self):
134         return "%s_ntoh" % self.get_c_name()
135
136     def get_swap_to_be_func_decl(self):
137         return "void %s(%s *msg)" % (
138             self.get_swap_to_be_func_name(), self.get_c_name())
139
140     def get_swap_to_be_func_def(self):
141         return "%s\n{\n%s\n}" % (
142             self.get_swap_to_be_func_decl(),
143             "\n".join([
144                 "  %s" % p.get_swap_to_be_code("msg->", "%s" % p.name)
145                 for p in self.fields if p.needs_byte_swap()]),
146         )
147
148     def get_swap_to_host_func_decl(self):
149         return "void %s(%s *msg)" % (
150             self.get_swap_to_host_func_name(), self.get_c_name())
151
152     def get_swap_to_host_func_def(self):
153         return "%s\n{\n%s\n}" % (
154             self.get_swap_to_host_func_decl(),
155             "\n".join([
156                 "  %s" % p.get_swap_to_host_code("msg->", "%s" % p.name)
157                 for p in self.fields if p.needs_byte_swap()]),
158         )
159
160     def get_swap_to_be_code(self, struct, var):
161         return "%s(&%s%s);" % (self.get_swap_to_be_func_name(), struct, var)
162
163     def get_swap_to_host_code(self, struct, var):
164         return "%s(&%s%s);" % (self.get_swap_to_host_func_name(), struct, var)
165
166     def needs_byte_swap(self):
167         for f in self.fields:
168             if f.needs_byte_swap():
169                 return True
170         return False
171
172
173 class CMessage (Message):
174     def __init__(self, logger, definition, typedict,
175                  struct_type_class, simple_type_class, field_class):
176         super().__init__(logger, definition, typedict, struct_type_class,
177                          simple_type_class, field_class)
178         self.payload_members = [
179             "  %s" % p.get_c_def()
180             for p in self.fields
181             if p.type != self.header
182         ]
183
184     def has_payload(self):
185         return len(self.payload_members) > 0
186
187     def get_msg_id_name(self):
188         return "vapi_msg_id_%s" % self.name
189
190     def get_c_name(self):
191         return "vapi_msg_%s" % self.name
192
193     def get_payload_struct_name(self):
194         return "vapi_payload_%s" % self.name
195
196     def get_alloc_func_vla_field_length_name(self, field):
197         return "%s_array_size" % field.name
198
199     def get_alloc_func_name(self):
200         return "vapi_alloc_%s" % self.name
201
202     def get_alloc_vla_param_names(self):
203         return [self.get_alloc_func_vla_field_length_name(f)
204                 for f in self.fields
205                 if f.nelem_field is not None]
206
207     def get_alloc_func_decl(self):
208         return "%s* %s(struct vapi_ctx_s *ctx%s)" % (
209             self.get_c_name(),
210             self.get_alloc_func_name(),
211             "".join([", size_t %s" % n for n in
212                      self.get_alloc_vla_param_names()]))
213
214     def get_alloc_func_def(self):
215         extra = []
216         if self.header.has_field('client_index'):
217             extra.append(
218                 "  msg->header.client_index = vapi_get_client_index(ctx);")
219         if self.header.has_field('context'):
220             extra.append("  msg->header.context = 0;")
221         return "\n".join([
222             "%s" % self.get_alloc_func_decl(),
223             "{",
224             "  %s *msg = NULL;" % self.get_c_name(),
225             "  const size_t size = sizeof(%s)%s;" % (
226                 self.get_c_name(),
227                 "".join([
228                     " + sizeof(msg->payload.%s[0]) * %s" % (
229                         f.name,
230                         self.get_alloc_func_vla_field_length_name(f))
231                     for f in self.fields
232                     if f.nelem_field is not None
233                 ])),
234             "  /* cast here required to play nicely with C++ world ... */",
235             "  msg = (%s*)vapi_msg_alloc(ctx, size);" % self.get_c_name(),
236             "  if (!msg) {",
237             "    return NULL;",
238             "  }",
239         ] + extra + [
240             "  msg->header._vl_msg_id = vapi_lookup_vl_msg_id(ctx, %s);" %
241             self.get_msg_id_name(),
242             "\n".join(["  msg->payload.%s = %s;" % (
243                 f.nelem_field.name,
244                 self.get_alloc_func_vla_field_length_name(f))
245                 for f in self.fields
246                 if f.nelem_field is not None]),
247             "  return msg;",
248             "}"])
249
250     def get_calc_msg_size_func_name(self):
251         return "vapi_calc_%s_msg_size" % self.name
252
253     def get_calc_msg_size_func_decl(self):
254         return "uword %s(%s *msg)" % (
255             self.get_calc_msg_size_func_name(),
256             self.get_c_name())
257
258     def get_calc_msg_size_func_def(self):
259         return "\n".join([
260             "%s" % self.get_calc_msg_size_func_decl(),
261             "{",
262             "  return sizeof(*msg)%s;" %
263             "".join(["+ msg->payload.%s * sizeof(msg->payload.%s[0])" % (
264                     f.nelem_field.name,
265                     f.name)
266                 for f in self.fields
267                 if f.nelem_field is not None
268             ]),
269             "}",
270         ])
271
272     def get_c_def(self):
273         if self.has_payload():
274             return "\n".join([
275                 "typedef struct __attribute__ ((__packed__)) {",
276                 "%s; " %
277                 ";\n".join(self.payload_members),
278                 "} %s;" % self.get_payload_struct_name(),
279                 "",
280                 "typedef struct __attribute__ ((__packed__)) {",
281                 ("  %s %s;" % (self.header.get_c_name(),
282                                self.fields[0].name)
283                     if self.header is not None else ""),
284                 "  %s payload;" % self.get_payload_struct_name(),
285                 "} %s;" % self.get_c_name(), ])
286         else:
287             return "\n".join([
288                 "typedef struct __attribute__ ((__packed__)) {",
289                 ("  %s %s;" % (self.header.get_c_name(),
290                                self.fields[0].name)
291                     if self.header is not None else ""),
292                 "} %s;" % self.get_c_name(), ])
293
294     def get_swap_payload_to_host_func_name(self):
295         return "%s_payload_ntoh" % self.get_c_name()
296
297     def get_swap_payload_to_be_func_name(self):
298         return "%s_payload_hton" % self.get_c_name()
299
300     def get_swap_payload_to_host_func_decl(self):
301         return "void %s(%s *payload)" % (
302             self.get_swap_payload_to_host_func_name(),
303             self.get_payload_struct_name())
304
305     def get_swap_payload_to_be_func_decl(self):
306         return "void %s(%s *payload)" % (
307             self.get_swap_payload_to_be_func_name(),
308             self.get_payload_struct_name())
309
310     def get_swap_payload_to_be_func_def(self):
311         return "%s\n{\n%s\n}" % (
312             self.get_swap_payload_to_be_func_decl(),
313             "\n".join([
314                 "  %s" % p.get_swap_to_be_code("payload->", "%s" % p.name)
315                 for p in self.fields
316                 if p.needs_byte_swap() and p.type != self.header]),
317         )
318
319     def get_swap_payload_to_host_func_def(self):
320         return "%s\n{\n%s\n}" % (
321             self.get_swap_payload_to_host_func_decl(),
322             "\n".join([
323                 "  %s" % p.get_swap_to_host_code("payload->", "%s" % p.name)
324                 for p in self.fields
325                 if p.needs_byte_swap() and p.type != self.header]),
326         )
327
328     def get_swap_to_host_func_name(self):
329         return "%s_ntoh" % self.get_c_name()
330
331     def get_swap_to_be_func_name(self):
332         return "%s_hton" % self.get_c_name()
333
334     def get_swap_to_host_func_decl(self):
335         return "void %s(%s *msg)" % (
336             self.get_swap_to_host_func_name(), self.get_c_name())
337
338     def get_swap_to_be_func_decl(self):
339         return "void %s(%s *msg)" % (
340             self.get_swap_to_be_func_name(), self.get_c_name())
341
342     def get_swap_to_be_func_def(self):
343         return "\n".join([
344             "%s" % self.get_swap_to_be_func_decl(),
345             "{",
346             ("  VAPI_DBG(\"Swapping `%s'@%%p to big endian\", msg);" %
347                 self.get_c_name()),
348             "  %s(&msg->header);" % self.header.get_swap_to_be_func_name()
349             if self.header is not None else "",
350             "  %s(&msg->payload);" % self.get_swap_payload_to_be_func_name()
351             if self.has_payload() else "",
352             "}",
353         ])
354
355     def get_swap_to_host_func_def(self):
356         return "\n".join([
357             "%s" % self.get_swap_to_host_func_decl(),
358             "{",
359             ("  VAPI_DBG(\"Swapping `%s'@%%p to host byte order\", msg);" %
360                 self.get_c_name()),
361             "  %s(&msg->header);" % self.header.get_swap_to_host_func_name()
362             if self.header is not None else "",
363             "  %s(&msg->payload);" % self.get_swap_payload_to_host_func_name()
364             if self.has_payload() else "",
365             "}",
366         ])
367
368     def get_op_func_name(self):
369         return "vapi_%s" % self.name
370
371     def get_op_func_decl(self):
372         if self.reply.has_payload():
373             return "vapi_error_e %s(%s)" % (
374                 self.get_op_func_name(),
375                 ",\n  ".join([
376                     'struct vapi_ctx_s *ctx',
377                     '%s *msg' % self.get_c_name(),
378                     'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
379                     '                         void *callback_ctx',
380                     '                         vapi_error_e rv',
381                     '                         bool is_last',
382                     '                         %s *reply)' %
383                     self.reply.get_payload_struct_name(),
384                     'void *callback_ctx',
385                 ])
386             )
387         else:
388             return "vapi_error_e %s(%s)" % (
389                 self.get_op_func_name(),
390                 ",\n  ".join([
391                     'struct vapi_ctx_s *ctx',
392                     '%s *msg' % self.get_c_name(),
393                     'vapi_error_e (*callback)(struct vapi_ctx_s *ctx',
394                     '                         void *callback_ctx',
395                     '                         vapi_error_e rv',
396                     '                         bool is_last)',
397                     'void *callback_ctx',
398                 ])
399             )
400
401     def get_op_func_def(self):
402         return "\n".join([
403             "%s" % self.get_op_func_decl(),
404             "{",
405             "  if (!msg || !callback) {",
406             "    return VAPI_EINVAL;",
407             "  }",
408             "  if (vapi_is_nonblocking(ctx) && vapi_requests_full(ctx)) {",
409             "    return VAPI_EAGAIN;",
410             "  }",
411             "  vapi_error_e rv;",
412             "  if (VAPI_OK != (rv = vapi_producer_lock (ctx))) {",
413             "    return rv;",
414             "  }",
415             "  u32 req_context = vapi_gen_req_context(ctx);",
416             "  msg->header.context = req_context;",
417             "  %s(msg);" % self.get_swap_to_be_func_name(),
418             ("  if (VAPI_OK == (rv = vapi_send_with_control_ping "
419                 "(ctx, msg, req_context))) {"
420                 if self.is_dump() else
421                 "  if (VAPI_OK == (rv = vapi_send (ctx, msg))) {"
422              ),
423             ("    vapi_store_request(ctx, req_context, %s, "
424              "(vapi_cb_t)callback, callback_ctx);" %
425              ("true" if self.is_dump() else "false")),
426             "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
427             "      abort (); /* this really shouldn't happen */",
428             "    }",
429             "    if (vapi_is_nonblocking(ctx)) {",
430             "      rv = VAPI_OK;",
431             "    } else {",
432             "      rv = vapi_dispatch(ctx);",
433             "    }",
434             "  } else {",
435             "    %s(msg);" % self.get_swap_to_host_func_name(),
436             "    if (VAPI_OK != vapi_producer_unlock (ctx)) {",
437             "      abort (); /* this really shouldn't happen */",
438             "    }",
439             "  }",
440             "  return rv;",
441             "}",
442             "",
443         ])
444
445     def get_event_cb_func_decl(self):
446         if not self.is_reply():
447             raise Exception(
448                 "Cannot register event callback for non-reply message")
449         if self.has_payload():
450             return "\n".join([
451                 "void vapi_set_%s_event_cb (" %
452                 self.get_c_name(),
453                 "  struct vapi_ctx_s *ctx, ",
454                 ("  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
455                  "void *callback_ctx, %s *payload)," %
456                  self.get_payload_struct_name()),
457                 "  void *callback_ctx)",
458             ])
459         else:
460             return "\n".join([
461                 "void vapi_set_%s_event_cb (" %
462                 self.get_c_name(),
463                 "  struct vapi_ctx_s *ctx, ",
464                 "  vapi_error_e (*callback)(struct vapi_ctx_s *ctx, "
465                 "void *callback_ctx),",
466                 "  void *callback_ctx)",
467             ])
468
469     def get_event_cb_func_def(self):
470         if not self.is_reply():
471             raise Exception(
472                 "Cannot register event callback for non-reply function")
473         return "\n".join([
474             "%s" % self.get_event_cb_func_decl(),
475             "{",
476             ("  vapi_set_event_cb(ctx, %s, (vapi_event_cb)callback, "
477              "callback_ctx);" %
478              self.get_msg_id_name()),
479             "}"])
480
481     def get_c_metadata_struct_name(self):
482         return "__vapi_metadata_%s" % self.name
483
484     def get_c_constructor(self):
485         has_context = False
486         if self.header is not None:
487             has_context = self.header.has_field('context')
488         return '\n'.join([
489             'static void __attribute__((constructor)) __vapi_constructor_%s()'
490             % self.name,
491             '{',
492             '  static const char name[] = "%s";' % self.name,
493             '  static const char name_with_crc[] = "%s_%s";'
494             % (self.name, self.crc[2:]),
495             '  static vapi_message_desc_t %s = {' %
496             self.get_c_metadata_struct_name(),
497             '    name,',
498             '    sizeof(name) - 1,',
499             '    name_with_crc,',
500             '    sizeof(name_with_crc) - 1,',
501             '    true,' if has_context else '    false,',
502             '    offsetof(%s, context),' % self.header.get_c_name()
503             if has_context else '    0,',
504             ('    offsetof(%s, payload),' % self.get_c_name())
505             if self.has_payload() else '    ~0,',
506             '    sizeof(%s),' % self.get_c_name(),
507             '    (generic_swap_fn_t)%s,' % self.get_swap_to_be_func_name(),
508             '    (generic_swap_fn_t)%s,' % self.get_swap_to_host_func_name(),
509             '    ~0,',
510             '  };',
511             '',
512             '  %s = vapi_register_msg(&%s);' %
513             (self.get_msg_id_name(), self.get_c_metadata_struct_name()),
514             '  VAPI_DBG("Assigned msg id %%d to %s", %s);' %
515             (self.name, self.get_msg_id_name()),
516             '}',
517         ])
518
519
520 vapi_send_with_control_ping = """
521 static inline vapi_error_e
522 vapi_send_with_control_ping (vapi_ctx_t ctx, void *msg, u32 context)
523 {
524   vapi_msg_control_ping *ping = vapi_alloc_control_ping (ctx);
525   if (!ping)
526     {
527       return VAPI_ENOMEM;
528     }
529   ping->header.context = context;
530   vapi_msg_control_ping_hton (ping);
531   return vapi_send2 (ctx, msg, ping);
532 }
533 """
534
535
536 def gen_json_unified_header(parser, logger, j, io, name):
537     logger.info("Generating header `%s'" % name)
538     orig_stdout = sys.stdout
539     sys.stdout = io
540     include_guard = "__included_%s" % (
541         j.replace(".", "_").replace("/", "_").replace("-", "_"))
542     print("#ifndef %s" % include_guard)
543     print("#define %s" % include_guard)
544     print("")
545     print("#include <stdlib.h>")
546     print("#include <stddef.h>")
547     print("#include <arpa/inet.h>")
548     print("#include <vapi/vapi_internal.h>")
549     print("#include <vapi/vapi.h>")
550     print("#include <vapi/vapi_dbg.h>")
551     print("")
552     print("#ifdef __cplusplus")
553     print("extern \"C\" {")
554     print("#endif")
555     if name == "vpe.api.vapi.h":
556         print("")
557         print("static inline vapi_error_e vapi_send_with_control_ping "
558               "(vapi_ctx_t ctx, void * msg, u32 context);")
559     else:
560         print("#include <vapi/vpe.api.vapi.h>")
561     print("")
562     for m in parser.messages_by_json[j].values():
563         print("extern vapi_msg_id_t %s;" % m.get_msg_id_name())
564     print("")
565     print("#define DEFINE_VAPI_MSG_IDS_%s\\" %
566           j.replace(".", "_").replace("/", "_").replace("-", "_").upper())
567     print("\\\n".join([
568         "  vapi_msg_id_t %s;" % m.get_msg_id_name()
569         for m in parser.messages_by_json[j].values()
570     ]))
571     print("")
572     print("")
573     for t in parser.types_by_json[j].values():
574         try:
575             print("%s" % t.get_c_def())
576             print("")
577         except:
578             pass
579     for m in parser.messages_by_json[j].values():
580         print("%s" % m.get_c_def())
581         print("")
582
583     print("")
584     function_attrs = "static inline "
585     for t in parser.types_by_json[j].values():
586         print("%s%s" % (function_attrs, t.get_swap_to_be_func_def()))
587         print("")
588         print("%s%s" % (function_attrs, t.get_swap_to_host_func_def()))
589         print("")
590     for m in parser.messages_by_json[j].values():
591         if m.has_payload():
592             print("%s%s" % (function_attrs,
593                             m.get_swap_payload_to_be_func_def()))
594             print("")
595             print("%s%s" % (function_attrs,
596                             m.get_swap_payload_to_host_func_def()))
597             print("")
598         print("%s%s" % (function_attrs, m.get_calc_msg_size_func_def()))
599         print("")
600         print("%s%s" % (function_attrs, m.get_swap_to_be_func_def()))
601         print("")
602         print("%s%s" % (function_attrs, m.get_swap_to_host_func_def()))
603         print("")
604     for m in parser.messages_by_json[j].values():
605         if m.is_reply():
606             continue
607         print("%s%s" % (function_attrs, m.get_alloc_func_def()))
608         print("")
609         print("%s%s" % (function_attrs, m.get_op_func_def()))
610         print("")
611     print("")
612     for m in parser.messages_by_json[j].values():
613         print("%s" % m.get_c_constructor())
614         print("")
615     print("")
616     for m in parser.messages_by_json[j].values():
617         if not m.is_reply():
618             continue
619         print("%s%s;" % (function_attrs, m.get_event_cb_func_def()))
620         print("")
621     print("")
622
623     if name == "vpe.api.vapi.h":
624         print("%s" % vapi_send_with_control_ping)
625         print("")
626
627     print("#ifdef __cplusplus")
628     print("}")
629     print("#endif")
630     print("")
631     print("#endif")
632     sys.stdout = orig_stdout
633
634
635 def json_to_c_header_name(json_name):
636     if json_name.endswith(".json"):
637         return "%s.vapi.h" % os.path.splitext(json_name)[0]
638     raise Exception("Unexpected json name `%s'!" % json_name)
639
640
641 def gen_c_unified_headers(parser, logger, prefix):
642     if prefix == "" or prefix is None:
643         prefix = ""
644     else:
645         prefix = "%s/" % prefix
646     for j in parser.json_files:
647         with open('%s%s' % (prefix, json_to_c_header_name(j)), "w") as io:
648             gen_json_unified_header(
649                 parser, logger, j, io, json_to_c_header_name(j))
650
651
652 if __name__ == '__main__':
653     try:
654         verbose = int(os.getenv("V", 0))
655     except:
656         verbose = 0
657
658     if verbose >= 2:
659         log_level = 10
660     elif verbose == 1:
661         log_level = 20
662     else:
663         log_level = 40
664
665     logging.basicConfig(stream=sys.stdout, level=log_level)
666     logger = logging.getLogger("VAPI C GEN")
667     logger.setLevel(log_level)
668
669     argparser = argparse.ArgumentParser(description="VPP C API generator")
670     argparser.add_argument('files', metavar='api-file', action='append',
671                            type=str, help='json api file'
672                            '(may be specified multiple times)')
673     argparser.add_argument('--prefix', action='store', default=None,
674                            help='path prefix')
675     args = argparser.parse_args()
676
677     jsonparser = JsonParser(logger, args.files,
678                             simple_type_class=CSimpleType,
679                             struct_type_class=CStructType,
680                             field_class=CField,
681                             message_class=CMessage)
682
683     # not using the model of having separate generated header and code files
684     # with generated symbols present in shared library (per discussion with
685     # Damjan), to avoid symbol version issues in .so
686     # gen_c_headers_and_code(jsonparser, logger, args.prefix)
687
688     gen_c_unified_headers(jsonparser, logger, args.prefix)
689
690     for e in jsonparser.exceptions:
691         logger.error(e)