Menu
Lumberyard
Developer Guide (Version 1.11)

Template Drivers

AZ Code Generator is in preview release and is subject to change.

Template drivers are Python scripts that process the intermediate JSON data and route it into the Jinja2 output templates. The scripts preprocess the data from the Clang front end, execute the template rendering, and control where the generated output is written to disk.

These scripts are usually called by one or more code generation passes in WAF wscript files. Each Python script can reference multiple templates. This offers great flexibility in implementation, especially when multiple templates rely on the same preprocessed data. 

Specifying Drivers in Waf

Drivers are specified by file name in each code generation pass. The file path is relative to the root of the wscript target. All drivers are invoked on each input file.

The following shows the structure of a sample Waf entry.

Copy
'az_code_gen' = [ { 'files': [ <files to gen> ], 'scripts': [ <list of script file paths relative to current wscript folder> ] } ]

For more details on how to specify passes, see AZ Code Generator Integration with Waf .

Creating a Template Driver in Python

To create a template driver in Python, you must import the TemplateDriver base class and override its methods. The code for the class can be found in the dev/Code/Tools/AzCodeGenerator/Scripts/az_code_gen/base.py file.

This class is automatically injected into Python by AZ Code Generator and only needs to be imported as az_code_gen.base, as in the following example.

Copy
from az_code_gen.base import *

Methods to Override in the TemplateDriver Class

To implement your template driver, override the following methods in the TemplateDriver class.

add_dependency

Call the add_dependency method to manually add a dependency to the az_code_gen task in Waf. The file path given should be absolute so that the render template can specify additional dependencies that Waf does not automatically include. These dependencies might be external data files used to render the templates, or files that were used to generate the input data.

Syntax

Copy
add_dependency(self, dependency_file)

apply_transformations

Override the apply_transformations method to manipulate the raw JSON object, which is passed in as the obj parameter. Manipulations are performed in place on the object. The object is then forwarded through the pipeline and is eventually passed to jinja_args of render_templates. Any object returned by this method is provided to the Jinja environment as extra_data.

Syntax

Copy
apply_transformations(self, obj)

For an example of this method, see Preprocessing Intermediate Data.

get_expected_tags

Override the get_expected_tags method to return a list of tags that must be found in any input file. If the required tags are not present, this driver is skipped.

Important

This method is deprecated as of Lumberyard v1.6. After Lumberyard v1.6, all scripts will be processed regardless of expected tags, and get_expected_tags will not be invoked.

Syntax

Copy
get_expected_tags(self)

render_template_to_file

Renders a template to disk. This method also adds the value of output_file as a dependency of the az_code_gen task in Waf.

Syntax

Copy
render_template_to_file(self, template_file, template_kwargs, output_file, should_add_to_build=False)

Parameters

Parameter Description
template_file Specifies the path to a template relative to the directory that contains the template driver .py file.
template_kwargs Specifies a dictionary of key–value pairs to be passed to Jinja. Generally this should be treated as a passthrough variable for the jinja_args given to render_templates, but you can add additional key–value pairs.
output_file Specifies the target file for the rendered Jinja output. The path is relative to the target output folder.
should_add_to_build A Boolean value that specifies whether Waf should add this file to the C++ build and linker. The default is false.

render_templates

Override render_templates to invoke template rendering by calling render_template_to_file.

Syntax

Copy
render_templates(self, input_file, **jinja_args)

Parameters

Parameter Description
input_file The path relative to the input path that is used to invoke Clang.
jinja_args The raw data from the intermediate JSON object after the template driver performs preprocessing on the object.

Minimal Template Driver

The minimum code required for a template driver is to derive from the TemplateDriver base class and implement a factory function to construct the template driver.

Copy
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver): pass # Factory function - called from launcher def create_drivers(env): return [MyTemplateDriver(env)]

The az_code_gen module is automatically provided by AZ Code Generator. It contains the TemplateDriver and other useful methods from the base.py file.

The create_drivers function simply forwards the Jinja environment that is used to render templates. However, you can alter the function to perform other work when the driver is instantiated.

Note

The above bare-bones implementation works but does not generate any output.

Rendering Templates

To generate some output, you must implement the render_templates method, as in the following example.

Copy
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver): def render_templates(self, input_file, **jinja_args): self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp') # Factory function - called from launcher def create_drivers(env): return [MyTemplateDriver(env)]

The render_templates method takes the relative input_file path and any arguments that were passed in from the AZCodeGenerator.exe utility. The input_file path usually contains inputs such as the intermediate json_object created by Clang.

Template drivers can extend this information by implementing the apply_transformations method. For more information, see Preprocessing Intermediate Data.

The render_template_to_file method takes a template file and argument key–value pairs to pass into the template engine directly and an output path to write the template engine render output to disk.

Configuring Automatic Build Injection

At this point, the example generates a minimal .cpp file. The example above does not compile or link the .cpp file. This is appropriate if you intend to include the generated code manually using an #include in another file.

To inject the generated file automatically, add the should_add_to_build parameter to the render_template_to_file method and pass the parameter the value of true. The should_add_to_build parameter informs Waf that the generated file needs to be built and linked into the current target.

Note

Using the should_add_to_build parameter is not recommended for header files or other generated files that are not C++ code that must be compiled and linked.

The following example shows some build injected output.

Copy
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver): def render_templates(self, input_file, **jinja_args): self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp', should_add_to_build=True) # Factory function - called from launcher def create_drivers(env): return [MyTemplateDriver(env)]

Preprocessing Intermediate Data

Some cases require preprocessing of the intermediate data for easier consumption by the template engine. To do this, implement the apply_transformations method in your template driver. You can use this method to access the intermediate JSON data object directly before it gets passed to render_templates. An example follows.

Copy
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver): def render_templates(self, input_file, **jinja_args): self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp') def apply_transformations(self, obj): obj['my_custom_data'] = 42 # Factory function - called from launcher def create_drivers(env): return [MyTemplateDriver(env)]

For information on the contents of the obj variable, see Intermediate JSON Data Format.