Skip to content

Extending Glad

- The Aarnold - edited this page Oct 7, 2024 · 6 revisions

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).

Create a python package

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.

Add a specification

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

Add a language

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 generator config

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.

Testing

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.

Clone this wiki locally