scons

How to represent a scons builder that generates two files?


We have this scons builder which generates two files foo.asc and foo.pnr. Is there a way to represent it? For example by specifying suffix = [".asc", ".pnr"].

As far as we can see, a builder is assumed to generate only a single file and we don't want to run the builder twice, generating the two files twice. I deally the builder would run just once if one or the two output files are missing.

pnr_builder = Builder(
    action=(
        "nextpnr-ice40 --{0}{1} --package {2} --json $SOURCE --asc $TARGET "
        "--report {3}.pnr --pcf {4} {5}"
    ).format(
        FPGA_TYPE,
        FPGA_SIZE,
        FPGA_PACK,
        TARGET,
        PCF,
        "" if VERBOSE_ALL or VERBOSE_PNR else "-q",
    ),
    suffix=".asc",
    src_suffix=".json",
)
env.Append(BUILDERS={"PnR": pnr_builder})

Solution

  • I would suggest adding an emitter to your builder.

    This emitter can then set up your TARGETS to have them in a specific order, then you can use those in the command line for your builder.

    Here's the users guide info on emitters: https://scons.org/doc/production/HTML/scons-user.html#id1459

    Note we have a discord server where you can interactively ask questions if you'd like.

    Rewritten. Note I've not tried this code. the VERBOSE_ALL/VERBOSE_PNR may need some tweaking. The code below expects that all of FPGA_TYPE,FPGA_SIZE,FPGA_PACK,VERBOSE_ALL,VERBOSE_PNR Are env variables. Or set in the call to the builder. Also, I'd suggest adding PNR_ASC_SUFFIX and PNR_SUFFIX as env vars to specify those suffixes.

    Another note, this code expects both .asc and .pnr file names to be specified as targets when you call this builder, if that's not a reasonable expectation, then you'd want to add logic to this emitter to generate a .asc and .pnr suffixed file possible from the source file name.

    def pnr_emitter(target, source, env):
        """
        Alter target list so we can predict which element of the list is .asc and which is .pnr
        """
        asc_file = None
        pnr_file = None
        for t in target:
            if t.endswith('.asc'):
                asc_file = t
            elif t.endswith('.pnr'):
                pnr_file = t
        if pnr_file and asc_file:
            target = [pnr_file, asc_file]
    
        return target, source
    
    pnr_builder = Builder(
        action=(
            "nextpnr-ice40 --${FPGA_TYPE}${FPGA_SIZE} --package ${FPA_PACK} --json $SOURCE --asc ${TARGETS[1]} "
            "--report ${TARGETS[0]} --pcf ${(VERBOSE_ALL or VERBOSE_PNR) and '' or '-q'"
        ),
        src_suffix=".json",
        emitter=pnr_emitter,
    )
    env.Append(BUILDERS={"PnR": pnr_builder})