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