-
Notifications
You must be signed in to change notification settings - Fork 0
Extending Glad
Glad can be extended to add support for new languages and specifications using setuptools entry points.
The proper way to do this is to create a new python package and add the additional language and/or specification to the right list of entry points.
This page is intended to give some general guidelines on how to create a plugin for glad, however, the author recommends taking example on how glad itself or the existing plugins implement their features (specifications and generators).
You must first create a basic file structure for your package with a pyproject.toml
file:
extending_glad/
└── pyproject.toml
More information on what the pyproject.toml
file is can be found here.
You can start by adding the following lines to pyproject.toml
:
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
This specifies the build backend to be setuptools
, which is the one glad
uses.
Then you can add information about your plugin, specifying its name, description, etc:
[project]
name = "my-glad-plugin"
version = "1.0.0"
description = "A new plugin for glad2!"
dependencies = ["glad2"]
The complete documentation of the [project]
table is available here.
You can also take example on the glad repository or on the existing plugins.
The dependencies
field must include (of course) glad2
and any other dependency required by your plugin, if any.
To add additional specifications you must extend the glad.specifications
entry point with
an appropriate specification class.
Usually, inheriting from glad.parse.Specification
and overriding the glad.parse.Specification.DISPLAY_NAME
,
glad.parse.Specification.API
and glad.parse.Specification.NAME
static variables is enough.
For example, you can create a file named my_specification.py
declaring the
OpenGL specification:
from glad.parse import Specification
class GL(Specification):
DISPLAY_NAME = 'OpenGL'
API = 'https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/master/xml/'
NAME = 'gl'
Then, add your specification class to the glad.specifications
entry point by
adding the following lines at the end of your pyproject.toml
:
[project.entry-points."glad.specifications"]
gl = "glad_plugin.specification.my_specification:GL"
The final file structure should look like this:
extending_glad/
├── pyproject.toml
└── glad_plugin/
└── specification/
└── my_specification.py
A language is (for now) just a generator which accepts a feature set and turns it
into code. Glad uses Jinja2 to generate code by
default, but custom generators can inherit from glad.generator.BaseGenerator
and generate code in any desired way. Otherwise, they can inherit from
glad.generator.JinjaGenerator
to use Jinja2 as
well.
A generator usually overrides the glad.generator.BaseGenerator.DISPLAY_NAME
and
glad.generator.BaseGenerator.Config
(and glad.generator.JinjaGenerator.TEMPLATES
,
if extending glad.generator.JinjaGenerator
) static variables, and implements
a id
method. It must also override the generate
method when extending from glad.generator.BaseGenerator
,
or the get_templates
method when extending from
glad.generator.JinjaGenerator
. A basic generator using Jinja would then look
like:
from glad.generator import JinjaGenerator
from glad.config import NullConfig
class MyGenerator(JinjaGenerator):
DISPLAY_NAME = 'MyLang'
TEMPLATES = ['glad_plugin.generator.my_lang']
Config = NullConfig
def __init__(self, *args, **kwargs):
JinjaGenerator.__init__(self, *args, **kwargs)
@property
def id(self):
return 'mylang'
def get_templates(self, spec, feature_set, config):
return [ ('template_file.j2', 'generated_code.mylang') ]
Here, the TEMPLATES
static variable gives the location(s) of the templates
directory(ies), containing the Jinja2 template files. For
more information on the Config
variable, see how to implement a custom
Config. The get_templates
method must return a
list of tuples, associating the name of a template file to the name of the file
that will contain the resulting generated code.
For the generator to be detected by glad, you must add the generator class to
the glad.generator
entry point in your pyproject.toml
file. For example,
adding
[project.entry-points."glad.generator"]
my_lang = "glad_plugin.generator.my_lang.__init__:MyGenerator"
to the end of pyproject.toml
would reflect the following file structure
extending_glad/
├── pyproject.toml
└── glad_plugin/
└── generator/
└── my_lang/
└── templates/
└── template_file.j2
└── __init__.py
where the __init__.py
file contains the MyGenerator
class, and the templates
directory contains the Jinja2 templates used by the
generator, as given by the get_templates
method.
The name of the entry point (here my_lang
) will be the name used on the
command line to invoke this generator, e.g glad --api gl:core=3.3 --out-path glad-gl my_lang
.
Custom command line options can be used in association with the generator to alter the code it generates and conditionally add features such as multi context or debugging.
A custom configuration class inheriting from glad.config.Config
can be
defined and instanciated by the Config
static
variable of your custom generator. For example:
from glad.generator import JinjaGenerator
from glad.config import Config, ConfigOption
class MyConfig(Config):
DEBUG = ConfigOption(
converter=bool,
default=False,
description='Enables generation of a debug build'
)
MX = ConfigOption(
converter=bool,
default=False,
description='Enables support for multiple GL contexts'
)
#...
class MyGenerator(JinjaGenerator):
# ...
Config = MyConfig
# ...
The static variables of the MyConfig
class will then appear as options when invoking
glad my_lang --help
from the command line.
Having the glad2 package installed, you can
test your plugin by installing it locally using pip and running glad
normally.
For development purposes, we recommend installing the plugin in
editable mode by running pip install -e .
inside the directory containing the
pyproject.toml
file of your project.