summaryrefslogtreecommitdiffstats
path: root/host/libs/virglrenderer/gen_entries.py
diff options
context:
space:
mode:
Diffstat (limited to 'host/libs/virglrenderer/gen_entries.py')
-rwxr-xr-xhost/libs/virglrenderer/gen_entries.py317
1 files changed, 317 insertions, 0 deletions
diff --git a/host/libs/virglrenderer/gen_entries.py b/host/libs/virglrenderer/gen_entries.py
new file mode 100755
index 000000000..fbfdb4daf
--- /dev/null
+++ b/host/libs/virglrenderer/gen_entries.py
@@ -0,0 +1,317 @@
+#!/usr/bin/env python
+
+# Copyright 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Utility functions used to parse a list of DLL entry points.
+# Expected format:
+#
+# <empty-line> -> ignored
+# #<comment> -> ignored
+# %<verbatim> -> verbatim output for header files.
+# !<prefix> -> prefix name for header files.
+# <return-type> <function-name> <signature> ; -> entry point declaration.
+#
+# Anything else is an error.
+
+import re
+import sys
+import argparse
+
+re_func = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)\((.*)\);$""")
+re_param = re.compile(r"""^(.*[\* ])([A-Za-z_][A-Za-z0-9_]*)$""")
+
+class Entry:
+ """Small class used to model a single DLL entry point."""
+ def __init__(self, func_name, return_type, parameters):
+ """Initialize Entry instance. |func_name| is the function name,
+ |return_type| its return type, and |parameters| is a list of
+ (type,name) tuples from the entry's signature.
+ """
+ self.func_name = func_name
+ self.return_type = return_type
+ self.parameters = ""
+ self.vartypes = []
+ self.varnames = []
+ self.call = ""
+ comma = ""
+ for param in parameters:
+ self.vartypes.append(param[0])
+ self.varnames.append(param[1])
+ self.parameters += "%s%s %s" % (comma, param[0], param[1])
+ self.call += "%s%s" % (comma, param[1])
+ comma = ", "
+
+def banner_command(argv):
+ """Return sanitized command-line description.
+ |argv| must be a list of command-line parameters, e.g. sys.argv.
+ Return a string corresponding to the command, with platform-specific
+ paths removed."""
+
+ # Remove path from first parameter
+ argv = argv[:]
+ argv[0] = "host/commands/gen-entries.py"
+ return ' '.join(argv)
+
+def parse_entries_file(lines):
+ """Parse an .entries file and return a tuple of:
+ entries: list of Entry instances from the file.
+ prefix_name: prefix name from the file, or None.
+ verbatim: list of verbatim lines from the file.
+ errors: list of errors in the file, prefixed by line number.
+ """
+ entries = []
+ verbatim = []
+ errors = []
+ lineno = 0
+ prefix_name = None
+ for line in lines:
+ lineno += 1
+ line = line.strip()
+ if len(line) == 0: # Ignore empty lines
+ continue
+ if line[0] == '#': # Ignore comments
+ continue
+ if line[0] == '!': # Prefix name
+ prefix_name = line[1:]
+ continue
+ if line[0] == '%': # Verbatim line copy
+ verbatim.append(line[1:])
+ continue
+ # Must be a function signature.
+ m = re_func.match(line)
+ if not m:
+ errors.append("%d: '%s'" % (lineno, line))
+ continue
+
+ return_type, func_name, parameters = m.groups()
+ return_type = return_type.strip()
+ parameters = parameters.strip()
+ params = []
+ failure = False
+ if parameters != "void":
+ for parameter in parameters.split(','):
+ parameter = parameter.strip()
+ m = re_param.match(parameter)
+ if not m:
+ errors.append("%d: parameter '%s'" % (lineno, parameter))
+ failure = True
+ break
+ else:
+ param_type, param_name = m.groups()
+ params.append((param_type.strip(), param_name.strip()))
+
+ if not failure:
+ entries.append(Entry(func_name, return_type, params))
+
+ return (entries, prefix_name, verbatim, errors)
+
+
+def gen_functions_header(entries, prefix_name, verbatim, filename, with_args):
+ """Generate a C header containing a macro listing all entry points.
+ |entries| is a list of Entry instances.
+ |prefix_name| is a prefix-name, it will be converted to upper-case.
+ |verbatim| is a list of verbatim lines that must appear before the
+ macro declaration. Useful to insert #include <> statements.
+ |filename| is the name of the original file.
+ """
+ prefix_name = prefix_name.upper()
+
+ print "// Auto-generated with: %s" % banner_command(sys.argv)
+ print "// DO NOT EDIT THIS FILE"
+ print ""
+ print "#ifndef %s_FUNCTIONS_H" % prefix_name
+ print "#define %s_FUNCTIONS_H" % prefix_name
+ print ""
+ for line in verbatim:
+ print line
+
+ print "#define LIST_%s_FUNCTIONS(X) \\" % prefix_name
+ for entry in entries:
+ if with_args:
+ print " X(%s, %s, (%s), (%s)) \\" % \
+ (entry.return_type, entry.func_name, entry.parameters,
+ entry.call)
+ else:
+ print " X(%s, %s, (%s)) \\" % \
+ (entry.return_type, entry.func_name, entry.parameters)
+
+ print ""
+ print ""
+ print "#endif // %s_FUNCTIONS_H" % prefix_name
+
+def gen_dll_wrapper(entries, prefix_name, verbatim, filename):
+ """Generate a C source file that contains functions that act as wrappers
+ for entry points located in another shared library. This allows the
+ code that calls these functions to perform lazy-linking to system
+ libraries.
+ |entries|, |prefix_name|, |verbatim| and |filename| are the same as
+ for gen_functions_header() above.
+ """
+ upper_name = prefix_name.upper()
+
+ ENTRY_PREFIX = "__dll_"
+
+ print "// Auto-generated with: %s" % banner_command(sys.argv)
+ print "// DO NOT EDIT THIS FILE"
+ print ""
+ print "#include <dlfcn.h>"
+ for line in verbatim:
+ print line
+
+ print ""
+ print "///"
+ print "/// W R A P P E R P O I N T E R S"
+ print "///"
+ print ""
+ for entry in entries:
+ ptr_name = ENTRY_PREFIX + entry.func_name
+ print "static %s (*%s)(%s) = 0;" % \
+ (entry.return_type, ptr_name, entry.parameters)
+
+ print ""
+ print "///"
+ print "/// W R A P P E R F U N C T I O N S"
+ print "///"
+ print ""
+
+ for entry in entries:
+ print "%s %s(%s) {" % \
+ (entry.return_type, entry.func_name, entry.parameters)
+ ptr_name = ENTRY_PREFIX + entry.func_name
+ if entry.return_type != "void":
+ print " return %s(%s);" % (ptr_name, entry.call)
+ else:
+ print " %s(%s);" % (ptr_name, entry.call)
+ print "}\n"
+
+ print ""
+ print "///"
+ print "/// I N I T I A L I Z A T I O N F U N C T I O N"
+ print "///"
+ print ""
+
+ print "int %s_dynlink_init(void* lib) {" % prefix_name
+ for entry in entries:
+ ptr_name = ENTRY_PREFIX + entry.func_name
+ print " %s = (%s(*)(%s))dlsym(lib, \"%s\");" % \
+ (ptr_name,
+ entry.return_type,
+ entry.parameters,
+ entry.func_name)
+ print " if (!%s) return -1;" % ptr_name
+ print " return 0;"
+ print "}"
+
+
+def gen_windows_def_file(entries):
+ """Generate a windows DLL .def file. |entries| is a list of Entry instances.
+ """
+ print "EXPORTS"
+ for entry in entries:
+ print " %s" % entry.func_name
+
+
+def gen_unix_sym_file(entries):
+ """Generate an ELF linker version file. |entries| is a list of Entry
+ instances.
+ """
+ print "VERSION {"
+ print "\tglobal:"
+ for entry in entries:
+ print "\t\t%s;" % entry.func_name
+ print "\tlocal:"
+ print "\t\t*;"
+ print "};"
+
+def gen_symbols(entries, underscore):
+ """Generate a list of symbols from |entries|, a list of Entry instances.
+ |underscore| is a boolean. If True, then prepend an underscore to each
+ symbol name.
+ """
+ prefix = ""
+ if underscore:
+ prefix = "_"
+ for entry in entries:
+ print "%s%s" % (prefix, entry.func_name)
+
+def parse_file(filename, lines, mode):
+ """Generate one of possible outputs from |filename|. |lines| must be a list
+ of text lines from the file, and |mode| is one of the --mode option
+ values.
+ """
+ entries, prefix_name, verbatim, errors = parse_entries_file(lines)
+ if errors:
+ for error in errors:
+ print >> sys.stderr, "ERROR: %s:%s" % (filename, error)
+ sys.exit(1)
+
+ if not prefix_name:
+ prefix_name = "unknown"
+
+ if mode == 'def':
+ gen_windows_def_file(entries)
+ elif mode == 'sym':
+ gen_unix_sym_file(entries)
+ elif mode == 'wrapper':
+ gen_dll_wrapper(entries, prefix_name, verbatim, filename)
+ elif mode == 'symbols':
+ gen_symbols(entries, False)
+ elif mode == '_symbols':
+ gen_symbols(entries, True)
+ elif mode == 'functions':
+ gen_functions_header(entries, prefix_name, verbatim, filename, False)
+ elif mode == 'funcargs':
+ gen_functions_header(entries, prefix_name, verbatim, filename, True)
+
+
+# List of valid --mode option values.
+mode_list = [
+ 'def', 'sym', 'wrapper', 'symbols', '_symbols', 'functions', 'funcargs'
+]
+
+# Argument parsing.
+parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description="""\
+A script used to parse an .entries input file containing a list of function
+declarations, and generate various output files depending on the value of
+the --mode option, which can be:
+
+ def Generate a windows DLL .def file.
+ sym Generate a Unix .so linker script.
+ wrapper Generate a C source file containing wrapper functions.
+ symbols Generate a simple list of symbols, one per line.
+ _symbols Generate a simple list of symbols, prefixed with _.
+ functions Generate a C header containing a macro listing all functions.
+ funcargs Like 'functions', but adds function call arguments to listing.
+
+""")
+parser.add_argument("--mode", help="Output mode", choices=mode_list)
+parser.add_argument("--output", help="output file")
+parser.add_argument("file", help=".entries file path")
+
+args = parser.parse_args()
+
+if not args.mode:
+ print >> sys.stderr, "ERROR: Please use --mode=<name>, see --help."
+ sys.exit(1)
+
+if args.output:
+ sys.stdout = open(args.output, "w+")
+
+if args.file == '--':
+ parse_file("<stdin>", sys.stdin, args.mode)
+else:
+ parse_file(args.file, open(args.file), args.mode)