forked from Imagelibrary/seL4
This commit also converts our own copyright headers to directly use SPDX, but leaves all other copyright header intact, only adding the SPDX ident. As far as possible this commit also merges multiple Data61 copyright statements/headers into one for consistency.
143 lines
4.8 KiB
Python
Executable File
143 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
|
|
#
|
|
# SPDX-License-Identifier: BSD-2-Clause
|
|
#
|
|
|
|
"""
|
|
Script to generate a c header file containing function prototypes and
|
|
doxygen comments from a given interface defined in an xml file.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import operator
|
|
import logging
|
|
import itertools
|
|
from libsel4_tools import syscall_stub_gen
|
|
from lxml import etree
|
|
|
|
# Word size is required by the syscall_stub_gen library, but won't affect the output
|
|
WORD_SIZE = 32
|
|
FN_DECL_PREFIX = "static inline"
|
|
DEFAULT_RETURN_TYPE = "int"
|
|
|
|
|
|
def init_all_types():
|
|
"""
|
|
Return an array of all c types involved in the sel4 interface
|
|
"""
|
|
|
|
data_types = syscall_stub_gen.init_data_types(WORD_SIZE)
|
|
arch_types = list(itertools.chain(*syscall_stub_gen.init_arch_types(WORD_SIZE).values()))
|
|
|
|
return data_types + arch_types
|
|
|
|
|
|
def generate_prototype(interface_name, method_name, method_id, inputs, outputs, comment):
|
|
"""
|
|
Returns a string containing a commented function prototype based on its arguments
|
|
"""
|
|
|
|
prefix = FN_DECL_PREFIX
|
|
if syscall_stub_gen.generate_result_struct(interface_name, method_name, outputs):
|
|
return_type = "%s_%s_t" % (interface_name, method_name)
|
|
else:
|
|
return_type = DEFAULT_RETURN_TYPE
|
|
|
|
param_list = syscall_stub_gen.generate_param_list(inputs, outputs)
|
|
name = "%s_%s" % (interface_name, method_name)
|
|
|
|
return "%s\n%s %s %s(%s);" % (comment, prefix, return_type, name, param_list)
|
|
|
|
|
|
def gen_invocations(input_files, output_file):
|
|
"""
|
|
Given a collection of input xml files describing sel4 interfaces,
|
|
generates a c header file containing doxygen-commented function
|
|
prototypes.
|
|
"""
|
|
|
|
types = init_all_types()
|
|
|
|
for input_file in input_files:
|
|
methods, _, api = syscall_stub_gen.parse_xml_file(input_file, types)
|
|
prototypes = []
|
|
|
|
# figure out the prefix to use for an interface group id. This makes groups per arch,
|
|
# sel4_arch unique even through the interface name is the same.
|
|
prefix = None
|
|
if "arch_include" in input_file:
|
|
# extract the 2nd last path member
|
|
(path, tail) = os.path.split(os.path.dirname(input_file))
|
|
assert tail == "interfaces"
|
|
(path, prefix) = os.path.split(path)
|
|
|
|
# group the methods in each interface
|
|
for interface_name, methods in itertools.groupby(methods, lambda x: x[0]):
|
|
group_id = interface_name if prefix is None else prefix + '_' + interface_name
|
|
group_name = interface_name
|
|
output_file.write("/**\n * @defgroup %s %s\n * @{\n */\n\n" % (group_id, group_name))
|
|
output_file.write("/** @} */\n")
|
|
for (interface_name, method_name, method_id, inputs, outputs, _, comment) in methods:
|
|
prototype = "/**\n * @addtogroup %s %s\n * @{\n */\n\n" % (group_id, group_name)
|
|
prototype += generate_prototype(interface_name,
|
|
method_name, method_id, inputs, outputs, comment)
|
|
prototype += "/** @} */\n"
|
|
prototypes.append(prototype)
|
|
|
|
prototypes.sort()
|
|
|
|
output_file.write("/**\n * @defgroup %s %s\n * @{\n */\n\n" % (api.name, api.name))
|
|
|
|
for prototype in prototypes:
|
|
output_file.write(prototype)
|
|
output_file.write("\n\n")
|
|
|
|
output_file.write("/** @} */\n")
|
|
|
|
|
|
def process_args():
|
|
usage_str = "%(prog)s [OPTIONS] [FILES]"
|
|
|
|
parser = argparse.ArgumentParser(description='Generates doxygen-annotated header '
|
|
'containing object invocation prototypes',
|
|
usage=usage_str)
|
|
|
|
parser.add_argument("-o", "--output", dest="output", default="/dev/stdout",
|
|
type=str,
|
|
help="Output file to write stub to. (default: %(default)s).")
|
|
parser.add_argument("files", metavar="FILES", nargs="+", type=str,
|
|
help="Input XML files.")
|
|
|
|
parser.add_argument("-d", "--dtd", nargs="?", type=str,
|
|
help="DTD xml schema to validate input files against")
|
|
|
|
return parser
|
|
|
|
|
|
def main():
|
|
parser = process_args()
|
|
args = parser.parse_args()
|
|
|
|
if args.dtd is not None:
|
|
dtd = etree.DTD(args.dtd)
|
|
for f in args.files:
|
|
xml = etree.parse(f)
|
|
if not dtd.validate(xml):
|
|
logging.error("Failed to validate %s against %s" % (f, args.dtd))
|
|
logging.error(dtd.error_log)
|
|
return -1
|
|
|
|
if not os.path.exists(os.path.dirname(args.output)):
|
|
os.makedirs(os.path.dirname(args.output))
|
|
|
|
with open(args.output, "w") as output:
|
|
gen_invocations(args.files, output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|