Skip to content

Multifile Templates

Sometimes you need to generate multiple related files from a single template group. embgen supports multifile templates for these cases.

Use Cases

  • Header and Source — Generate both .h and .c files together
  • Multiple Modules — Generate several related SystemVerilog files
  • Split Output — Separate definitions from implementations

Naming Convention

Multifile templates use the _multi suffix:

template.<group>_multi.<extension>[.<suffix>].j2

Different Extensions (Same Group)

Generate files with different extensions:

template.c_multi.h.j2    → <name>.h
template.c_multi.c.j2    → <name>.c

CLI usage: --c-multi generates both files

Same Extension (With Suffix)

Generate multiple files with the same extension:

template.sv_multi.sv.1.j2    → <name>_1.sv
template.sv_multi.sv.2.j2    → <name>_2.sv

CLI usage: --sv-multi generates both files

Examples

C Header and Source

Create two templates for header and implementation:

templates/
├── template.c_multi.h.j2    # Header file
└── template.c_multi.c.j2    # Source file

template.c_multi.h.j2:

// {{ name }}.h - Generated by embgen
#ifndef {{ name | upper }}_H
#define {{ name | upper }}_H

{% for item in config.items %}
void {{ item.name }}(void);
{% endfor %}

#endif

template.c_multi.c.j2:

// {{ name }}.c - Generated by embgen
#include "{{ name }}.h"

{% for item in config.items %}
void {{ item.name }}(void) {
    // Implementation for {{ item.name }}
}

{% endfor %}

CLI usage:

embgen mydomain config.yml -o output/ --c-multi

Output:

output/
├── myconfig.h
└── myconfig.c

SystemVerilog Modules

Generate multiple related Verilog files:

templates/
├── template.sv_multi.sv.1.j2    # Top module
├── template.sv_multi.sv.2.j2    # Controller
└── template.sv_multi.sv.3.j2    # Datapath

template.sv_multi.sv.1.j2:

// {{ name }}_top.sv
module {{ name }}_top (
    input clk,
    input rst_n
);
    {{ name }}_ctrl ctrl_inst (...);
    {{ name }}_dp dp_inst (...);
endmodule

template.sv_multi.sv.2.j2:

// {{ name }}_ctrl.sv
module {{ name }}_ctrl (...);
    // Controller logic
endmodule

template.sv_multi.sv.3.j2:

// {{ name }}_dp.sv
module {{ name }}_dp (...);
    // Datapath logic
endmodule

CLI usage:

embgen mydomain config.yml -o output/ --sv-multi

Output:

output/
├── myconfig_1.sv
├── myconfig_2.sv
└── myconfig_3.sv

Mixing Single and Multifile

You can have both single-file and multifile templates in the same domain:

templates/
├── template.h.j2            # Single: --h
├── template.md.j2           # Single: --md
├── template.c_multi.h.j2    # Multifile: --c-multi
└── template.c_multi.c.j2    # Multifile: --c-multi

CLI usage:

# Generate just the header
embgen mydomain config.yml -o output/ --h

# Generate header + source pair
embgen mydomain config.yml -o output/ --c-multi

# Generate everything
embgen mydomain config.yml -o output/ --h --md --c-multi

Output Filename Patterns

Template Config Name Output File
template.h.j2 MyConfig myconfig.h
template.c_multi.h.j2 MyConfig myconfig.h
template.c_multi.c.j2 MyConfig myconfig.c
template.sv_multi.sv.1.j2 MyConfig myconfig_1.sv
template.sv_multi.sv.2.j2 MyConfig myconfig_2.sv

The base filename comes from config.output_filename (which defaults to the lowercase name or can be overridden with the file field).

Python API

When using the Python API, multifile groups are discovered separately:

from embgen.templates import discover_templates

single_templates, multifile_groups = discover_templates(templates_path)

# single_templates: {"h": ("C Header", "template.h.j2"), ...}
# multifile_groups: {"c": MultifileGroup(...), "sv": MultifileGroup(...)}

# Access multifile group info
c_group = multifile_groups["c"]
print(c_group.description)     # "C Source"
print(c_group.templates)       # [TemplateInfo(...), TemplateInfo(...)]

Generating multifile output:

from embgen.generator import CodeGenerator

code_gen = CodeGenerator(generator, output_path)

# Generate a multifile group
for template_info in multifile_groups["c"].templates:
    code_gen.render_to_file(
        config,
        template_info.filename,
        template_info.output_ext,
        template_info.suffix,
    )

Template Discovery Rules

  1. Templates must end in .j2 or .jinja
  2. Files starting with _ are ignored (use for includes)
  3. Single templates: template.<ext>.j2
  4. Multifile templates: template.<group>_multi.<ext>[.<suffix>].j2

The group name becomes the CLI flag: --<group>-multi