From c09626cd6306239bc473aaf73a2030d5e56699b8 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 3 Sep 2020 11:36:57 +0100 Subject: libcamera: Move Header generation utilities to utils Move the GPL2 utilities which handle generation of controls, formats and the top level libcamera header to the utils subtree. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Reviewed-by: Paul Elder --- include/libcamera/gen-formats.py | 118 -------------------------- include/libcamera/gen-header.sh | 32 -------- include/libcamera/meson.build | 6 -- src/libcamera/gen-controls.py | 173 --------------------------------------- src/libcamera/meson.build | 2 - utils/gen-controls.py | 173 +++++++++++++++++++++++++++++++++++++++ utils/gen-formats.py | 118 ++++++++++++++++++++++++++ utils/gen-header.sh | 32 ++++++++ utils/meson.build | 5 ++ 9 files changed, 328 insertions(+), 331 deletions(-) delete mode 100755 include/libcamera/gen-formats.py delete mode 100755 include/libcamera/gen-header.sh delete mode 100755 src/libcamera/gen-controls.py create mode 100755 utils/gen-controls.py create mode 100755 utils/gen-formats.py create mode 100755 utils/gen-header.sh diff --git a/include/libcamera/gen-formats.py b/include/libcamera/gen-formats.py deleted file mode 100755 index 60dcecc3..00000000 --- a/include/libcamera/gen-formats.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2020, Google Inc. -# -# Author: Laurent Pinchart -# -# gen-formats.py - Generate formats definitions from YAML - -import argparse -import re -import string -import sys -import yaml - - -class DRMFourCC(object): - format_regex = re.compile(r"#define (DRM_FORMAT_[A-Z0-9_]+)[ \t]+fourcc_code\(('.', '.', '.', '.')\)") - mod_vendor_regex = re.compile(r"#define DRM_FORMAT_MOD_VENDOR_([A-Z0-9_]+)[ \t]+([0-9a-fA-Fx]+)") - mod_regex = re.compile(r"#define ([A-Za-z0-9_]+)[ \t]+fourcc_mod_code\(([A-Z0-9_]+), ([0-9a-fA-Fx]+)\)") - - def __init__(self, filename): - self.formats = {} - self.vendors = {} - self.mods = {} - - for line in open(filename, 'rb').readlines(): - line = line.decode('utf-8') - - match = DRMFourCC.format_regex.match(line) - if match: - format, fourcc = match.groups() - self.formats[format] = fourcc - continue - - match = DRMFourCC.mod_vendor_regex.match(line) - if match: - vendor, value = match.groups() - self.vendors[vendor] = int(value, 0) - continue - - match = DRMFourCC.mod_regex.match(line) - if match: - mod, vendor, value = match.groups() - self.mods[mod] = (vendor, int(value, 0)) - continue - - def fourcc(self, name): - return self.formats[name] - - def mod(self, name): - vendor, value = self.mods[name] - return self.vendors[vendor], value - - -def generate_h(formats, drm_fourcc): - template = string.Template('constexpr PixelFormat ${name}{ __fourcc(${fourcc}), __mod(${mod}) };') - - fmts = [] - - for format in formats: - name, format = format.popitem() - - data = { - 'name': name, - 'fourcc': drm_fourcc.fourcc(format['fourcc']), - 'mod': '0, 0', - } - - mod = format.get('mod') - if mod: - data['mod'] = '%u, %u' % drm_fourcc.mod(mod) - - fmts.append(template.substitute(data)) - - return {'formats': '\n'.join(fmts)} - - -def fill_template(template, data): - - template = open(template, 'rb').read() - template = template.decode('utf-8') - template = string.Template(template) - return template.substitute(data) - - -def main(argv): - - # Parse command line arguments - parser = argparse.ArgumentParser() - parser.add_argument('-o', dest='output', metavar='file', type=str, - help='Output file name. Defaults to standard output if not specified.') - parser.add_argument('input', type=str, - help='Input file name.') - parser.add_argument('template', type=str, - help='Template file name.') - parser.add_argument('drm_fourcc', type=str, - help='Path to drm_fourcc.h.') - args = parser.parse_args(argv[1:]) - - data = open(args.input, 'rb').read() - formats = yaml.safe_load(data)['formats'] - drm_fourcc = DRMFourCC(args.drm_fourcc) - - data = generate_h(formats, drm_fourcc) - data = fill_template(args.template, data) - - if args.output: - output = open(args.output, 'wb') - output.write(data.encode('utf-8')) - output.close() - else: - sys.stdout.write(data) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/include/libcamera/gen-header.sh b/include/libcamera/gen-header.sh deleted file mode 100755 index fcb9c5e1..00000000 --- a/include/libcamera/gen-header.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -src_dir="$1" -dst_file="$2" - -cat < "$dst_file" -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* This file is auto-generated, do not edit! */ -/* - * Copyright (C) 2018-2019, Google Inc. - * - * libcamera.h - libcamera public API - */ -#ifndef __LIBCAMERA_LIBCAMERA_H__ -#define __LIBCAMERA_LIBCAMERA_H__ - -EOF - -headers=$(for header in "$src_dir"/*.h "$src_dir"/*.h.in ; do - header=$(basename "$header") - header="${header%.in}" - echo "$header" -done | sort) - -for header in $headers ; do - echo "#include " >> "$dst_file" -done - -cat <> "$dst_file" - -#endif /* __LIBCAMERA_LIBCAMERA_H__ */ -EOF diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index cdb8e037..692931a5 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -34,8 +34,6 @@ install_headers(libcamera_public_headers, # # control_ids.h and property_ids.h -gen_controls = files('../../src/libcamera/gen-controls.py') - control_source_files = [ 'control_ids', 'property_ids', @@ -57,8 +55,6 @@ endforeach libcamera_public_headers += control_headers # formats.h -gen_formats = files('gen-formats.py') - formats_h = custom_target('formats_h', input : files( '../../src/libcamera/formats.yaml', @@ -72,8 +68,6 @@ formats_h = custom_target('formats_h', libcamera_public_headers += formats_h # libcamera.h -gen_header = files('gen-header.sh') - libcamera_h = custom_target('gen-header', input : 'meson.build', output : 'libcamera.h', diff --git a/src/libcamera/gen-controls.py b/src/libcamera/gen-controls.py deleted file mode 100755 index 87c3d52a..00000000 --- a/src/libcamera/gen-controls.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (C) 2019, Google Inc. -# -# Author: Laurent Pinchart -# -# gen-controls.py - Generate control definitions from YAML - -import argparse -import string -import sys -import yaml - - -def snake_case(s): - return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_') - - -def format_description(description): - description = description.strip('\n').split('\n') - description[0] = '\\brief ' + description[0] - return '\n'.join([(line and ' * ' or ' *') + line for line in description]) - - -def generate_cpp(controls): - enum_doc_start_template = string.Template('''/** - * \\enum ${name}Values - * \\brief Supported ${name} values''') - enum_doc_value_template = string.Template(''' * \\var ${name}Values::${value} -${description}''') - doc_template = string.Template('''/** - * \\var ${name} -${description} - */''') - def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, "${name}");') - - ctrls_doc = [] - ctrls_def = [] - ctrls_map = [] - - for ctrl in controls: - name, ctrl = ctrl.popitem() - id_name = snake_case(name).upper() - - ctrl_type = ctrl['type'] - if ctrl_type == 'string': - ctrl_type = 'std::string' - elif ctrl.get('size'): - ctrl_type = 'Span' % ctrl_type - - info = { - 'name': name, - 'type': ctrl_type, - 'description': format_description(ctrl['description']), - 'id_name': id_name, - } - - enum = ctrl.get('enum') - if enum: - enum_doc = [] - enum_doc.append(enum_doc_start_template.substitute(info)) - - for entry in enum: - value_info = { - 'name' : name, - 'value': entry['name'], - 'description': format_description(entry['description']), - } - enum_doc.append(enum_doc_value_template.substitute(value_info)) - - enum_doc = '\n *\n'.join(enum_doc) - enum_doc += '\n */' - ctrls_doc.append(enum_doc) - - ctrls_doc.append(doc_template.substitute(info)) - ctrls_def.append(def_template.substitute(info)) - ctrls_map.append('\t{ ' + id_name + ', &' + name + ' },') - - return { - 'controls_doc': '\n\n'.join(ctrls_doc), - 'controls_def': '\n'.join(ctrls_def), - 'controls_map': '\n'.join(ctrls_map), - } - - -def generate_h(controls): - enum_template_start = string.Template('''enum ${name}Values {''') - enum_value_template = string.Template('''\t${name} = ${value},''') - template = string.Template('''extern const Control<${type}> ${name};''') - - ctrls = [] - ids = [] - id_value = 1 - - for ctrl in controls: - name, ctrl = ctrl.popitem() - id_name = snake_case(name).upper() - - ids.append('\t' + id_name + ' = ' + str(id_value) + ',') - - ctrl_type = ctrl['type'] - if ctrl_type == 'string': - ctrl_type = 'std::string' - elif ctrl.get('size'): - ctrl_type = 'Span' % ctrl_type - - info = { - 'name': name, - 'type': ctrl_type, - } - - enum = ctrl.get('enum') - if enum: - ctrls.append(enum_template_start.substitute(info)) - - for entry in enum: - value_info = { - 'name': entry['name'], - 'value': entry['value'], - } - ctrls.append(enum_value_template.substitute(value_info)) - ctrls.append("};") - - ctrls.append(template.substitute(info)) - id_value += 1 - - return {'ids': '\n'.join(ids), 'controls': '\n'.join(ctrls)} - - -def fill_template(template, data): - - template = open(template, 'rb').read() - template = template.decode('utf-8') - template = string.Template(template) - return template.substitute(data) - - -def main(argv): - - # Parse command line arguments - parser = argparse.ArgumentParser() - parser.add_argument('-o', dest='output', metavar='file', type=str, - help='Output file name. Defaults to standard output if not specified.') - parser.add_argument('input', type=str, - help='Input file name.') - parser.add_argument('template', type=str, - help='Template file name.') - args = parser.parse_args(argv[1:]) - - data = open(args.input, 'rb').read() - controls = yaml.safe_load(data)['controls'] - - if args.template.endswith('.cpp.in'): - data = generate_cpp(controls) - elif args.template.endswith('.h.in'): - data = generate_h(controls) - else: - raise RuntimeError('Unknown template type') - - data = fill_template(args.template, data) - - if args.output: - output = open(args.output, 'wb') - output.write(data.encode('utf-8')) - output.close() - else: - sys.stdout.write(data) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 0e6ecf50..d63dacd5 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -77,8 +77,6 @@ if libudev.found() ]) endif -gen_controls = files('gen-controls.py') - control_sources = [] foreach source : control_source_files diff --git a/utils/gen-controls.py b/utils/gen-controls.py new file mode 100755 index 00000000..87c3d52a --- /dev/null +++ b/utils/gen-controls.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2019, Google Inc. +# +# Author: Laurent Pinchart +# +# gen-controls.py - Generate control definitions from YAML + +import argparse +import string +import sys +import yaml + + +def snake_case(s): + return ''.join([c.isupper() and ('_' + c) or c for c in s]).strip('_') + + +def format_description(description): + description = description.strip('\n').split('\n') + description[0] = '\\brief ' + description[0] + return '\n'.join([(line and ' * ' or ' *') + line for line in description]) + + +def generate_cpp(controls): + enum_doc_start_template = string.Template('''/** + * \\enum ${name}Values + * \\brief Supported ${name} values''') + enum_doc_value_template = string.Template(''' * \\var ${name}Values::${value} +${description}''') + doc_template = string.Template('''/** + * \\var ${name} +${description} + */''') + def_template = string.Template('extern const Control<${type}> ${name}(${id_name}, "${name}");') + + ctrls_doc = [] + ctrls_def = [] + ctrls_map = [] + + for ctrl in controls: + name, ctrl = ctrl.popitem() + id_name = snake_case(name).upper() + + ctrl_type = ctrl['type'] + if ctrl_type == 'string': + ctrl_type = 'std::string' + elif ctrl.get('size'): + ctrl_type = 'Span' % ctrl_type + + info = { + 'name': name, + 'type': ctrl_type, + 'description': format_description(ctrl['description']), + 'id_name': id_name, + } + + enum = ctrl.get('enum') + if enum: + enum_doc = [] + enum_doc.append(enum_doc_start_template.substitute(info)) + + for entry in enum: + value_info = { + 'name' : name, + 'value': entry['name'], + 'description': format_description(entry['description']), + } + enum_doc.append(enum_doc_value_template.substitute(value_info)) + + enum_doc = '\n *\n'.join(enum_doc) + enum_doc += '\n */' + ctrls_doc.append(enum_doc) + + ctrls_doc.append(doc_template.substitute(info)) + ctrls_def.append(def_template.substitute(info)) + ctrls_map.append('\t{ ' + id_name + ', &' + name + ' },') + + return { + 'controls_doc': '\n\n'.join(ctrls_doc), + 'controls_def': '\n'.join(ctrls_def), + 'controls_map': '\n'.join(ctrls_map), + } + + +def generate_h(controls): + enum_template_start = string.Template('''enum ${name}Values {''') + enum_value_template = string.Template('''\t${name} = ${value},''') + template = string.Template('''extern const Control<${type}> ${name};''') + + ctrls = [] + ids = [] + id_value = 1 + + for ctrl in controls: + name, ctrl = ctrl.popitem() + id_name = snake_case(name).upper() + + ids.append('\t' + id_name + ' = ' + str(id_value) + ',') + + ctrl_type = ctrl['type'] + if ctrl_type == 'string': + ctrl_type = 'std::string' + elif ctrl.get('size'): + ctrl_type = 'Span' % ctrl_type + + info = { + 'name': name, + 'type': ctrl_type, + } + + enum = ctrl.get('enum') + if enum: + ctrls.append(enum_template_start.substitute(info)) + + for entry in enum: + value_info = { + 'name': entry['name'], + 'value': entry['value'], + } + ctrls.append(enum_value_template.substitute(value_info)) + ctrls.append("};") + + ctrls.append(template.substitute(info)) + id_value += 1 + + return {'ids': '\n'.join(ids), 'controls': '\n'.join(ctrls)} + + +def fill_template(template, data): + + template = open(template, 'rb').read() + template = template.decode('utf-8') + template = string.Template(template) + return template.substitute(data) + + +def main(argv): + + # Parse command line arguments + parser = argparse.ArgumentParser() + parser.add_argument('-o', dest='output', metavar='file', type=str, + help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('input', type=str, + help='Input file name.') + parser.add_argument('template', type=str, + help='Template file name.') + args = parser.parse_args(argv[1:]) + + data = open(args.input, 'rb').read() + controls = yaml.safe_load(data)['controls'] + + if args.template.endswith('.cpp.in'): + data = generate_cpp(controls) + elif args.template.endswith('.h.in'): + data = generate_h(controls) + else: + raise RuntimeError('Unknown template type') + + data = fill_template(args.template, data) + + if args.output: + output = open(args.output, 'wb') + output.write(data.encode('utf-8')) + output.close() + else: + sys.stdout.write(data) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/utils/gen-formats.py b/utils/gen-formats.py new file mode 100755 index 00000000..60dcecc3 --- /dev/null +++ b/utils/gen-formats.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2020, Google Inc. +# +# Author: Laurent Pinchart +# +# gen-formats.py - Generate formats definitions from YAML + +import argparse +import re +import string +import sys +import yaml + + +class DRMFourCC(object): + format_regex = re.compile(r"#define (DRM_FORMAT_[A-Z0-9_]+)[ \t]+fourcc_code\(('.', '.', '.', '.')\)") + mod_vendor_regex = re.compile(r"#define DRM_FORMAT_MOD_VENDOR_([A-Z0-9_]+)[ \t]+([0-9a-fA-Fx]+)") + mod_regex = re.compile(r"#define ([A-Za-z0-9_]+)[ \t]+fourcc_mod_code\(([A-Z0-9_]+), ([0-9a-fA-Fx]+)\)") + + def __init__(self, filename): + self.formats = {} + self.vendors = {} + self.mods = {} + + for line in open(filename, 'rb').readlines(): + line = line.decode('utf-8') + + match = DRMFourCC.format_regex.match(line) + if match: + format, fourcc = match.groups() + self.formats[format] = fourcc + continue + + match = DRMFourCC.mod_vendor_regex.match(line) + if match: + vendor, value = match.groups() + self.vendors[vendor] = int(value, 0) + continue + + match = DRMFourCC.mod_regex.match(line) + if match: + mod, vendor, value = match.groups() + self.mods[mod] = (vendor, int(value, 0)) + continue + + def fourcc(self, name): + return self.formats[name] + + def mod(self, name): + vendor, value = self.mods[name] + return self.vendors[vendor], value + + +def generate_h(formats, drm_fourcc): + template = string.Template('constexpr PixelFormat ${name}{ __fourcc(${fourcc}), __mod(${mod}) };') + + fmts = [] + + for format in formats: + name, format = format.popitem() + + data = { + 'name': name, + 'fourcc': drm_fourcc.fourcc(format['fourcc']), + 'mod': '0, 0', + } + + mod = format.get('mod') + if mod: + data['mod'] = '%u, %u' % drm_fourcc.mod(mod) + + fmts.append(template.substitute(data)) + + return {'formats': '\n'.join(fmts)} + + +def fill_template(template, data): + + template = open(template, 'rb').read() + template = template.decode('utf-8') + template = string.Template(template) + return template.substitute(data) + + +def main(argv): + + # Parse command line arguments + parser = argparse.ArgumentParser() + parser.add_argument('-o', dest='output', metavar='file', type=str, + help='Output file name. Defaults to standard output if not specified.') + parser.add_argument('input', type=str, + help='Input file name.') + parser.add_argument('template', type=str, + help='Template file name.') + parser.add_argument('drm_fourcc', type=str, + help='Path to drm_fourcc.h.') + args = parser.parse_args(argv[1:]) + + data = open(args.input, 'rb').read() + formats = yaml.safe_load(data)['formats'] + drm_fourcc = DRMFourCC(args.drm_fourcc) + + data = generate_h(formats, drm_fourcc) + data = fill_template(args.template, data) + + if args.output: + output = open(args.output, 'wb') + output.write(data.encode('utf-8')) + output.close() + else: + sys.stdout.write(data) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/utils/gen-header.sh b/utils/gen-header.sh new file mode 100755 index 00000000..fcb9c5e1 --- /dev/null +++ b/utils/gen-header.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +src_dir="$1" +dst_file="$2" + +cat < "$dst_file" +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* This file is auto-generated, do not edit! */ +/* + * Copyright (C) 2018-2019, Google Inc. + * + * libcamera.h - libcamera public API + */ +#ifndef __LIBCAMERA_LIBCAMERA_H__ +#define __LIBCAMERA_LIBCAMERA_H__ + +EOF + +headers=$(for header in "$src_dir"/*.h "$src_dir"/*.h.in ; do + header=$(basename "$header") + header="${header%.in}" + echo "$header" +done | sort) + +for header in $headers ; do + echo "#include " >> "$dst_file" +done + +cat <> "$dst_file" + +#endif /* __LIBCAMERA_LIBCAMERA_H__ */ +EOF diff --git a/utils/meson.build b/utils/meson.build index c3cd9d69..ef5507b1 100644 --- a/utils/meson.build +++ b/utils/meson.build @@ -1,3 +1,8 @@ # SPDX-License-Identifier: CC0-1.0 subdir('ipu3') + +## Code generation +gen_controls = files('gen-controls.py') +gen_formats = files('gen-formats.py') +gen_header = files('gen-header.sh') -- cgit v1.2.1