blob: c6aa009cbb9245da2e0e028ca20362fc3d8644a4 [file] [log] [blame]
Ole Troan1b1ccad2019-10-25 18:30:40 +02001#!/usr/bin/env python3
Klement Sekeradc15be22017-06-12 06:49:33 +02002
3import argparse
4import os
5import sys
6import logging
Klement Sekera2108c0c2018-08-24 11:43:20 +02007from vapi_c_gen import CField, CEnum, CStruct, CSimpleType, CStructType,\
Ole Troan53fffa12018-11-13 12:36:56 +01008 CMessage, json_to_c_header_name, CAlias
Klement Sekeradc15be22017-06-12 06:49:33 +02009from vapi_json_parser import JsonParser
10
11
12class CppField(CField):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020013 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020014
15
16class CppStruct(CStruct):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020017 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020018
19
Klement Sekera2108c0c2018-08-24 11:43:20 +020020class CppEnum(CEnum):
21 pass
22
23
Ole Troan53fffa12018-11-13 12:36:56 +010024class CppAlias(CAlias):
25 pass
26
27
Klement Sekeradc15be22017-06-12 06:49:33 +020028class CppSimpleType (CSimpleType):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020029 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020030
31
32class CppStructType (CStructType, CppStruct):
Klement Sekera8b6b5ab2018-05-03 14:27:42 +020033 pass
Klement Sekeradc15be22017-06-12 06:49:33 +020034
35
36class CppMessage (CMessage):
Klement Sekeradc15be22017-06-12 06:49:33 +020037 def get_swap_to_be_template_instantiation(self):
38 return "\n".join([
39 "template <> inline void vapi_swap_to_be<%s>(%s *msg)" %
40 (self.get_c_name(), self.get_c_name()),
41 "{",
42 " %s(msg);" % self.get_swap_to_be_func_name(),
43 "}",
44 ])
45
46 def get_swap_to_host_template_instantiation(self):
47 return "\n".join([
48 "template <> inline void vapi_swap_to_host<%s>(%s *msg)" %
49 (self.get_c_name(), self.get_c_name()),
50 "{",
51 " %s(msg);" % self.get_swap_to_host_func_name(),
52 "}",
53 ])
54
55 def get_alloc_template_instantiation(self):
56 return "\n".join([
57 "template <> inline %s* vapi_alloc<%s%s>"
58 "(Connection &con%s)" %
59 (self.get_c_name(), self.get_c_name(),
60 ", size_t" * len(self.get_alloc_vla_param_names()),
61 "".join([", size_t %s" % n for n in
62 self.get_alloc_vla_param_names()])
63 ),
64 "{",
65 " %s* result = %s(con.vapi_ctx%s);" %
66 (self.get_c_name(), self.get_alloc_func_name(),
67 "".join([", %s" % n
68 for n in self.get_alloc_vla_param_names()])),
69 "#if VAPI_CPP_DEBUG_LEAKS",
70 " con.on_shm_data_alloc(result);",
71 "#endif",
72 " return result;",
73 "}",
74 ])
75
76 def get_cpp_name(self):
77 return "%s%s" % (self.name[0].upper(), self.name[1:])
78
79 def get_req_template_name(self):
Klement Sekera2108c0c2018-08-24 11:43:20 +020080 if self.reply_is_stream:
Klement Sekeradc15be22017-06-12 06:49:33 +020081 template = "Dump"
82 else:
83 template = "Request"
84
85 return "%s<%s, %s%s>" % (
86 template,
87 self.get_c_name(),
88 self.reply.get_c_name(),
89 "".join([", size_t"] * len(self.get_alloc_vla_param_names()))
90 )
91
92 def get_req_template_instantiation(self):
93 return "template class %s;" % self.get_req_template_name()
94
95 def get_type_alias(self):
96 return "using %s = %s;" % (
97 self.get_cpp_name(), self.get_req_template_name())
98
99 def get_reply_template_name(self):
100 return "Msg<%s>" % (self.get_c_name())
101
102 def get_reply_type_alias(self):
103 return "using %s = %s;" % (
104 self.get_cpp_name(), self.get_reply_template_name())
105
106 def get_msg_class_instantiation(self):
107 return "template class Msg<%s>;" % self.get_c_name()
108
109 def get_get_msg_id_t_instantiation(self):
110 return "\n".join([
111 ("template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()"
112 % self.get_c_name()),
113 "{",
114 " return ::%s; " % self.get_msg_id_name(),
115 "}",
116 "",
117 ("template <> inline vapi_msg_id_t "
118 "vapi_get_msg_id_t<Msg<%s>>()" % self.get_c_name()),
119 "{",
120 " return ::%s; " % self.get_msg_id_name(),
121 "}",
122 ])
123
124 def get_cpp_constructor(self):
125 return '\n'.join([
126 ('static void __attribute__((constructor)) '
127 '__vapi_cpp_constructor_%s()'
128 % self.name),
129 '{',
130 (' vapi::vapi_msg_set_msg_id<%s>(%s);' % (
131 self.get_c_name(), self.get_msg_id_name())),
132 '}',
133 ])
134
135
136def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments):
137 logger.info("Generating header `%s'" % io.name)
138 orig_stdout = sys.stdout
139 sys.stdout = io
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200140 d, f = os.path.split(j)
Klement Sekeradc15be22017-06-12 06:49:33 +0200141 include_guard = "__included_hpp_%s" % (
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200142 f.replace(".", "_").replace("/", "_").replace("-", "_"))
Klement Sekeradc15be22017-06-12 06:49:33 +0200143 print("#ifndef %s" % include_guard)
144 print("#define %s" % include_guard)
145 print("")
146 print("#include <vapi/vapi.hpp>")
Mohsin Kazmib3abec72018-08-27 13:17:09 +0200147 print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(f)))
Klement Sekeradc15be22017-06-12 06:49:33 +0200148 print("")
149 print("namespace vapi {")
150 print("")
151 for m in parser.messages_by_json[j].values():
152 # utility functions need to go first, otherwise internal instantiation
153 # causes headaches ...
154 if add_debug_comments:
155 print("/* m.get_swap_to_be_template_instantiation() */")
156 print("%s" % m.get_swap_to_be_template_instantiation())
157 print("")
158 if add_debug_comments:
159 print("/* m.get_swap_to_host_template_instantiation() */")
160 print("%s" % m.get_swap_to_host_template_instantiation())
161 print("")
162 if add_debug_comments:
163 print("/* m.get_get_msg_id_t_instantiation() */")
164 print("%s" % m.get_get_msg_id_t_instantiation())
165 print("")
166 if add_debug_comments:
167 print("/* m.get_cpp_constructor() */")
168 print("%s" % m.get_cpp_constructor())
169 print("")
Klement Sekera2108c0c2018-08-24 11:43:20 +0200170 if not m.is_reply and not m.is_event:
Klement Sekeradc15be22017-06-12 06:49:33 +0200171 if add_debug_comments:
172 print("/* m.get_alloc_template_instantiation() */")
173 print("%s" % m.get_alloc_template_instantiation())
174 print("")
175 if add_debug_comments:
176 print("/* m.get_msg_class_instantiation() */")
177 print("%s" % m.get_msg_class_instantiation())
178 print("")
Klement Sekera2108c0c2018-08-24 11:43:20 +0200179 if m.is_reply or m.is_event:
Klement Sekeradc15be22017-06-12 06:49:33 +0200180 if add_debug_comments:
181 print("/* m.get_reply_type_alias() */")
182 print("%s" % m.get_reply_type_alias())
183 continue
184 if add_debug_comments:
185 print("/* m.get_req_template_instantiation() */")
186 print("%s" % m.get_req_template_instantiation())
187 print("")
188 if add_debug_comments:
189 print("/* m.get_type_alias() */")
190 print("%s" % m.get_type_alias())
191 print("")
192 print("}") # namespace vapi
193
194 print("#endif")
195 sys.stdout = orig_stdout
196
197
198def json_to_cpp_header_name(json_name):
199 if json_name.endswith(".json"):
200 return "%s.vapi.hpp" % os.path.splitext(json_name)[0]
201 raise Exception("Unexpected json name `%s'!" % json_name)
202
203
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200204def gen_cpp_headers(parser, logger, prefix, gen_h_prefix, remove_path,
Klement Sekeradc15be22017-06-12 06:49:33 +0200205 add_debug_comments=False):
206 if prefix == "" or prefix is None:
207 prefix = ""
208 else:
209 prefix = "%s/" % prefix
210 if gen_h_prefix is None:
211 gen_h_prefix = ""
212 else:
213 gen_h_prefix = "%s/" % gen_h_prefix
214 for j in parser.json_files:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200215 if remove_path:
216 d, f = os.path.split(j)
217 else:
218 f = j
219 with open('%s%s' % (prefix, json_to_cpp_header_name(f)), "w") as io:
Klement Sekeradc15be22017-06-12 06:49:33 +0200220 gen_json_header(parser, logger, j, io,
221 gen_h_prefix, add_debug_comments)
222
223
224if __name__ == '__main__':
225 try:
226 verbose = int(os.getenv("V", 0))
227 except:
228 verbose = 0
229
230 if verbose >= 2:
231 log_level = 10
232 elif verbose == 1:
233 log_level = 20
234 else:
235 log_level = 40
236
237 logging.basicConfig(stream=sys.stdout, level=log_level)
238 logger = logging.getLogger("VAPI CPP GEN")
239 logger.setLevel(log_level)
240
241 argparser = argparse.ArgumentParser(description="VPP C++ API generator")
242 argparser.add_argument('files', metavar='api-file', action='append',
243 type=str, help='json api file'
244 '(may be specified multiple times)')
245 argparser.add_argument('--prefix', action='store', default=None,
246 help='path prefix')
247 argparser.add_argument('--gen-h-prefix', action='store', default=None,
248 help='generated C header prefix')
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200249 argparser.add_argument('--remove-path', action='store_true',
250 help='remove path from filename')
Klement Sekeradc15be22017-06-12 06:49:33 +0200251 args = argparser.parse_args()
252
253 jsonparser = JsonParser(logger, args.files,
254 simple_type_class=CppSimpleType,
255 struct_type_class=CppStructType,
256 field_class=CppField,
Klement Sekera2108c0c2018-08-24 11:43:20 +0200257 enum_class=CppEnum,
Ole Troan53fffa12018-11-13 12:36:56 +0100258 message_class=CppMessage,
259 alias_class=CppAlias)
Klement Sekeradc15be22017-06-12 06:49:33 +0200260
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200261 gen_cpp_headers(jsonparser, logger, args.prefix, args.gen_h_prefix,
262 args.remove_path)
Klement Sekeradc15be22017-06-12 06:49:33 +0200263
264 for e in jsonparser.exceptions:
Damjan Marion4c64b6e2018-08-26 18:14:46 +0200265 logger.warning(e)