Fix: vppapigen make build fails on fresh install
[vpp.git] / src / tools / vppapigen / vppapigen_c.py
1 # C generation
2 import datetime
3 import os
4 import time
5
6 datestring = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time())))
7 input_filename = 'inputfil'
8 top_boilerplate = '''\
9 /*
10  * VLIB API definitions {datestring}
11  * Input file: {input_filename}
12  * Automatically generated: please edit the input file NOT this file!
13  */
14
15 #if defined(vl_msg_id)||defined(vl_union_id) \\
16     || defined(vl_printfun) ||defined(vl_endianfun) \\
17     || defined(vl_api_version)||defined(vl_typedefs) \\
18     || defined(vl_msg_name)||defined(vl_msg_name_crc_list) \\
19     || defined(vl_api_version_tuple)
20 /* ok, something was selected */
21 #else
22 #warning no content included from {input_filename}
23 #endif
24
25 #define VL_API_PACKED(x) x __attribute__ ((packed))
26 '''
27
28 bottom_boilerplate = '''\
29 /****** API CRC (whole file) *****/
30
31 #ifdef vl_api_version
32 vl_api_version({input_filename}, {file_crc:#08x})
33
34 #endif
35 '''
36
37
38 def msg_ids(s):
39     output = '''\
40
41 /****** Message ID / handler enum ******/
42
43 #ifdef vl_msg_id
44 '''
45
46     for t in s['Define']:
47         output += "vl_msg_id(VL_API_%s, vl_api_%s_t_handler)\n" % \
48                   (t.name.upper(), t.name)
49     output += "#endif"
50
51     return output
52
53
54 def msg_names(s):
55     output = '''\
56
57 /****** Message names ******/
58
59 #ifdef vl_msg_name
60 '''
61
62     for t in s['Define']:
63         dont_trace = 0 if t.dont_trace else 1
64         output += "vl_msg_name(vl_api_%s_t, %d)\n" % (t.name, dont_trace)
65     output += "#endif"
66
67     return output
68
69
70 def msg_name_crc_list(s, suffix):
71     output = '''\
72
73 /****** Message name, crc list ******/
74
75 #ifdef vl_msg_name_crc_list
76 '''
77     output += "#define foreach_vl_msg_name_crc_%s " % suffix
78
79     for t in s['Define']:
80         output += "\\\n_(VL_API_%s, %s, %08x) " % \
81                    (t.name.upper(), t.name, t.crc)
82     output += "\n#endif"
83
84     return output
85
86
87 def duplicate_wrapper_head(name):
88     s = "#ifndef defined_%s\n" % name
89     s += "#define defined_%s\n" % name
90     return s
91
92
93 def duplicate_wrapper_tail():
94     return '#endif\n\n'
95
96
97 def typedefs(objs, filename):
98     name = filename.replace('.', '_')
99     output = '''\
100
101
102 /****** Typedefs ******/
103
104 #ifdef vl_typedefs
105 #ifndef included_{module}
106 #define included_{module}
107 '''
108     output = output.format(module=name)
109     for o in objs:
110         tname = o.__class__.__name__
111         output += duplicate_wrapper_head(o.name)
112         if tname == 'Enum':
113             output += "typedef enum {\n"
114             for b in o.block:
115                 output += "    %s = %s,\n" % (b[0], b[1])
116             output += '} vl_api_%s_t;\n' % o.name
117         else:
118             if tname == 'Union':
119                 output += "typedef VL_API_PACKED(union _vl_api_%s {\n" % o.name
120             else:
121                 output += "typedef VL_API_PACKED(struct _vl_api_%s {\n" % o.name
122             for b in o.block:
123                 if b.type == 'Field':
124                     output += "    %s %s;\n" % (b.fieldtype, b.fieldname)
125                 elif b.type == 'Array':
126                     if b.lengthfield:
127                         output += "    %s %s[0];\n" % (b.fieldtype, b.fieldname)
128                     else:
129                         output += "    %s %s[%s];\n" % (b.fieldtype, b.fieldname,
130                                                         b.length)
131                 else:
132                     raise ValueError("Error in processing array type %s" % b)
133
134             output += '}) vl_api_%s_t;\n' % o.name
135         output += duplicate_wrapper_tail()
136
137     output += "\n#endif"
138     output += "\n#endif\n\n"
139
140     return output
141
142
143 format_strings = {'u8': '%u',
144                   'i8': '%d',
145                   'u16': '%u',
146                   'i16': '%d',
147                   'u32': '%u',
148                   'i32': '%ld',
149                   'u64': '%llu',
150                   'i64': '%llu',
151                   'f64': '%.2f', }
152
153
154 def printfun(objs):
155     output = '''\
156 /****** Print functions *****/
157 #ifdef vl_printfun
158
159 #ifdef LP64
160 #define _uword_fmt \"%lld\"
161 #define _uword_cast (long long)
162 #else
163 #define _uword_fmt \"%ld\"
164 #define _uword_cast long
165 #endif
166
167 '''
168     for t in objs:
169         if t.__class__.__name__ == 'Enum':
170             continue
171         if t.manual_print:
172             output += "/***** manual: vl_api_%s_t_print  *****/\n\n" % t.name
173             continue
174         output += duplicate_wrapper_head(t.name + '_t_print')
175         output += "static inline void *vl_api_%s_t_print (vl_api_%s_t *a," % \
176                   (t.name, t.name)
177         output += "void *handle)\n{\n"
178         output += "    vl_print(handle, \"vl_api_%s_t:\\n\");\n" % t.name
179
180         for o in t.block:
181             if o.type != 'Field':
182                 continue
183             if o.fieldtype in format_strings:
184                 output += "    vl_print(handle, \"%s: %s\\n\", a->%s);\n" % \
185                           (o.fieldname, format_strings[o.fieldtype],
186                            o.fieldname)
187
188         output += '    return handle;\n'
189         output += '}\n\n'
190         output += duplicate_wrapper_tail()
191
192     output += "\n#endif /* vl_printfun */\n"
193
194     return output
195
196
197 endian_strings = {
198     'u16': 'clib_net_to_host_u16',
199     'u32': 'clib_net_to_host_u32',
200     'u64': 'clib_net_to_host_u64',
201     'i16': 'clib_net_to_host_u16',
202     'i32': 'clib_net_to_host_u32',
203     'i64': 'clib_net_to_host_u64',
204 }
205
206
207 def endianfun(objs):
208     output = '''\
209
210 /****** Endian swap functions *****/\n\
211 #ifdef vl_endianfun
212
213 #undef clib_net_to_host_uword
214 #ifdef LP64
215 #define clib_net_to_host_uword clib_net_to_host_u64
216 #else
217 #define clib_net_to_host_uword clib_net_to_host_u32
218 #endif
219
220 '''
221
222     for t in objs:
223         if t.__class__.__name__ == 'Enum':
224             continue
225         if t.manual_endian:
226             output += "/***** manual: vl_api_%s_t_endian  *****/\n\n" % t.name
227             continue
228         output += duplicate_wrapper_head(t.name + '_t_endian')
229         output += "static inline void vl_api_%s_t_endian (vl_api_%s_t *a)" % \
230                   (t.name, t.name)
231         output += "\n{\n"
232
233         for o in t.block:
234             if o.type != 'Field':
235                 continue
236             if o.fieldtype in endian_strings:
237                 output += "    a->%s = %s(a->%s);\n" % \
238                         (o.fieldname, endian_strings[o.fieldtype], o.fieldname)
239             else:
240                 output += "    /* a->%s = a->%s (no-op) */\n" % \
241                                           (o.fieldname, o.fieldname)
242
243         output += '}\n\n'
244         output += duplicate_wrapper_tail()
245     output += "\n#endif /* vl_endianfun */\n\n"
246
247     return output
248
249
250 def version_tuple(s, module):
251     output = '''\
252 /****** Version tuple *****/
253
254 #ifdef vl_api_version_tuple
255
256 '''
257     if 'version' in s['Option']:
258         v = s['Option']['version']
259         (major, minor, patch) = v.split('.')
260         output += "vl_api_version_tuple(%s, %s, %s, %s)\n" % \
261                   (module, major, minor, patch)
262
263     output += "\n#endif /* vl_api_version_tuple */\n\n"
264
265     return output
266
267
268 #
269 # Plugin entry point
270 #
271 def run(input_filename, s, file_crc):
272     basename = os.path.basename(input_filename)
273     filename, file_extension = os.path.splitext(basename)
274     output = top_boilerplate.format(datestring=datestring,
275                                     input_filename=basename)
276     output += msg_ids(s)
277     output += msg_names(s)
278     output += msg_name_crc_list(s, filename)
279     output += typedefs(s['types'] + s['Define'], filename + file_extension)
280     output += printfun(s['types'] + s['Define'])
281     output += endianfun(s['types'] + s['Define'])
282     output += version_tuple(s, basename)
283     output += bottom_boilerplate.format(input_filename=basename,
284                                         file_crc=file_crc)
285
286     return output