Message ID | 20220506145414.99039-6-tomi.valkeinen@ideasonboard.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Tomi, Thank you for the patch. On Fri, May 06, 2022 at 05:54:12PM +0300, Tomi Valkeinen wrote: > Generate enums for controls from control_ids.yaml. The generator script > has some heuristics to generate nicer enum names. E.g. instead of having > "LensShadingMapMode.LensShadingMapModeOff" we get > "LensShadingMapMode.Off". This heuristics may need to be updated when > the yaml file is changed or new controls are added. > > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> > --- > src/py/libcamera/gen-py-control-enums.py | 95 +++++++++++++++++++++++ > src/py/libcamera/meson.build | 12 +++ > src/py/libcamera/pyenums_generated.cpp.in | 21 +++++ > src/py/libcamera/pymain.cpp | 2 + > 4 files changed, 130 insertions(+) > create mode 100755 src/py/libcamera/gen-py-control-enums.py > create mode 100644 src/py/libcamera/pyenums_generated.cpp.in > > diff --git a/src/py/libcamera/gen-py-control-enums.py b/src/py/libcamera/gen-py-control-enums.py > new file mode 100755 > index 00000000..dcc28b1a > --- /dev/null > +++ b/src/py/libcamera/gen-py-control-enums.py > @@ -0,0 +1,95 @@ > +#!/usr/bin/env python3 > +# SPDX-License-Identifier: GPL-2.0-or-later > +# > +# Generate Python bindings enums for controls from YAML > + > +import argparse > +import string > +import sys > +import yaml > + > + > +def find_common_prefix(strings): > + prefix = strings[0] > + > + for string in strings[1:]: > + while string[:len(prefix)] != prefix and prefix: > + prefix = prefix[:len(prefix) - 1] > + if not prefix: > + break > + > + return prefix > + > + > +def generate_py(controls): > + out = '' > + > + for ctrl in controls: > + name, ctrl = ctrl.popitem() > + > + enum = ctrl.get('enum') > + if not enum: > + continue > + > + if ctrl.get('draft'): > + ns = 'libcamera::controls::draft::' > + else: > + ns = 'libcamera::controls::' > + > + cpp_enum = name + 'Enum' > + > + out += '\tpy::enum_<{}{}>(m, \"{}\")\n'.format(ns, cpp_enum, name) > + > + if name == 'LensShadingMapMode': > + prefix = 'LensShadingMapMode' > + else: > + prefix = find_common_prefix([e['name'] for e in enum]) > + > + for entry in enum: > + cpp_enum = entry['name'] > + py_enum = entry['name'][len(prefix):] > + > + out += '\t\t.value(\"{}\", {}{})\n'.format(py_enum, ns, cpp_enum) > + > + out += '\t;\n' > + > + return {'enums': out} > + > + > +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'] > + > + data = generate_py(controls) > + > + 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/py/libcamera/meson.build b/src/py/libcamera/meson.build > index e4abc34a..f4c7590c 100644 > --- a/src/py/libcamera/meson.build > +++ b/src/py/libcamera/meson.build > @@ -17,6 +17,18 @@ pycamera_sources = files([ > 'pymain.cpp', > ]) > > +gen_input_files = [ > + meson.project_source_root() / 'src' / 'libcamera' / 'control_ids.yaml', > + 'pyenums_generated.cpp.in' You can add a comma at the end of the line. No need to resend for that, it can be fixed when applying. > +] > + > +generated_sources = custom_target('py_gen_controls', > + input : gen_input_files, > + output : ['pyenums_generated.cpp'], > + command : ['gen-py-control-enums.py', '-o', '@OUTPUT@', '@INPUT@']) > + > +pycamera_sources += generated_sources > + > pycamera_deps = [ > libcamera_public, > py3_dep, > diff --git a/src/py/libcamera/pyenums_generated.cpp.in b/src/py/libcamera/pyenums_generated.cpp.in > new file mode 100644 > index 00000000..96daf257 > --- /dev/null > +++ b/src/py/libcamera/pyenums_generated.cpp.in > @@ -0,0 +1,21 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2021, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > + * > + * Python bindings > + * > + * This file is auto-generated. Do not edit. > + */ > + > +#include <libcamera/libcamera.h> > + > +#include <pybind11/smart_holder.h> > + > +namespace py = pybind11; > + > +using namespace libcamera; > + > +void init_pyenums_generated(py::module& m) > +{ > +${enums} > +} > diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp > index 8c3be8f4..aff672aa 100644 > --- a/src/py/libcamera/pymain.cpp > +++ b/src/py/libcamera/pymain.cpp > @@ -131,10 +131,12 @@ static void handleRequestCompleted(Request *req) > } > > void init_pyenums(py::module &m); > +void init_pyenums_generated(py::module &m); > > PYBIND11_MODULE(_libcamera, m) > { > init_pyenums(m); > + init_pyenums_generated(m); > > /* Forward declarations */ > >
diff --git a/src/py/libcamera/gen-py-control-enums.py b/src/py/libcamera/gen-py-control-enums.py new file mode 100755 index 00000000..dcc28b1a --- /dev/null +++ b/src/py/libcamera/gen-py-control-enums.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Generate Python bindings enums for controls from YAML + +import argparse +import string +import sys +import yaml + + +def find_common_prefix(strings): + prefix = strings[0] + + for string in strings[1:]: + while string[:len(prefix)] != prefix and prefix: + prefix = prefix[:len(prefix) - 1] + if not prefix: + break + + return prefix + + +def generate_py(controls): + out = '' + + for ctrl in controls: + name, ctrl = ctrl.popitem() + + enum = ctrl.get('enum') + if not enum: + continue + + if ctrl.get('draft'): + ns = 'libcamera::controls::draft::' + else: + ns = 'libcamera::controls::' + + cpp_enum = name + 'Enum' + + out += '\tpy::enum_<{}{}>(m, \"{}\")\n'.format(ns, cpp_enum, name) + + if name == 'LensShadingMapMode': + prefix = 'LensShadingMapMode' + else: + prefix = find_common_prefix([e['name'] for e in enum]) + + for entry in enum: + cpp_enum = entry['name'] + py_enum = entry['name'][len(prefix):] + + out += '\t\t.value(\"{}\", {}{})\n'.format(py_enum, ns, cpp_enum) + + out += '\t;\n' + + return {'enums': out} + + +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'] + + data = generate_py(controls) + + 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/py/libcamera/meson.build b/src/py/libcamera/meson.build index e4abc34a..f4c7590c 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -17,6 +17,18 @@ pycamera_sources = files([ 'pymain.cpp', ]) +gen_input_files = [ + meson.project_source_root() / 'src' / 'libcamera' / 'control_ids.yaml', + 'pyenums_generated.cpp.in' +] + +generated_sources = custom_target('py_gen_controls', + input : gen_input_files, + output : ['pyenums_generated.cpp'], + command : ['gen-py-control-enums.py', '-o', '@OUTPUT@', '@INPUT@']) + +pycamera_sources += generated_sources + pycamera_deps = [ libcamera_public, py3_dep, diff --git a/src/py/libcamera/pyenums_generated.cpp.in b/src/py/libcamera/pyenums_generated.cpp.in new file mode 100644 index 00000000..96daf257 --- /dev/null +++ b/src/py/libcamera/pyenums_generated.cpp.in @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> + * + * Python bindings + * + * This file is auto-generated. Do not edit. + */ + +#include <libcamera/libcamera.h> + +#include <pybind11/smart_holder.h> + +namespace py = pybind11; + +using namespace libcamera; + +void init_pyenums_generated(py::module& m) +{ +${enums} +} diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index 8c3be8f4..aff672aa 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -131,10 +131,12 @@ static void handleRequestCompleted(Request *req) } void init_pyenums(py::module &m); +void init_pyenums_generated(py::module &m); PYBIND11_MODULE(_libcamera, m) { init_pyenums(m); + init_pyenums_generated(m); /* Forward declarations */