blob: 6e9f5d3f46ffa2ff1043dab15c9a6a0465f018fe [file] [log] [blame]
Klement Sekeradc15be22017-06-12 06:49:33 +02001#!/usr/bin/env python3
2
3import argparse
4import os
5import sys
6import logging
7from vapi_c_gen import CField, CStruct, CSimpleType, CStructType, CMessage, \
8 json_to_c_header_name
9from vapi_json_parser import JsonParser
10
11
12class CppField(CField):
13 def __init__(
14 self,
15 field_name,
16 field_type,
17 array_len=None,
18 nelem_field=None):
19 super().__init__(field_name, field_type, array_len, nelem_field)
20
21
22class CppStruct(CStruct):
23 def __init__(self, name, fields):
24 super().__init__(name, fields)
25
26
27class CppSimpleType (CSimpleType):
28
29 def __init__(self, name):
30 super().__init__(name)
31
32
33class CppStructType (CStructType, CppStruct):
34 def __init__(self, definition, typedict, field_class):
35 super().__init__(definition, typedict, field_class)
36
37
38class CppMessage (CMessage):
39 def __init__(self, logger, definition, typedict,
40 struct_type_class, simple_type_class, field_class):
41 super().__init__(logger, definition, typedict, struct_type_class,
42 simple_type_class, field_class)
43
44 def get_swap_to_be_template_instantiation(self):
45 return "\n".join([
46 "template <> inline void vapi_swap_to_be<%s>(%s *msg)" %
47 (self.get_c_name(), self.get_c_name()),
48 "{",
49 " %s(msg);" % self.get_swap_to_be_func_name(),
50 "}",
51 ])
52
53 def get_swap_to_host_template_instantiation(self):
54 return "\n".join([
55 "template <> inline void vapi_swap_to_host<%s>(%s *msg)" %
56 (self.get_c_name(), self.get_c_name()),
57 "{",
58 " %s(msg);" % self.get_swap_to_host_func_name(),
59 "}",
60 ])
61
62 def get_alloc_template_instantiation(self):
63 return "\n".join([
64 "template <> inline %s* vapi_alloc<%s%s>"
65 "(Connection &con%s)" %
66 (self.get_c_name(), self.get_c_name(),
67 ", size_t" * len(self.get_alloc_vla_param_names()),
68 "".join([", size_t %s" % n for n in
69 self.get_alloc_vla_param_names()])
70 ),
71 "{",
72 " %s* result = %s(con.vapi_ctx%s);" %
73 (self.get_c_name(), self.get_alloc_func_name(),
74 "".join([", %s" % n
75 for n in self.get_alloc_vla_param_names()])),
76 "#if VAPI_CPP_DEBUG_LEAKS",
77 " con.on_shm_data_alloc(result);",
78 "#endif",
79 " return result;",
80 "}",
81 ])
82
83 def get_cpp_name(self):
84 return "%s%s" % (self.name[0].upper(), self.name[1:])
85
86 def get_req_template_name(self):
87 if self.is_dump():
88 template = "Dump"
89 else:
90 template = "Request"
91
92 return "%s<%s, %s%s>" % (
93 template,
94 self.get_c_name(),
95 self.reply.get_c_name(),
96 "".join([", size_t"] * len(self.get_alloc_vla_param_names()))
97 )
98
99 def get_req_template_instantiation(self):
100 return "template class %s;" % self.get_req_template_name()
101
102 def get_type_alias(self):
103 return "using %s = %s;" % (
104 self.get_cpp_name(), self.get_req_template_name())
105
106 def get_reply_template_name(self):
107 return "Msg<%s>" % (self.get_c_name())
108
109 def get_reply_type_alias(self):
110 return "using %s = %s;" % (
111 self.get_cpp_name(), self.get_reply_template_name())
112
113 def get_msg_class_instantiation(self):
114 return "template class Msg<%s>;" % self.get_c_name()
115
116 def get_get_msg_id_t_instantiation(self):
117 return "\n".join([
118 ("template <> inline vapi_msg_id_t vapi_get_msg_id_t<%s>()"
119 % self.get_c_name()),
120 "{",
121 " return ::%s; " % self.get_msg_id_name(),
122 "}",
123 "",
124 ("template <> inline vapi_msg_id_t "
125 "vapi_get_msg_id_t<Msg<%s>>()" % self.get_c_name()),
126 "{",
127 " return ::%s; " % self.get_msg_id_name(),
128 "}",
129 ])
130
131 def get_cpp_constructor(self):
132 return '\n'.join([
133 ('static void __attribute__((constructor)) '
134 '__vapi_cpp_constructor_%s()'
135 % self.name),
136 '{',
137 (' vapi::vapi_msg_set_msg_id<%s>(%s);' % (
138 self.get_c_name(), self.get_msg_id_name())),
139 '}',
140 ])
141
142
143def gen_json_header(parser, logger, j, io, gen_h_prefix, add_debug_comments):
144 logger.info("Generating header `%s'" % io.name)
145 orig_stdout = sys.stdout
146 sys.stdout = io
147 include_guard = "__included_hpp_%s" % (
148 j.replace(".", "_").replace("/", "_").replace("-", "_"))
149 print("#ifndef %s" % include_guard)
150 print("#define %s" % include_guard)
151 print("")
152 print("#include <vapi/vapi.hpp>")
153 print("#include <%s%s>" % (gen_h_prefix, json_to_c_header_name(j)))
154 print("")
155 print("namespace vapi {")
156 print("")
157 for m in parser.messages_by_json[j].values():
158 # utility functions need to go first, otherwise internal instantiation
159 # causes headaches ...
160 if add_debug_comments:
161 print("/* m.get_swap_to_be_template_instantiation() */")
162 print("%s" % m.get_swap_to_be_template_instantiation())
163 print("")
164 if add_debug_comments:
165 print("/* m.get_swap_to_host_template_instantiation() */")
166 print("%s" % m.get_swap_to_host_template_instantiation())
167 print("")
168 if add_debug_comments:
169 print("/* m.get_get_msg_id_t_instantiation() */")
170 print("%s" % m.get_get_msg_id_t_instantiation())
171 print("")
172 if add_debug_comments:
173 print("/* m.get_cpp_constructor() */")
174 print("%s" % m.get_cpp_constructor())
175 print("")
176 if not m.is_reply():
177 if add_debug_comments:
178 print("/* m.get_alloc_template_instantiation() */")
179 print("%s" % m.get_alloc_template_instantiation())
180 print("")
181 if add_debug_comments:
182 print("/* m.get_msg_class_instantiation() */")
183 print("%s" % m.get_msg_class_instantiation())
184 print("")
185 if m.is_reply():
186 if add_debug_comments:
187 print("/* m.get_reply_type_alias() */")
188 print("%s" % m.get_reply_type_alias())
189 continue
190 if add_debug_comments:
191 print("/* m.get_req_template_instantiation() */")
192 print("%s" % m.get_req_template_instantiation())
193 print("")
194 if add_debug_comments:
195 print("/* m.get_type_alias() */")
196 print("%s" % m.get_type_alias())
197 print("")
198 print("}") # namespace vapi
199
200 print("#endif")
201 sys.stdout = orig_stdout
202
203
204def json_to_cpp_header_name(json_name):
205 if json_name.endswith(".json"):
206 return "%s.vapi.hpp" % os.path.splitext(json_name)[0]
207 raise Exception("Unexpected json name `%s'!" % json_name)
208
209
210def gen_cpp_headers(parser, logger, prefix, gen_h_prefix,
211 add_debug_comments=False):
212 if prefix == "" or prefix is None:
213 prefix = ""
214 else:
215 prefix = "%s/" % prefix
216 if gen_h_prefix is None:
217 gen_h_prefix = ""
218 else:
219 gen_h_prefix = "%s/" % gen_h_prefix
220 for j in parser.json_files:
221 with open('%s%s' % (prefix, json_to_cpp_header_name(j)), "w") as io:
222 gen_json_header(parser, logger, j, io,
223 gen_h_prefix, add_debug_comments)
224
225
226if __name__ == '__main__':
227 try:
228 verbose = int(os.getenv("V", 0))
229 except:
230 verbose = 0
231
232 if verbose >= 2:
233 log_level = 10
234 elif verbose == 1:
235 log_level = 20
236 else:
237 log_level = 40
238
239 logging.basicConfig(stream=sys.stdout, level=log_level)
240 logger = logging.getLogger("VAPI CPP GEN")
241 logger.setLevel(log_level)
242
243 argparser = argparse.ArgumentParser(description="VPP C++ API generator")
244 argparser.add_argument('files', metavar='api-file', action='append',
245 type=str, help='json api file'
246 '(may be specified multiple times)')
247 argparser.add_argument('--prefix', action='store', default=None,
248 help='path prefix')
249 argparser.add_argument('--gen-h-prefix', action='store', default=None,
250 help='generated C header prefix')
251 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,
257 message_class=CppMessage)
258
259 gen_cpp_headers(jsonparser, logger, args.prefix, args.gen_h_prefix)
260
261 for e in jsonparser.exceptions:
262 logger.error(e)