[08/10] utils: codegen: gen-controls.py: Move helper classes to separate file
diff mbox series

Message ID 20240809005914.20662-9-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • libcamera: Improve code generation for controls
Related show

Commit Message

Laurent Pinchart Aug. 9, 2024, 12:59 a.m. UTC
The ControlEnum and Control helper classes defined in gen-controls.py
are useful for other generator scripts. Move them to a separate file to
make it possible to share them.

Extend the Python build environment to add the path to the new Python
module to PYTHONPATH, and use it when invoking the gen-controls.py
script.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 include/libcamera/meson.build |   1 +
 src/libcamera/meson.build     |   3 +-
 utils/codegen/controls.py     | 112 ++++++++++++++++++++++++++++++++++
 utils/codegen/gen-controls.py | 105 +------------------------------
 4 files changed, 116 insertions(+), 105 deletions(-)
 create mode 100644 utils/codegen/controls.py

Comments

Dan Scally Aug. 14, 2024, 10:34 p.m. UTC | #1
Hi Laurent

On 09/08/2024 01:59, Laurent Pinchart wrote:
> The ControlEnum and Control helper classes defined in gen-controls.py
> are useful for other generator scripts. Move them to a separate file to
> make it possible to share them.
>
> Extend the Python build environment to add the path to the new Python
> module to PYTHONPATH


This doesn't happen in this patch...though given they're in the same directory the import works 
anyway, so it isn't causing harm. With the commit message corrected:


Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>

> , and use it when invoking the gen-controls.py
> script.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>   include/libcamera/meson.build |   1 +
>   src/libcamera/meson.build     |   3 +-
>   utils/codegen/controls.py     | 112 ++++++++++++++++++++++++++++++++++
>   utils/codegen/gen-controls.py | 105 +------------------------------
>   4 files changed, 116 insertions(+), 105 deletions(-)
>   create mode 100644 utils/codegen/controls.py
>
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index d90a8615e52d..a969a95dbf7a 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -88,6 +88,7 @@ foreach mode, entry : controls_map
>                                        command : [gen_controls, '-o', '@OUTPUT@',
>                                                   '--mode', mode, '-t', template_file,
>                                                   '-r', ranges_file, '@INPUT@'],
> +                                     env : py_build_env,
>                                        install : true,
>                                        install_dir : libcamera_headers_install_dir)
>   endforeach
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 3fd3a87e9f95..aa9ab0291854 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -151,7 +151,8 @@ foreach mode, inout_files : controls_mode_files
>                                        output : output_file,
>                                        command : [gen_controls, '-o', '@OUTPUT@',
>                                                   '--mode', mode, '-t', template_file,
> -                                                '-r', ranges_file, '@INPUT@'])
> +                                                '-r', ranges_file, '@INPUT@'],
> +                                     env : py_build_env)
>   endforeach
>   
>   libcamera_public_sources += control_sources
> diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py
> new file mode 100644
> index 000000000000..7bafee599c80
> --- /dev/null
> +++ b/utils/codegen/controls.py
> @@ -0,0 +1,112 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2019, Google Inc.
> +#
> +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> +#
> +# Helper classes to handle source code generation for libcamera controls
> +
> +
> +class ControlEnum(object):
> +    def __init__(self, data):
> +        self.__data = data
> +
> +    @property
> +    def description(self):
> +        """The enum description"""
> +        return self.__data.get('description')
> +
> +    @property
> +    def name(self):
> +        """The enum name"""
> +        return self.__data.get('name')
> +
> +    @property
> +    def value(self):
> +        """The enum value"""
> +        return self.__data.get('value')
> +
> +
> +class Control(object):
> +    def __init__(self, name, data, vendor):
> +        self.__name = name
> +        self.__data = data
> +        self.__enum_values = None
> +        self.__size = None
> +        self.__vendor = vendor
> +
> +        enum_values = data.get('enum')
> +        if enum_values is not None:
> +            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> +
> +        size = self.__data.get('size')
> +        if size is not None:
> +            if len(size) == 0:
> +                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> +
> +            # Compute the total number of elements in the array. If any of the
> +            # array dimension is a string, the array is variable-sized.
> +            num_elems = 1
> +            for dim in size:
> +                if type(dim) is str:
> +                    num_elems = 0
> +                    break
> +
> +                dim = int(dim)
> +                if dim <= 0:
> +                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> +
> +                num_elems *= dim
> +
> +            self.__size = num_elems
> +
> +    @property
> +    def description(self):
> +        """The control description"""
> +        return self.__data.get('description')
> +
> +    @property
> +    def enum_values(self):
> +        """The enum values, if the control is an enumeration"""
> +        if self.__enum_values is None:
> +            return
> +        for enum in self.__enum_values:
> +            yield enum
> +
> +    @property
> +    def enum_values_count(self):
> +        """The number of enum values, if the control is an enumeration"""
> +        if self.__enum_values is None:
> +            return 0
> +        return len(self.__enum_values)
> +
> +    @property
> +    def is_enum(self):
> +        """Is the control an enumeration"""
> +        return self.__enum_values is not None
> +
> +    @property
> +    def vendor(self):
> +        """The vendor string, or None"""
> +        return self.__vendor
> +
> +    @property
> +    def name(self):
> +        """The control name (CamelCase)"""
> +        return self.__name
> +
> +    @property
> +    def type(self):
> +        typ = self.__data.get('type')
> +        size = self.__data.get('size')
> +
> +        if typ == 'string':
> +            return 'std::string'
> +
> +        if self.__size is None:
> +            return typ
> +
> +        if self.__size:
> +            return f"Span<const {typ}, {self.__size}>"
> +        else:
> +            return f"Span<const {typ}>"
> diff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py
> index 685ef7a00d5f..2968eb9a5d4e 100755
> --- a/utils/codegen/gen-controls.py
> +++ b/utils/codegen/gen-controls.py
> @@ -12,110 +12,7 @@ import os
>   import sys
>   import yaml
>   
> -
> -class ControlEnum(object):
> -    def __init__(self, data):
> -        self.__data = data
> -
> -    @property
> -    def description(self):
> -        """The enum description"""
> -        return self.__data.get('description')
> -
> -    @property
> -    def name(self):
> -        """The enum name"""
> -        return self.__data.get('name')
> -
> -    @property
> -    def value(self):
> -        """The enum value"""
> -        return self.__data.get('value')
> -
> -
> -class Control(object):
> -    def __init__(self, name, data, vendor):
> -        self.__name = name
> -        self.__data = data
> -        self.__enum_values = None
> -        self.__size = None
> -        self.__vendor = vendor
> -
> -        enum_values = data.get('enum')
> -        if enum_values is not None:
> -            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> -
> -        size = self.__data.get('size')
> -        if size is not None:
> -            if len(size) == 0:
> -                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> -
> -            # Compute the total number of elements in the array. If any of the
> -            # array dimension is a string, the array is variable-sized.
> -            num_elems = 1
> -            for dim in size:
> -                if type(dim) is str:
> -                    num_elems = 0
> -                    break
> -
> -                dim = int(dim)
> -                if dim <= 0:
> -                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> -
> -                num_elems *= dim
> -
> -            self.__size = num_elems
> -
> -    @property
> -    def description(self):
> -        """The control description"""
> -        return self.__data.get('description')
> -
> -    @property
> -    def enum_values(self):
> -        """The enum values, if the control is an enumeration"""
> -        if self.__enum_values is None:
> -            return
> -        for enum in self.__enum_values:
> -            yield enum
> -
> -    @property
> -    def enum_values_count(self):
> -        """The number of enum values, if the control is an enumeration"""
> -        if self.__enum_values is None:
> -            return 0
> -        return len(self.__enum_values)
> -
> -    @property
> -    def is_enum(self):
> -        """Is the control an enumeration"""
> -        return self.__enum_values is not None
> -
> -    @property
> -    def vendor(self):
> -        """The vendor string, or None"""
> -        return self.__vendor
> -
> -    @property
> -    def name(self):
> -        """The control name (CamelCase)"""
> -        return self.__name
> -
> -    @property
> -    def type(self):
> -        typ = self.__data.get('type')
> -        size = self.__data.get('size')
> -
> -        if typ == 'string':
> -            return 'std::string'
> -
> -        if self.__size is None:
> -            return typ
> -
> -        if self.__size:
> -            return f"Span<const {typ}, {self.__size}>"
> -        else:
> -            return f"Span<const {typ}>"
> +from controls import Control
>   
>   
>   def snake_case(s):
Paul Elder Aug. 15, 2024, 4:21 a.m. UTC | #2
On Fri, Aug 09, 2024 at 03:59:12AM +0300, Laurent Pinchart wrote:
> The ControlEnum and Control helper classes defined in gen-controls.py
> are useful for other generator scripts. Move them to a separate file to
> make it possible to share them.
> 
> Extend the Python build environment to add the path to the new Python

Where is the python build environment being extended?


Paul

> module to PYTHONPATH, and use it when invoking the gen-controls.py
> script.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  include/libcamera/meson.build |   1 +
>  src/libcamera/meson.build     |   3 +-
>  utils/codegen/controls.py     | 112 ++++++++++++++++++++++++++++++++++
>  utils/codegen/gen-controls.py | 105 +------------------------------
>  4 files changed, 116 insertions(+), 105 deletions(-)
>  create mode 100644 utils/codegen/controls.py
> 
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index d90a8615e52d..a969a95dbf7a 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -88,6 +88,7 @@ foreach mode, entry : controls_map
>                                       command : [gen_controls, '-o', '@OUTPUT@',
>                                                  '--mode', mode, '-t', template_file,
>                                                  '-r', ranges_file, '@INPUT@'],
> +                                     env : py_build_env,
>                                       install : true,
>                                       install_dir : libcamera_headers_install_dir)
>  endforeach
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index 3fd3a87e9f95..aa9ab0291854 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -151,7 +151,8 @@ foreach mode, inout_files : controls_mode_files
>                                       output : output_file,
>                                       command : [gen_controls, '-o', '@OUTPUT@',
>                                                  '--mode', mode, '-t', template_file,
> -                                                '-r', ranges_file, '@INPUT@'])
> +                                                '-r', ranges_file, '@INPUT@'],
> +                                     env : py_build_env)
>  endforeach
>  
>  libcamera_public_sources += control_sources
> diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py
> new file mode 100644
> index 000000000000..7bafee599c80
> --- /dev/null
> +++ b/utils/codegen/controls.py
> @@ -0,0 +1,112 @@
> +#!/usr/bin/env python3
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2019, Google Inc.
> +#
> +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> +#
> +# Helper classes to handle source code generation for libcamera controls
> +
> +
> +class ControlEnum(object):
> +    def __init__(self, data):
> +        self.__data = data
> +
> +    @property
> +    def description(self):
> +        """The enum description"""
> +        return self.__data.get('description')
> +
> +    @property
> +    def name(self):
> +        """The enum name"""
> +        return self.__data.get('name')
> +
> +    @property
> +    def value(self):
> +        """The enum value"""
> +        return self.__data.get('value')
> +
> +
> +class Control(object):
> +    def __init__(self, name, data, vendor):
> +        self.__name = name
> +        self.__data = data
> +        self.__enum_values = None
> +        self.__size = None
> +        self.__vendor = vendor
> +
> +        enum_values = data.get('enum')
> +        if enum_values is not None:
> +            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> +
> +        size = self.__data.get('size')
> +        if size is not None:
> +            if len(size) == 0:
> +                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> +
> +            # Compute the total number of elements in the array. If any of the
> +            # array dimension is a string, the array is variable-sized.
> +            num_elems = 1
> +            for dim in size:
> +                if type(dim) is str:
> +                    num_elems = 0
> +                    break
> +
> +                dim = int(dim)
> +                if dim <= 0:
> +                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> +
> +                num_elems *= dim
> +
> +            self.__size = num_elems
> +
> +    @property
> +    def description(self):
> +        """The control description"""
> +        return self.__data.get('description')
> +
> +    @property
> +    def enum_values(self):
> +        """The enum values, if the control is an enumeration"""
> +        if self.__enum_values is None:
> +            return
> +        for enum in self.__enum_values:
> +            yield enum
> +
> +    @property
> +    def enum_values_count(self):
> +        """The number of enum values, if the control is an enumeration"""
> +        if self.__enum_values is None:
> +            return 0
> +        return len(self.__enum_values)
> +
> +    @property
> +    def is_enum(self):
> +        """Is the control an enumeration"""
> +        return self.__enum_values is not None
> +
> +    @property
> +    def vendor(self):
> +        """The vendor string, or None"""
> +        return self.__vendor
> +
> +    @property
> +    def name(self):
> +        """The control name (CamelCase)"""
> +        return self.__name
> +
> +    @property
> +    def type(self):
> +        typ = self.__data.get('type')
> +        size = self.__data.get('size')
> +
> +        if typ == 'string':
> +            return 'std::string'
> +
> +        if self.__size is None:
> +            return typ
> +
> +        if self.__size:
> +            return f"Span<const {typ}, {self.__size}>"
> +        else:
> +            return f"Span<const {typ}>"
> diff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py
> index 685ef7a00d5f..2968eb9a5d4e 100755
> --- a/utils/codegen/gen-controls.py
> +++ b/utils/codegen/gen-controls.py
> @@ -12,110 +12,7 @@ import os
>  import sys
>  import yaml
>  
> -
> -class ControlEnum(object):
> -    def __init__(self, data):
> -        self.__data = data
> -
> -    @property
> -    def description(self):
> -        """The enum description"""
> -        return self.__data.get('description')
> -
> -    @property
> -    def name(self):
> -        """The enum name"""
> -        return self.__data.get('name')
> -
> -    @property
> -    def value(self):
> -        """The enum value"""
> -        return self.__data.get('value')
> -
> -
> -class Control(object):
> -    def __init__(self, name, data, vendor):
> -        self.__name = name
> -        self.__data = data
> -        self.__enum_values = None
> -        self.__size = None
> -        self.__vendor = vendor
> -
> -        enum_values = data.get('enum')
> -        if enum_values is not None:
> -            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> -
> -        size = self.__data.get('size')
> -        if size is not None:
> -            if len(size) == 0:
> -                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> -
> -            # Compute the total number of elements in the array. If any of the
> -            # array dimension is a string, the array is variable-sized.
> -            num_elems = 1
> -            for dim in size:
> -                if type(dim) is str:
> -                    num_elems = 0
> -                    break
> -
> -                dim = int(dim)
> -                if dim <= 0:
> -                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> -
> -                num_elems *= dim
> -
> -            self.__size = num_elems
> -
> -    @property
> -    def description(self):
> -        """The control description"""
> -        return self.__data.get('description')
> -
> -    @property
> -    def enum_values(self):
> -        """The enum values, if the control is an enumeration"""
> -        if self.__enum_values is None:
> -            return
> -        for enum in self.__enum_values:
> -            yield enum
> -
> -    @property
> -    def enum_values_count(self):
> -        """The number of enum values, if the control is an enumeration"""
> -        if self.__enum_values is None:
> -            return 0
> -        return len(self.__enum_values)
> -
> -    @property
> -    def is_enum(self):
> -        """Is the control an enumeration"""
> -        return self.__enum_values is not None
> -
> -    @property
> -    def vendor(self):
> -        """The vendor string, or None"""
> -        return self.__vendor
> -
> -    @property
> -    def name(self):
> -        """The control name (CamelCase)"""
> -        return self.__name
> -
> -    @property
> -    def type(self):
> -        typ = self.__data.get('type')
> -        size = self.__data.get('size')
> -
> -        if typ == 'string':
> -            return 'std::string'
> -
> -        if self.__size is None:
> -            return typ
> -
> -        if self.__size:
> -            return f"Span<const {typ}, {self.__size}>"
> -        else:
> -            return f"Span<const {typ}>"
> +from controls import Control
>  
>  
>  def snake_case(s):
> -- 
> Regards,
> 
> Laurent Pinchart
>
Paul Elder Aug. 15, 2024, 4:34 a.m. UTC | #3
On Thu, Aug 15, 2024 at 01:21:02PM +0900, Paul Elder wrote:
> On Fri, Aug 09, 2024 at 03:59:12AM +0300, Laurent Pinchart wrote:
> > The ControlEnum and Control helper classes defined in gen-controls.py
> > are useful for other generator scripts. Move them to a separate file to
> > make it possible to share them.
> > 
> > Extend the Python build environment to add the path to the new Python
> 
> Where is the python build environment being extended?

Oh I see it's in the next patch.


Paul

> 
> > module to PYTHONPATH, and use it when invoking the gen-controls.py
> > script.
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  include/libcamera/meson.build |   1 +
> >  src/libcamera/meson.build     |   3 +-
> >  utils/codegen/controls.py     | 112 ++++++++++++++++++++++++++++++++++
> >  utils/codegen/gen-controls.py | 105 +------------------------------
> >  4 files changed, 116 insertions(+), 105 deletions(-)
> >  create mode 100644 utils/codegen/controls.py
> > 
> > diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> > index d90a8615e52d..a969a95dbf7a 100644
> > --- a/include/libcamera/meson.build
> > +++ b/include/libcamera/meson.build
> > @@ -88,6 +88,7 @@ foreach mode, entry : controls_map
> >                                       command : [gen_controls, '-o', '@OUTPUT@',
> >                                                  '--mode', mode, '-t', template_file,
> >                                                  '-r', ranges_file, '@INPUT@'],
> > +                                     env : py_build_env,
> >                                       install : true,
> >                                       install_dir : libcamera_headers_install_dir)
> >  endforeach
> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> > index 3fd3a87e9f95..aa9ab0291854 100644
> > --- a/src/libcamera/meson.build
> > +++ b/src/libcamera/meson.build
> > @@ -151,7 +151,8 @@ foreach mode, inout_files : controls_mode_files
> >                                       output : output_file,
> >                                       command : [gen_controls, '-o', '@OUTPUT@',
> >                                                  '--mode', mode, '-t', template_file,
> > -                                                '-r', ranges_file, '@INPUT@'])
> > +                                                '-r', ranges_file, '@INPUT@'],
> > +                                     env : py_build_env)
> >  endforeach
> >  
> >  libcamera_public_sources += control_sources
> > diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py
> > new file mode 100644
> > index 000000000000..7bafee599c80
> > --- /dev/null
> > +++ b/utils/codegen/controls.py
> > @@ -0,0 +1,112 @@
> > +#!/usr/bin/env python3
> > +# SPDX-License-Identifier: GPL-2.0-or-later
> > +# Copyright (C) 2019, Google Inc.
> > +#
> > +# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > +#
> > +# Helper classes to handle source code generation for libcamera controls
> > +
> > +
> > +class ControlEnum(object):
> > +    def __init__(self, data):
> > +        self.__data = data
> > +
> > +    @property
> > +    def description(self):
> > +        """The enum description"""
> > +        return self.__data.get('description')
> > +
> > +    @property
> > +    def name(self):
> > +        """The enum name"""
> > +        return self.__data.get('name')
> > +
> > +    @property
> > +    def value(self):
> > +        """The enum value"""
> > +        return self.__data.get('value')
> > +
> > +
> > +class Control(object):
> > +    def __init__(self, name, data, vendor):
> > +        self.__name = name
> > +        self.__data = data
> > +        self.__enum_values = None
> > +        self.__size = None
> > +        self.__vendor = vendor
> > +
> > +        enum_values = data.get('enum')
> > +        if enum_values is not None:
> > +            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> > +
> > +        size = self.__data.get('size')
> > +        if size is not None:
> > +            if len(size) == 0:
> > +                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> > +
> > +            # Compute the total number of elements in the array. If any of the
> > +            # array dimension is a string, the array is variable-sized.
> > +            num_elems = 1
> > +            for dim in size:
> > +                if type(dim) is str:
> > +                    num_elems = 0
> > +                    break
> > +
> > +                dim = int(dim)
> > +                if dim <= 0:
> > +                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> > +
> > +                num_elems *= dim
> > +
> > +            self.__size = num_elems
> > +
> > +    @property
> > +    def description(self):
> > +        """The control description"""
> > +        return self.__data.get('description')
> > +
> > +    @property
> > +    def enum_values(self):
> > +        """The enum values, if the control is an enumeration"""
> > +        if self.__enum_values is None:
> > +            return
> > +        for enum in self.__enum_values:
> > +            yield enum
> > +
> > +    @property
> > +    def enum_values_count(self):
> > +        """The number of enum values, if the control is an enumeration"""
> > +        if self.__enum_values is None:
> > +            return 0
> > +        return len(self.__enum_values)
> > +
> > +    @property
> > +    def is_enum(self):
> > +        """Is the control an enumeration"""
> > +        return self.__enum_values is not None
> > +
> > +    @property
> > +    def vendor(self):
> > +        """The vendor string, or None"""
> > +        return self.__vendor
> > +
> > +    @property
> > +    def name(self):
> > +        """The control name (CamelCase)"""
> > +        return self.__name
> > +
> > +    @property
> > +    def type(self):
> > +        typ = self.__data.get('type')
> > +        size = self.__data.get('size')
> > +
> > +        if typ == 'string':
> > +            return 'std::string'
> > +
> > +        if self.__size is None:
> > +            return typ
> > +
> > +        if self.__size:
> > +            return f"Span<const {typ}, {self.__size}>"
> > +        else:
> > +            return f"Span<const {typ}>"
> > diff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py
> > index 685ef7a00d5f..2968eb9a5d4e 100755
> > --- a/utils/codegen/gen-controls.py
> > +++ b/utils/codegen/gen-controls.py
> > @@ -12,110 +12,7 @@ import os
> >  import sys
> >  import yaml
> >  
> > -
> > -class ControlEnum(object):
> > -    def __init__(self, data):
> > -        self.__data = data
> > -
> > -    @property
> > -    def description(self):
> > -        """The enum description"""
> > -        return self.__data.get('description')
> > -
> > -    @property
> > -    def name(self):
> > -        """The enum name"""
> > -        return self.__data.get('name')
> > -
> > -    @property
> > -    def value(self):
> > -        """The enum value"""
> > -        return self.__data.get('value')
> > -
> > -
> > -class Control(object):
> > -    def __init__(self, name, data, vendor):
> > -        self.__name = name
> > -        self.__data = data
> > -        self.__enum_values = None
> > -        self.__size = None
> > -        self.__vendor = vendor
> > -
> > -        enum_values = data.get('enum')
> > -        if enum_values is not None:
> > -            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
> > -
> > -        size = self.__data.get('size')
> > -        if size is not None:
> > -            if len(size) == 0:
> > -                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
> > -
> > -            # Compute the total number of elements in the array. If any of the
> > -            # array dimension is a string, the array is variable-sized.
> > -            num_elems = 1
> > -            for dim in size:
> > -                if type(dim) is str:
> > -                    num_elems = 0
> > -                    break
> > -
> > -                dim = int(dim)
> > -                if dim <= 0:
> > -                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
> > -
> > -                num_elems *= dim
> > -
> > -            self.__size = num_elems
> > -
> > -    @property
> > -    def description(self):
> > -        """The control description"""
> > -        return self.__data.get('description')
> > -
> > -    @property
> > -    def enum_values(self):
> > -        """The enum values, if the control is an enumeration"""
> > -        if self.__enum_values is None:
> > -            return
> > -        for enum in self.__enum_values:
> > -            yield enum
> > -
> > -    @property
> > -    def enum_values_count(self):
> > -        """The number of enum values, if the control is an enumeration"""
> > -        if self.__enum_values is None:
> > -            return 0
> > -        return len(self.__enum_values)
> > -
> > -    @property
> > -    def is_enum(self):
> > -        """Is the control an enumeration"""
> > -        return self.__enum_values is not None
> > -
> > -    @property
> > -    def vendor(self):
> > -        """The vendor string, or None"""
> > -        return self.__vendor
> > -
> > -    @property
> > -    def name(self):
> > -        """The control name (CamelCase)"""
> > -        return self.__name
> > -
> > -    @property
> > -    def type(self):
> > -        typ = self.__data.get('type')
> > -        size = self.__data.get('size')
> > -
> > -        if typ == 'string':
> > -            return 'std::string'
> > -
> > -        if self.__size is None:
> > -            return typ
> > -
> > -        if self.__size:
> > -            return f"Span<const {typ}, {self.__size}>"
> > -        else:
> > -            return f"Span<const {typ}>"
> > +from controls import Control
> >  
> >  
> >  def snake_case(s):

Patch
diff mbox series

diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index d90a8615e52d..a969a95dbf7a 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -88,6 +88,7 @@  foreach mode, entry : controls_map
                                      command : [gen_controls, '-o', '@OUTPUT@',
                                                 '--mode', mode, '-t', template_file,
                                                 '-r', ranges_file, '@INPUT@'],
+                                     env : py_build_env,
                                      install : true,
                                      install_dir : libcamera_headers_install_dir)
 endforeach
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 3fd3a87e9f95..aa9ab0291854 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -151,7 +151,8 @@  foreach mode, inout_files : controls_mode_files
                                      output : output_file,
                                      command : [gen_controls, '-o', '@OUTPUT@',
                                                 '--mode', mode, '-t', template_file,
-                                                '-r', ranges_file, '@INPUT@'])
+                                                '-r', ranges_file, '@INPUT@'],
+                                     env : py_build_env)
 endforeach
 
 libcamera_public_sources += control_sources
diff --git a/utils/codegen/controls.py b/utils/codegen/controls.py
new file mode 100644
index 000000000000..7bafee599c80
--- /dev/null
+++ b/utils/codegen/controls.py
@@ -0,0 +1,112 @@ 
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2019, Google Inc.
+#
+# Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+#
+# Helper classes to handle source code generation for libcamera controls
+
+
+class ControlEnum(object):
+    def __init__(self, data):
+        self.__data = data
+
+    @property
+    def description(self):
+        """The enum description"""
+        return self.__data.get('description')
+
+    @property
+    def name(self):
+        """The enum name"""
+        return self.__data.get('name')
+
+    @property
+    def value(self):
+        """The enum value"""
+        return self.__data.get('value')
+
+
+class Control(object):
+    def __init__(self, name, data, vendor):
+        self.__name = name
+        self.__data = data
+        self.__enum_values = None
+        self.__size = None
+        self.__vendor = vendor
+
+        enum_values = data.get('enum')
+        if enum_values is not None:
+            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
+
+        size = self.__data.get('size')
+        if size is not None:
+            if len(size) == 0:
+                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
+
+            # Compute the total number of elements in the array. If any of the
+            # array dimension is a string, the array is variable-sized.
+            num_elems = 1
+            for dim in size:
+                if type(dim) is str:
+                    num_elems = 0
+                    break
+
+                dim = int(dim)
+                if dim <= 0:
+                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
+
+                num_elems *= dim
+
+            self.__size = num_elems
+
+    @property
+    def description(self):
+        """The control description"""
+        return self.__data.get('description')
+
+    @property
+    def enum_values(self):
+        """The enum values, if the control is an enumeration"""
+        if self.__enum_values is None:
+            return
+        for enum in self.__enum_values:
+            yield enum
+
+    @property
+    def enum_values_count(self):
+        """The number of enum values, if the control is an enumeration"""
+        if self.__enum_values is None:
+            return 0
+        return len(self.__enum_values)
+
+    @property
+    def is_enum(self):
+        """Is the control an enumeration"""
+        return self.__enum_values is not None
+
+    @property
+    def vendor(self):
+        """The vendor string, or None"""
+        return self.__vendor
+
+    @property
+    def name(self):
+        """The control name (CamelCase)"""
+        return self.__name
+
+    @property
+    def type(self):
+        typ = self.__data.get('type')
+        size = self.__data.get('size')
+
+        if typ == 'string':
+            return 'std::string'
+
+        if self.__size is None:
+            return typ
+
+        if self.__size:
+            return f"Span<const {typ}, {self.__size}>"
+        else:
+            return f"Span<const {typ}>"
diff --git a/utils/codegen/gen-controls.py b/utils/codegen/gen-controls.py
index 685ef7a00d5f..2968eb9a5d4e 100755
--- a/utils/codegen/gen-controls.py
+++ b/utils/codegen/gen-controls.py
@@ -12,110 +12,7 @@  import os
 import sys
 import yaml
 
-
-class ControlEnum(object):
-    def __init__(self, data):
-        self.__data = data
-
-    @property
-    def description(self):
-        """The enum description"""
-        return self.__data.get('description')
-
-    @property
-    def name(self):
-        """The enum name"""
-        return self.__data.get('name')
-
-    @property
-    def value(self):
-        """The enum value"""
-        return self.__data.get('value')
-
-
-class Control(object):
-    def __init__(self, name, data, vendor):
-        self.__name = name
-        self.__data = data
-        self.__enum_values = None
-        self.__size = None
-        self.__vendor = vendor
-
-        enum_values = data.get('enum')
-        if enum_values is not None:
-            self.__enum_values = [ControlEnum(enum) for enum in enum_values]
-
-        size = self.__data.get('size')
-        if size is not None:
-            if len(size) == 0:
-                raise RuntimeError(f'Control `{self.__name}` size must have at least one dimension')
-
-            # Compute the total number of elements in the array. If any of the
-            # array dimension is a string, the array is variable-sized.
-            num_elems = 1
-            for dim in size:
-                if type(dim) is str:
-                    num_elems = 0
-                    break
-
-                dim = int(dim)
-                if dim <= 0:
-                    raise RuntimeError(f'Control `{self.__name}` size must have positive values only')
-
-                num_elems *= dim
-
-            self.__size = num_elems
-
-    @property
-    def description(self):
-        """The control description"""
-        return self.__data.get('description')
-
-    @property
-    def enum_values(self):
-        """The enum values, if the control is an enumeration"""
-        if self.__enum_values is None:
-            return
-        for enum in self.__enum_values:
-            yield enum
-
-    @property
-    def enum_values_count(self):
-        """The number of enum values, if the control is an enumeration"""
-        if self.__enum_values is None:
-            return 0
-        return len(self.__enum_values)
-
-    @property
-    def is_enum(self):
-        """Is the control an enumeration"""
-        return self.__enum_values is not None
-
-    @property
-    def vendor(self):
-        """The vendor string, or None"""
-        return self.__vendor
-
-    @property
-    def name(self):
-        """The control name (CamelCase)"""
-        return self.__name
-
-    @property
-    def type(self):
-        typ = self.__data.get('type')
-        size = self.__data.get('size')
-
-        if typ == 'string':
-            return 'std::string'
-
-        if self.__size is None:
-            return typ
-
-        if self.__size:
-            return f"Span<const {typ}, {self.__size}>"
-        else:
-            return f"Span<const {typ}>"
+from controls import Control
 
 
 def snake_case(s):