Code generation

Tint makes use of code generation tooling to emit source code and build files used to build Tint.

All code is generated with ./tools/run gen.

The generator uses heavy use of Go's text/template package. This is augmented with the functions declared in tools/src/template/template.go, and the data types provided by the tooling.

Build file generation

The generator will scan all the Tint source directories to produce BUILD.gn and BUILD.cmake files. These files contain the per-directory targets, conditionals and inter-target dependency information which is labour-intensive to maintain by hand.

The bulk of the build generator logic is in the file: tools/src/cmd/gen/build/build.go

Targets

There are 8 kinds of build target:

  • cmd targets are executables.
  • lib targets are libraries used in production code, and can also be used as a dependency by any other target kind .
  • test targets are libraries used by Tint unittests. Must not be used by production code.
  • test_cmd are test executables.
  • bench targets are libraries used by Tint benchmarks. Must not be used by production code.
  • bench_cmd are benchmark executables.
  • fuzz targets are libraries used by Tint fuzzers. Must not be used by production code.
  • fuzz_cmd are fuzzer executables.

The build generator uses a file naming convention based on the file name before the extension to classify each source file to a single target kind.

  • Source files named test or with a _test suffix are classed as test library targets.
    Example: parser_test.cc.
  • Source files named bench or with a _bench suffix are classed as bench library targets.
    Example: writer_bench.cc.
  • Source files named fuzz or with a _fuzz suffix are classed as fuzz library targets.
    Example: writer_fuzz.cc.
  • Source files with the name main are classed as executable targets. These typically exist under src/tint/cmd.
    Example: cmd/tint/main.cc.
  • Source files with the name main_test are classed as test executable targets. These typically exist under src/tint/cmd/test.
    Example: cmd/test/main_test.cc.
  • Source files with the name main_bench are classed as benchmark executable targets. These typically exist under src/tint/cmd/bench.
    Example: cmd/benchmark/main_bench.cc.
  • Source files with the name main_fuzz are classed as fuzzer executable targets. These typically exist under src/tint/cmd/fuzz.
    Example: cmd/benchmark/main_bench.cc.
  • All other files are considered lib targets.
    Example: parser.cc.

Each source directory can have at most one lib, test, test_main, bench, bench_main or cmd target.

The graph of target dependencies must be acyclic (DAG).

Target dependencies are automatically inferred from #includes made by the source files. Additional target dependencies can be added with the use of a BUILD.cfg file.

External dependencies

All external dependencies must be declared in src/tint/externals.json.

The syntax of this file is:

{
    "external-target-name": {
        "IncludePatterns": [
          /*
            A list of #include path patterns that refer to this external target.
            You may use the '*' wildcard for a single directory, or '**' as a multi-directory wildcard.
          */
          "myexternal/**.h",
        ],
        /* An optional build condition expression to wrap all uses of this external dependency */
        "Condition": "expression",
    },
    /* Repeat the above for all external targets */
}

GEN_BUILD directives

Source and build files can be annotated with special directives in comments to control the build file generation.

DirectiveDescription
GEN_BUILD:IGNORE_FILEAdd to a source file to have the file ignored by the generator
Example: // GEN_BUILD:IGNORE_FILE
GEN_BUILD:IGNORE_INCLUDEApply to the end of a #include in a source file to ignore this include for dependency analysis
Example: #include "foo/bar.h" // GEN_BUILD:IGNORE_INCLUDE
GEN_BUILD:CONDITION(cond)Applies the build condition for this source file.
Example: // GEN_BUILD:CONDITION(is_linux)
GEN_BUILD:DO_NOT_GENERATEPrevents the BUILD.* file from being generated.
Example: # GEN_BUILD:DO_NOT_GENERATE

BUILD.cfg files

A source directory may have an optional BUILD.cfg JSON file. The syntax of this file is:

{
  /* Build condition to apply to all targets of this directory. */
  "Condition": "cond",
  /* Options for the 'lib' target */
  "lib": { /* see TargetConfig */ },
  /* Options for the 'test' target */
  "test": { /* see TargetConfig */ },
  /* Options for the 'bench' target */
  "bench": { /* see TargetConfig */ },
  /* Options for the 'cmd' target */
  "cmd": { /* see TargetConfig */ },
}

All fields are optional.

The syntax of TargetConfig is:

{
  /* An override for the output file name for the target */
  "OutputName": "name",
  /* An additional condition for building this target */
  "Condition": "cond",
  "AdditionalDependencies": {
    "Internal": [
      /*
        A list of target name patterns that should in added as dependencies to this target.
        You may use the '*' wildcard for a single directory, or '**' as a multi-directory wildcard.
      */
    ],
    "External": [
      /*
        A list of external targets that should in added as dependencies to this target.
        Must match an external dependency declared in src/tint/externals.json
      */
    ]
  },
}

All fields are optional.

Templates

The build generator will emit a BUILD.ext file in each source directory, for each BUILD.ext.tmpl file found in tools/src/cmd/gen/build.

The template will be passed the Directory as $.