mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2026-01-11 08:07:23 +00:00
codegen: Allows to generate C declarations automatically
Allows to specify a @declare attribute for messages and structure that can generate the needed C structures. Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Christophe Fergeau <cfergeau@redhat.com>
This commit is contained in:
parent
dac34baaab
commit
3cd3886b27
@ -70,6 +70,8 @@ valid_attributes=set([
|
||||
'zero',
|
||||
# this attribute does not exist on the network, fill just structure with the value
|
||||
'virtual',
|
||||
# generate C structure declarations from protocol definition
|
||||
'declare',
|
||||
])
|
||||
|
||||
attributes_with_arguments=set([
|
||||
@ -483,6 +485,26 @@ class ArrayType(Type):
|
||||
def c_type(self):
|
||||
return self.element_type.c_type()
|
||||
|
||||
def generate_c_declaration(self, writer, member):
|
||||
name = member.name
|
||||
if member.has_attr("chunk"):
|
||||
return writer.writeln('SpiceChunks *%s;' % name)
|
||||
if member.has_attr("as_ptr"):
|
||||
len_var = member.attributes["as_ptr"][0]
|
||||
writer.writeln('uint32_t %s;' % len_var)
|
||||
return writer.writeln('%s *%s;' % (self.c_type(), name))
|
||||
if member.has_attr("to_ptr"):
|
||||
return writer.writeln('%s *%s;' % (self.c_type(), name))
|
||||
if member.has_attr("ptr_array"):
|
||||
return writer.writeln('%s *%s[0];' % (self.c_type(), name))
|
||||
if member.has_end_attr() or self.is_remaining_length():
|
||||
return writer.writeln('%s %s[0];' % (self.c_type(), name))
|
||||
if self.is_constant_length():
|
||||
return writer.writeln('%s %s[%s];' % (self.c_type(), name, self.size))
|
||||
if self.is_identifier_length():
|
||||
return writer.writeln('%s *%s;' % (self.c_type(), name))
|
||||
raise NotImplementedError('unknown array %s' % str(self))
|
||||
|
||||
class PointerType(Type):
|
||||
def __init__(self, target_type):
|
||||
Type.__init__(self)
|
||||
@ -517,6 +539,15 @@ class PointerType(Type):
|
||||
def get_num_pointers(self):
|
||||
return 1
|
||||
|
||||
def generate_c_declaration(self, writer, member):
|
||||
target_type = self.target_type
|
||||
is_array = target_type.is_array()
|
||||
if not is_array or target_type.is_identifier_length():
|
||||
writer.writeln("%s *%s;" % (target_type.c_type(), member.name))
|
||||
return
|
||||
raise NotImplementedError('Some pointers to array declarations are not implemented %s' %
|
||||
member)
|
||||
|
||||
class Containee:
|
||||
def __init__(self):
|
||||
self.attributes = {}
|
||||
@ -612,6 +643,14 @@ class Member(Containee):
|
||||
names = [prefix + "_" + name for name in names]
|
||||
return names
|
||||
|
||||
def generate_c_declaration(self, writer):
|
||||
if self.has_attr("zero"):
|
||||
return
|
||||
if self.is_pointer() or self.is_array():
|
||||
self.member_type.generate_c_declaration(writer, self)
|
||||
return
|
||||
return writer.writeln("%s %s;" % (self.member_type.c_type(), self.name))
|
||||
|
||||
class SwitchCase:
|
||||
def __init__(self, values, member):
|
||||
self.values = values
|
||||
@ -735,6 +774,17 @@ class Switch(Containee):
|
||||
names = names + c.get_pointer_names(marshalled)
|
||||
return names
|
||||
|
||||
def generate_c_declaration(self, writer):
|
||||
if self.has_attr("anon") and len(self.cases) == 1:
|
||||
self.cases[0].member.generate_c_declaration(writer)
|
||||
return
|
||||
writer.writeln('union {')
|
||||
writer.indent()
|
||||
for m in self.cases:
|
||||
m.member.generate_c_declaration(writer)
|
||||
writer.unindent()
|
||||
writer.writeln('} %s;' % self.name)
|
||||
|
||||
class ContainerType(Type):
|
||||
def is_fixed_sizeof(self):
|
||||
for m in self.members:
|
||||
@ -845,6 +895,20 @@ class ContainerType(Type):
|
||||
|
||||
return member
|
||||
|
||||
def generate_c_declaration(self, writer):
|
||||
if not self.has_attr('declare'):
|
||||
return
|
||||
name = self.c_type()
|
||||
writer.writeln('typedef struct %s {' % name)
|
||||
writer.indent()
|
||||
for m in self.members:
|
||||
m.generate_c_declaration(writer)
|
||||
if len(self.members) == 0:
|
||||
# make sure generated structure are not empty
|
||||
writer.writeln("char dummy[0];")
|
||||
writer.unindent()
|
||||
writer.writeln('} %s;' % name).newline()
|
||||
|
||||
class StructType(ContainerType):
|
||||
def __init__(self, name, members, attribute_list):
|
||||
Type.__init__(self)
|
||||
|
||||
@ -176,6 +176,8 @@ parser.add_option("--license", dest="license",
|
||||
parser.add_option("--generate-header",
|
||||
action="store_true", dest="generate_header", default=False,
|
||||
help="Generate also the header")
|
||||
parser.add_option("--generated-declaration-file", dest="generated_declaration_file", metavar="FILE",
|
||||
help="Name of the file to generate declarations")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
@ -257,6 +259,51 @@ else:
|
||||
print >> sys.stderr, "Invalid license specified: %s" % options.license
|
||||
sys.exit(1)
|
||||
|
||||
all_structures = {}
|
||||
def generate_declaration(t, writer_top):
|
||||
writer = codegen.CodeWriter()
|
||||
try:
|
||||
c_type = t.c_type()
|
||||
t.generate_c_declaration(writer)
|
||||
value = writer.getvalue().strip()
|
||||
if not value:
|
||||
return
|
||||
if c_type in all_structures:
|
||||
assert all_structures[c_type] == value, """Structure %s redefinition
|
||||
previous:
|
||||
%s
|
||||
---
|
||||
current:
|
||||
%s
|
||||
---""" % (c_type, all_structures[c_type], value)
|
||||
else:
|
||||
all_structures[c_type] = value
|
||||
t.generate_c_declaration(writer_top)
|
||||
except:
|
||||
print >> sys.stderr, 'type %s' % t
|
||||
print >> sys.stderr, writer.getvalue()
|
||||
traceback.print_exc(sys.stderr)
|
||||
|
||||
def generate_declarations():
|
||||
writer = codegen.CodeWriter()
|
||||
writer.public_suffix = options.suffix
|
||||
writer.write(license)
|
||||
|
||||
# all types
|
||||
for t in ptypes.get_named_types():
|
||||
if isinstance(t, ptypes.StructType):
|
||||
generate_declaration(t, writer)
|
||||
if isinstance(t, ptypes.ChannelType):
|
||||
for m in t.client_messages + t.server_messages:
|
||||
generate_declaration(m.message_type, writer)
|
||||
|
||||
content = writer.getvalue()
|
||||
write_content(options.generated_declaration_file, content,
|
||||
options.keep_identical_file)
|
||||
|
||||
if options.generated_declaration_file:
|
||||
generate_declarations()
|
||||
|
||||
writer.public_suffix = options.suffix
|
||||
|
||||
writer.writeln("/* this is a file autogenerated by spice_codegen.py */")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user