DVT SystemVerilog IDE User Guide
Rev. 24.2.25, 31 October 2024

42.7 Generating External Tool Scripts from the DVT Build Configuration

You can integrate DVT with external tools like compilers, simulators or linters via Run Configurations and External Builders.

Sometimes a good portion of the DVT build configuration file (.dvt/default.build) can be reused by the external tools. For example, an external compiler invocation is very similar to the content of each +dvt_init section from the default.build file, as it contains the same set of top files and compiler directives. However, most of the time there are tool, scripting or OS specific differences that do not allow a direct reuse.

For such situations, DVT provides the ${dvt_compile_script:<script_template.ftl>:<script.sh>} variable. It takes two mandatory arguments, provided as absolute paths or relative to the project root:

  1. script_template.ftl - a FreeMarker template of the script

  2. script.sh - the filename where DVT will generate the resulting script

In the script template you can access structured data describing the active build configuration. For example, the list of all +dvt_init sections and for each section the library name or list of all directives. When the external tool command gets executed, the template is processed and the script is generated. The variable itself is resolved to the full path of the generated script file, which can be used in the external tool command line.

The following API is accessible in the FreeMarker template:

isIncremental()Returns true if the script generation was triggered through an external builder's incremental build command.
getIncrementalFile()Returns the path to the incrementally compiled file - see isIncremental().
getInvocations()A list of invocation objects. Each +dvt_init section from the build configuration file is modeled by an invocation object. In the case of an external builder's incremental command, only the invocations in which the incrementally compiled file is specified.
invocation.getToolCompat()The compatiblity mode, one of DVT, IUS_IRUN, QUESTA_VCOM, QUESTA_VLOG, VCS_VHDLAN, VCS_VLOGAN
invocation.getCompilationRoot()The compilation root if specified by +dvt_compilation_root or the DVT project's location otherwise.
invocation.getDirectives()A list of directives specified in the corresponding +dvt_init section. A directive is comprised of its name and arguments, if any, separated by space. The content of -f included files is *not* available in the model. The -f directives are returned as-they-are.
invocation.replaceEnv(String input)A utility method to perform environment variable substitution in the scope of the current +dvt_init section. Any +dvt_setenv directives specified within the invocation are taken into account.
invocation.getLibName()The library name if specified by -work or "work" otherwise.
invocation.getIndex()The index of the invocation, where the first implicit invocation is #0.
getLibPathSet()A set of unique library name and path pairs.
libPath.getPath()Returns the library path.
libPath.getLib()Returns the library name.

Tip: An Eclipse plugin provides IDE functionality (syntax highlight, errors as you type, etc) for working with FreeMarker templates, see: http://download.jboss.org/jbosstools/oxygen/stable/updates/core/freemarker/1.5.302.v20171212-1534/

Note: Template processing errors prevent the execution of the external tool. They are reported in a pop-up dialog, and more details can be found in the FreeMarker page of the Console View.

Example: External Builder for QuestaSim on Windows OS

This example illustrates how to use the ${dvt_compile_script} variable to configure QuestaSim as an external compiler on Windows OS.

Click the drop-down arrow to the side of the Rebuild Project (External Builders) toolbar button and choose Configure....

Create a New... > External Builder (Generic) and fill in the full, incremental and clean commands.

On the Filters tab, enable the Questa filter category, and any other filters that may be relevant for you.

Tip: The external builder configuration is saved in the .dvt/external_builders.xml file, you can skip the steps above and simply create the file with the content listed below.

Create the script templates for full, incremental and clean commands. Listings of the files used in this example are provided below.

Note: The bin directory of the QuestaSim installation should be included in the %PATH% variable. Note: The ${env_var:DVT_HOME}\bin\utils\busybox program which is included in the DVT distribution allows scripts to be written in bash.

.dvt/external_builders.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<configurations>
  <configuration 
    ATTR_AUTO_COMMAND="${env_var:DVT_HOME}\bin\utils\busybox sh ${dvt_compile_script:.dvt/qw_incr.ftl:.dvt/qw_incr.sh}" 
    ATTR_BUILDER_ENABLED="false" 
    ATTR_BUILDER_NAME="questa_compile" 
    ATTR_CLEAN_COMMAND="${env_var:DVT_HOME}\bin\utils\busybox sh ${dvt_compile_script:.dvt/qw_clean.ftl:.dvt/qw_clean.sh}" 
    ATTR_FILTERS_KIND="Questa," 
    ATTR_FULL_COMMAND="${env_var:DVT_HOME}\bin\utils\busybox sh ${dvt_compile_script:.dvt/qw_full.ftl:.dvt/qw_full.sh}" 
    ATTR_WORKING_DIRECTORY="">
    <patterns/>
    <environment_variables ATTR_APPEND_ENVIRONMENT_VARIABLES="true"/>
  </configuration>
</configurations>

.dvt/qw_compile_full.ftl

#!/bin/bash
<#list getInvocations() as invocation>
echo "Invocation no ${invocation.getIndex()}"
<#assign compilationRoot = invocation.getCompilationRoot()>
cd "${compilationRoot}"
  <#assign libName = invocation.getLibName()>
vmake ${libName} &>/dev/null || vlib ${libName}
  <#if (invocation.getToolCompat() == "questa.vcom")>
vcom.exe \
  <#elseif (invocation.getToolCompat() == "questa.vlog")>
vlog.exe \
  </#if>
  <#list invocation.getDirectives() as directive>
    <#if (!directive?matches("\\+dvt_.*"))>
      <#if (directive?contains("\\"))>
        "${invocation.replaceEnv(directive)}" <#sep>\</#sep>
      <#else>
        ${invocation.replaceEnv(directive)} <#sep>\</#sep>
      </#if>
    </#if>
  </#list>
</#list>

.dvt/qw_compile_incr.ftl

#!/bin/bash
<#list getInvocations() as invocation>
echo "Invocation no ${invocation.getIndex()}"
<#assign compilationRoot = invocation.getCompilationRoot()>
cd "${compilationRoot}"
  <#assign libName = invocation.getLibName()>
vmake ${libName} &>/dev/null || vlib ${libName}
  <#if (invocation.getToolCompat() == "questa.vcom")>
vcom.exe \
  <#elseif (invocation.getToolCompat() == "questa.vlog")>
vlog.exe -incr \
  </#if>
  <#list invocation.getDirectives() as directive>
    <#if (!directive?matches("\\+dvt_.*") && (directive?starts_with("+") || directive?starts_with("-")))>
${directive} <#sep>\</#sep>
    </#if>
  </#list>
"${getIncrementalFile()}" \
</#list>

.dvt/qw_compile_clean.ftl

#!/bin/bash
<#list getLibPathSet() as libPath>
cd "${libPath.getPath()}"
vdel -lib ${libPath.getLib()} -all > /dev/null
</#list>