20.3. Using scanners with Builders

One approach for introducing scanners into the build is in conjunction with a Builder. There are two relvant optional parameters we can use when creating a builder: source_scanner and target_scanner. source_scanner is used for scanning source files, and target_scanner is used for scanning the target once it is generated.

import re

include_re = re.compile(r'^include\s+(\S+)$', re.M)

def kfile_scan(node, env, path, arg):
    contents = node.get_text_contents()
    return env.File(include_re.findall(contents))

kscan = Scanner(function=kfile_scan, skeys=['.k'], path_function=FindPathDirs('KPATH')

def build_function(target, source, env):
    # Code to build "target" from "source"
    return None

bld = Builder(
    action=build_function,
    suffix='.foo',
    source_scanner=kscan,
    src_suffix='.input',
)
env = Environment(BUILDERS={'Foo': bld})
env.Foo('file')
      

An emitter function can modify the list of sources or targets passed to the action function when the builder is triggered.

A scanner function will not affect the list of sources or targets seen by the builder during the build action. The scanner function will however affect if the builder should rebuild (if any of the files sourced by the scanner have changed for example).