Example #1
0
def main(argv, out, err):

    # We need a UTF-8 locale, so bail out if we don't have one. More
    # specifically, things like the version() computation traverse the file
    # system and, if they hit a UTF-8 filename, they try to decode it into your
    # preferred encoding and trigger an exception.
    encoding = locale.getpreferredencoding().lower()
    if encoding not in ('utf-8', 'utf8'):
        err.write('CAmkES uses UTF-8 encoding, but your locale\'s preferred '
                  'encoding is %s. You can override your locale with the LANG '
                  'environment variable.\n' % encoding)
        return -1

    options = parse_args(argv, out, err)

    # register object sizes with loader
    if options.object_sizes:
        register_object_sizes(
            yaml.load(options.object_sizes, Loader=yaml.FullLoader))

    # Ensure we were supplied equal items, outfiles and templates
    if len(options.outfile) != len(options.item) != len(options.template):
        err.write(
            'Different number of items and outfiles. Required one outfile location '
            'per item requested.\n')
        return -1

    # No duplicates in outfiles
    if len(set(options.outfile)) != len(options.outfile):
        err.write('Duplicate outfiles requrested through --outfile.\n')
        return -1

    # Save us having to pass debugging everywhere.
    die = functools.partial(_die, options)

    log.set_verbosity(options.verbosity)

    ast = pickle.load(options.load_ast)

    # Locate the assembly.
    assembly = ast.assembly
    if assembly is None:
        die('No assembly found')

    # Do some extra checks if the user asked for verbose output.
    if options.verbosity >= 2:

        # Try to catch type mismatches in attribute settings. Note that it is
        # not possible to conclusively evaluate type correctness because the
        # attributes' type system is (deliberately) too loose. That is, the
        # type of an attribute can be an uninterpreted C type the user will
        # provide post hoc.
        for i in assembly.composition.instances:
            for a in i.type.attributes:
                value = assembly.configuration[i.name].get(a.name)
                if value is not None:
                    if a.type == 'string' and not \
                            isinstance(value, six.string_types):
                        log.warning('attribute %s.%s has type string but is '
                                    'set to a value that is not a string' %
                                    (i.name, a.name))
                    elif a.type == 'int' and not \
                            isinstance(value, numbers.Number):
                        log.warning('attribute %s.%s has type int but is set '
                                    'to a value that is not an integer' %
                                    (i.name, a.name))

    try:
        r = Renderer(options.templates)
    except jinja2.exceptions.TemplateSyntaxError as e:
        die('template syntax error: %s' % e)

    if options.load_object_state is not None:
        render_state = pickle.load(options.load_object_state)
    elif options.save_object_state is None:
        render_state = None
    else:
        obj_space = ObjectAllocator()
        obj_space.spec.arch = options.architecture
        render_state = RenderState(obj_space=obj_space)

        for i in assembly.composition.instances:
            # Don't generate any code for hardware components.
            if i.type.hardware:
                continue

            key = i.address_space

            if key not in render_state.cspaces:
                cnode = render_state.obj_space.alloc(
                    ObjectType.seL4_CapTableObject,
                    name="%s_cnode" % key,
                    label=key)
                render_state.cspaces[key] = CSpaceAllocator(cnode)
                pd = obj_space.alloc(lookup_architecture(
                    options.architecture).vspace().object,
                                     name="%s_group_bin_pd" % key,
                                     label=key)
                addr_space = AddressSpaceAllocator(
                    re.sub(r'[^A-Za-z0-9]', '_', "%s_group_bin" % key), pd)
                render_state.pds[key] = pd
                render_state.addr_spaces[key] = addr_space

    for (item, outfile, template) in zip(options.item, options.outfile,
                                         options.template):
        key = item.split("/")
        if key[0] == "component":
            i = [
                x for x in assembly.composition.instances if x.name == key[1]
            ][0]
            obj_key = i.address_space
        elif key[0] == "connector":
            c = [
                c for c in assembly.composition.connections if c.name == key[1]
            ][0]
            if key[2] == "to":
                i = c.to_ends[int(key[3])]
            elif key[2] == "from":
                i = c.from_ends[int(key[3])]
            else:
                die("Invalid connector end")
            obj_key = i.instance.address_space
        elif key[0] == "assembly":
            i = assembly
            obj_key = None
        else:
            die("item: \"%s\" does not have the correct formatting to render."
                % item)

        try:
            g = r.render(i,
                         assembly,
                         template,
                         render_state,
                         obj_key,
                         outfile_name=outfile.name,
                         options=options,
                         my_pd=render_state.pds[obj_key] if obj_key else None)
            outfile.write(g)
            outfile.close()
        except TemplateError as inst:
            if hasattr(i, 'name'):
                die(rendering_error(i.name, inst))
            else:
                die(rendering_error(i.parent.name, inst))

    read = r.get_files_used()
    # Write a Makefile dependency rule if requested.
    if options.makefile_dependencies is not None:
        options.makefile_dependencies.write(
            '%s: \\\n  %s\n' %
            (options.outfile[0].name, ' \\\n  '.join(sorted(read))))

    if options.save_object_state is not None:
        # Write the render_state to the supplied outfile
        pickle.dump(render_state, options.save_object_state)

    sys.exit(0)
Example #2
0
def main():
    parser = argparse.ArgumentParser(
        description="")
    parser.add_argument('--architecture', '--arch', default='aarch32',
                        type=lambda x: type('')(x).lower(), choices=valid_architectures(),
                        help='Target architecture.')
    parser.add_argument('--object-sizes', required=True, type=argparse.FileType('r'))
    subparsers = parser.add_subparsers()
    parser_a = subparsers.add_parser('build_cnode')
    parser_a.add_argument('--ccspace', nargs='+', type=argparse.FileType('w'), action='append')
    parser_a.set_defaults(which="build_cnode")
    parser_a.add_argument('--manifest-in', type=argparse.FileType('rb'))
    parser_a.add_argument('--elffile', nargs='+', action='append')
    parser_b = subparsers.add_parser('gen_cdl')
    parser_b.add_argument('--outfile', type=argparse.FileType('w'))
    parser_b.set_defaults(which="gen_cdl")
    parser_b.add_argument('--manifest-in', type=argparse.FileType('rb'))
    parser_b.add_argument('--elffile', nargs='+', action='append')
    parser_b.add_argument('--keys', nargs='+', action='append')
    parser_b.add_argument('--fprovide-tcb-caps', action='store_true',
                          default=True, help='Hand out TCB caps to components, allowing them to '
                          'exit cleanly.')
    parser_b.add_argument('--fno-provide-tcb-caps', action='store_false',
                          dest='fprovide_tcb_caps', help='Do not hand out TCB caps, causing '
                          'components to fault on exiting.')
    parser_b.add_argument('--save-object-state', type=argparse.FileType('wb'))
    parser_b.add_argument('--static-alloc', action='store_true',
                          help='Perform static object allocation (requires --untyped)')
    parser_b.add_argument('--dynamic-alloc', action='store_false', dest='static_alloc',
                          help='Cancel --static-alloc')
    parser_b.add_argument('--untyped', type=argparse.FileType('r'),
                          help="YAML file with available seL4 bootinfo untypeds")

    args = parser.parse_args()
    register_object_sizes(yaml.load(args.object_sizes, Loader=yaml.FullLoader))

    if args.which == "build_cnode":
        data = yaml.load(args.manifest_in, Loader=yaml.FullLoader)
        assert 'cap_symbols' in data and 'region_symbols' in data, "Invalid file format"
        elfs = [item for sublist in args.elffile for item in sublist]
        cspaces = [item for sublist in args.ccspace for item in sublist]
        targets = zip(elfs, cspaces)
        manifest(data['cap_symbols'], data['region_symbols'], args.architecture, targets)
        return 0

    if args.which == "gen_cdl":
        if args.static_alloc and not args.untyped:
            parser.error('--static-alloc requires --untyped')

        allocator_state = pickle.load(args.manifest_in)
        elfs = [item for sublist in args.elffile for item in sublist]
        keys = [item for sublist in args.keys for item in sublist]
        targets = zip(elfs, keys)
        obj_space = final_spec(args, allocator_state.obj_space, allocator_state.cspaces,
                               allocator_state.addr_spaces, targets, args.architecture)

        # Calculate final layout for objects and ASID slots...
        ASIDTableAllocator().allocate(obj_space.spec)
        if args.static_alloc:
            alloc = BestFitAllocator()
            for ut in yaml.load(args.untyped, Loader=yaml.FullLoader):
                if len(ut):
                    is_device, paddr, size_bits = ut['device'], ut['paddr'], ut['size_bits']
                    alloc.add_untyped(Untyped("root_untyped_0x%x" % paddr,
                                              size_bits=size_bits, paddr=paddr), is_device)
            alloc.allocate(obj_space.spec)

        args.outfile.write(repr(obj_space.spec))
        if args.save_object_state:
            pickle.dump(allocator_state, args.save_object_state)

    return 0
Example #3
0
def main(argv, out, err):

    # We need a UTF-8 locale, so bail out if we don't have one. More
    # specifically, things like the version() computation traverse the file
    # system and, if they hit a UTF-8 filename, they try to decode it into your
    # preferred encoding and trigger an exception.
    encoding = locale.getpreferredencoding().lower()
    if encoding not in ('utf-8', 'utf8'):
        err.write('CAmkES uses UTF-8 encoding, but your locale\'s preferred '
                  'encoding is %s. You can override your locale with the LANG '
                  'environment variable.\n' % encoding)
        return -1

    options = parse_args(argv, out, err)

    # register object sizes with loader
    if options.object_sizes:
        register_object_sizes(
            yaml.load(options.object_sizes, Loader=yaml.FullLoader))

    # Ensure we were supplied equal items and outfiles
    if len(options.outfile) != len(options.item):
        err.write(
            'Different number of items and outfiles. Required one outfile location '
            'per item requested.\n')
        return -1

    # No duplicates in items or outfiles
    if len(set(options.item)) != len(options.item):
        err.write('Duplicate items requested through --item.\n')
        return -1
    if len(set(options.outfile)) != len(options.outfile):
        err.write('Duplicate outfiles requrested through --outfile.\n')
        return -1

    # Save us having to pass debugging everywhere.
    die = functools.partial(_die, options)

    log.set_verbosity(options.verbosity)

    ast = pickle.load(options.load_ast)

    # Locate the assembly.
    assembly = ast.assembly
    if assembly is None:
        die('No assembly found')

    # Do some extra checks if the user asked for verbose output.
    if options.verbosity >= 2:

        # Try to catch type mismatches in attribute settings. Note that it is
        # not possible to conclusively evaluate type correctness because the
        # attributes' type system is (deliberately) too loose. That is, the
        # type of an attribute can be an uninterpreted C type the user will
        # provide post hoc.
        for i in assembly.composition.instances:
            for a in i.type.attributes:
                value = assembly.configuration[i.name].get(a.name)
                if value is not None:
                    if a.type == 'string' and not \
                            isinstance(value, six.string_types):
                        log.warning('attribute %s.%s has type string but is '
                                    'set to a value that is not a string' %
                                    (i.name, a.name))
                    elif a.type == 'int' and not \
                            isinstance(value, numbers.Number):
                        log.warning('attribute %s.%s has type int but is set '
                                    'to a value that is not an integer' %
                                    (i.name, a.name))
    templates = Templates(options.platform)
    [templates.add_root(t) for t in options.templates]
    try:
        r = Renderer(templates)
    except jinja2.exceptions.TemplateSyntaxError as e:
        die('template syntax error: %s' % e)

    # The user may have provided their own connector definitions (with
    # associated) templates, in which case they won't be in the built-in lookup
    # dictionary. Let's add them now. Note, definitions here that conflict with
    # existing lookup entries will overwrite the existing entries. Note that
    # the extra check that the connector has some templates is just an
    # optimisation; the templates module handles connectors without templates
    # just fine.
    for c in (x for x in ast.items if isinstance(x, Connector) and (
            x.from_template is not None or x.to_template is not None)):
        try:
            # Find a connection that uses this type.
            connection = next(x for x in ast
                              if isinstance(x, Connection) and x.type == c)
            # Add the custom templates and update our collection of read
            # inputs.
            templates.add(c, connection)
        except TemplateError as e:
            die('while adding connector %s: %s' % (c.name, e))
        except StopIteration:
            # No connections use this type. There's no point adding it to the
            # template lookup dictionary.
            pass

    if options.load_object_state is not None:
        render_state = pickle.load(options.load_object_state)

    else:
        obj_space = ObjectAllocator()
        obj_space.spec.arch = options.architecture
        render_state = AllocatorState(obj_space=obj_space)

        for i in assembly.composition.instances:
            # Don't generate any code for hardware components.
            if i.type.hardware:
                continue

            key = i.address_space

            if key not in render_state.cspaces:
                cnode = render_state.obj_space.alloc(
                    ObjectType.seL4_CapTableObject,
                    name="%s_cnode" % key,
                    label=key)
                render_state.cspaces[key] = CSpaceAllocator(cnode)
                pd = obj_space.alloc(lookup_architecture(
                    options.architecture).vspace().object,
                                     name="%s_group_bin_pd" % key,
                                     label=key)
                addr_space = AddressSpaceAllocator(
                    re.sub(r'[^A-Za-z0-9]', '_', "%s_group_bin" % key), pd)
                render_state.pds[key] = pd
                render_state.addr_spaces[key] = addr_space

    for (item, outfile) in zip(options.item, options.outfile):
        key = item.split("/")
        if len(key) is 1:
            # We are rendering something that isn't a component or connection.
            i = assembly
            obj_key = None
            template = templates.lookup(item)
        elif key[1] in [
                "source", "header", "c_environment_source",
                "cakeml_start_source", "cakeml_end_source", "camkesConstants",
                "linker", "debug", "simple", "rump_config"
        ]:
            # We are rendering a component template
            i = [
                x for x in assembly.composition.instances if x.name == key[0]
            ][0]
            obj_key = i.address_space
            template = templates.lookup(item, i)
        elif key[1] in ["from", "to"]:
            # We are rendering a connection template
            c = [
                c for c in assembly.composition.connections if c.name == key[0]
            ][0]
            if key[1] == "to":
                i = c.to_ends[int(key[-1])]
            elif key[1] == "from":
                i = c.from_ends[int(key[-1])]
            else:
                die("Invalid connector end")
            obj_key = i.instance.address_space
            template = templates.lookup("/".join(key[:-1]), c)
        else:
            die("item: \"%s\" does not have the correct formatting to lookup a template."
                % item)
        try:
            g = r.render(i,
                         assembly,
                         template,
                         render_state,
                         obj_key,
                         outfile_name=outfile.name,
                         options=options,
                         my_pd=render_state.pds[obj_key] if obj_key else None)
            outfile.write(g)
            outfile.close()
        except TemplateError as inst:
            die(rendering_error(i.name, inst))

    read = r.get_files_used()
    # Write a Makefile dependency rule if requested.
    if options.makefile_dependencies is not None:
        options.makefile_dependencies.write(
            '%s: \\\n  %s\n' %
            (options.outfile[0].name, ' \\\n  '.join(sorted(read))))

    if options.save_object_state is not None:
        # Write the render_state to the supplied outfile
        pickle.dump(render_state, options.save_object_state)

    sys.exit(0)
Example #4
0
def main(argv, out, err):

    # We need a UTF-8 locale, so bail out if we don't have one. More
    # specifically, things like the version() computation traverse the file
    # system and, if they hit a UTF-8 filename, they try to decode it into your
    # preferred encoding and trigger an exception.
    encoding = locale.getpreferredencoding().lower()
    if encoding not in ('utf-8', 'utf8'):
        err.write('CAmkES uses UTF-8 encoding, but your locale\'s preferred '
                  'encoding is %s. You can override your locale with the LANG '
                  'environment variable.\n' % encoding)
        return -1

    options = parse_args(argv, out, err)

    # register object sizes with loader
    if options.object_sizes:
        register_object_sizes(yaml.load(options.object_sizes))

    # Ensure we were supplied equal items and outfiles
    if len(options.outfile) != len(options.item):
        err.write(
            'Different number of items and outfiles. Required one outfile location '
            'per item requested.\n')
        return -1

    # No duplicates in items or outfiles
    if len(set(options.item)) != len(options.item):
        err.write('Duplicate items requested through --item.\n')
        return -1
    if len(set(options.outfile)) != len(options.outfile):
        err.write('Duplicate outfiles requrested through --outfile.\n')
        return -1

    # Save us having to pass debugging everywhere.
    die = functools.partial(_die, options)

    log.set_verbosity(options.verbosity)

    # Build a list of item/outfile pairs that we have yet to match and process
    all_items = set(zip(options.item, options.outfile))
    done_items = set([])

    def done(s, file, item, r, read):
        ret = 0
        if s:
            file.write(s)
            file.close()

        done_items.add((item, file))
        if len(all_items - done_items) == 0:

            read |= r.get_files_used()
            # Write a Makefile dependency rule if requested.
            if options.makefile_dependencies is not None:
                options.makefile_dependencies.write(
                    '%s: \\\n  %s\n' %
                    (options.outfile[0].name, ' \\\n  '.join(sorted(read))))

            if options.save_object_state is not None:
                # Write the render_state to the supplied outfile
                pickle.dump(renderoptions.render_state,
                            options.save_object_state)

            sys.exit(ret)

    ast = pickle.load(options.load_ast)
    read = set()

    # Locate the assembly.
    assembly = ast.assembly
    if assembly is None:
        die('No assembly found')

    # Do some extra checks if the user asked for verbose output.
    if options.verbosity >= 2:

        # Try to catch type mismatches in attribute settings. Note that it is
        # not possible to conclusively evaluate type correctness because the
        # attributes' type system is (deliberately) too loose. That is, the
        # type of an attribute can be an uninterpreted C type the user will
        # provide post hoc.
        for i in assembly.composition.instances:
            for a in i.type.attributes:
                value = assembly.configuration[i.name].get(a.name)
                if value is not None:
                    if a.type == 'string' and not \
                            isinstance(value, six.string_types):
                        log.warning('attribute %s.%s has type string but is '
                                    'set to a value that is not a string' %
                                    (i.name, a.name))
                    elif a.type == 'int' and not \
                            isinstance(value, numbers.Number):
                        log.warning('attribute %s.%s has type int but is set '
                                    'to a value that is not an integer' %
                                    (i.name, a.name))
    obj_space = ObjectAllocator()
    obj_space.spec.arch = options.architecture
    render_state = RenderState(obj_space=obj_space)

    templates = Templates(options.platform)
    [templates.add_root(t) for t in options.templates]
    try:
        r = Renderer(templates)
    except jinja2.exceptions.TemplateSyntaxError as e:
        die('template syntax error: %s' % e)

    # The user may have provided their own connector definitions (with
    # associated) templates, in which case they won't be in the built-in lookup
    # dictionary. Let's add them now. Note, definitions here that conflict with
    # existing lookup entries will overwrite the existing entries. Note that
    # the extra check that the connector has some templates is just an
    # optimisation; the templates module handles connectors without templates
    # just fine.
    for c in (x for x in ast.items if isinstance(x, Connector) and (
            x.from_template is not None or x.to_template is not None)):
        try:
            # Find a connection that uses this type.
            connection = next(x for x in ast
                              if isinstance(x, Connection) and x.type == c)
            # Add the custom templates and update our collection of read
            # inputs.
            templates.add(c, connection)
        except TemplateError as e:
            die('while adding connector %s: %s' % (c.name, e))
        except StopIteration:
            # No connections use this type. There's no point adding it to the
            # template lookup dictionary.
            pass

    def apply_capdl_filters(renderoptions):
        # Derive a set of usable ELF objects from the filenames we were passed.
        render_state = renderoptions.render_state
        elfs = {}
        for e in options.elf:
            try:
                name = os.path.basename(e)
                if name in elfs:
                    raise Exception(
                        'duplicate ELF files of name \'%s\' encountered' %
                        name)
                elf = ELF(e, name, options.architecture)
                group = name.replace("_group_bin", "")
                # Avoid inferring a TCB as we've already created our own.
                elf_spec = elf.get_spec(
                    infer_tcb=False,
                    infer_asid=False,
                    pd=render_state.pds[group],
                    use_large_frames=options.largeframe,
                    addr_space=render_state.addr_spaces[group])
                render_state.obj_space.merge(elf_spec, label=group)
                elfs[name] = (e, elf)
            except Exception as inst:
                die('While opening \'%s\': %s' % (e, inst))
        for space in render_state.cspaces.values():
            for (slot, tcb) in [
                (v, v.referent) for (k, v) in space.cnode.slots.items()
                    if v is not None and isinstance(v.referent, TCB)
            ]:
                elf = elfs.get(tcb.elf)
                funcs = {"get_vaddr": lambda x: elf[1].get_symbol_vaddr(x)}
                tcb.ip = simple_eval(str(tcb.ip), functions=funcs)
                tcb.sp = simple_eval(str(tcb.sp), functions=funcs)
                tcb.addr = simple_eval(str(tcb.addr), functions=funcs)
                if not options.fprovide_tcb_caps:
                    del space.cnode[slot]
            space.cnode.finalise_size(
                arch=lookup_architecture(options.architecture))

    renderoptions = RenderOptions(
        options.verbosity, options.frpc_lock_elision,
        options.fspecialise_syscall_stubs, options.fprovide_tcb_caps,
        options.largeframe, options.largeframe_dma, options.architecture,
        options.debug_fault_handlers, options.default_priority,
        options.default_max_priority, options.default_affinity,
        options.default_period, options.default_budget, options.default_data,
        options.default_size_bits, options.default_stack_size,
        options.realtime, options.verification_base_name, render_state)

    def instantiate_misc_templates(renderoptions):
        for (item, outfile) in (all_items - done_items):
            try:
                template = templates.lookup(item)
                if template:
                    g = r.render(assembly,
                                 assembly,
                                 template,
                                 renderoptions.render_state,
                                 None,
                                 outfile_name=outfile.name,
                                 options=renderoptions)
                    done(g, outfile, item, r, read)
            except TemplateError as inst:
                die(rendering_error(item, inst))

    if "camkes-gen.cmake" in options.item:
        instantiate_misc_templates(renderoptions)

    if options.load_object_state is not None:
        # There is an assumption that if load_object_state is set, we
        # skip all of the component and connector logic below.
        # FIXME: refactor to clarify control flow
        renderoptions.render_state = pickle.load(options.load_object_state)
        apply_capdl_filters(renderoptions)
        instantiate_misc_templates(renderoptions)

        # If a template wasn't instantiated, something went wrong, and we can't recover
        raise CAmkESError("No template instantiated on capdl generation path")

    # We're now ready to instantiate the template the user requested, but there
    # are a few wrinkles in the process. Namely,
    #  1. Template instantiation needs to be done in a deterministic order. The
    #     runner is invoked multiple times and template code needs to be
    #     allocated identical cap slots in each run.
    #  2. Components and connections need to be instantiated before any other
    #     templates, regardless of whether they are the ones we are after. Some
    #     other templates, such as the Makefile depend on the obj_space and
    #     cspaces.
    #  3. All actual code templates, up to the template that was requested,
    #     need to be instantiated. This is related to (1) in that the cap slots
    #     allocated are dependent on what allocations have been done prior to a
    #     given allocation call.

    # Instantiate the per-component source and header files.
    for i in assembly.composition.instances:
        # Don't generate any code for hardware components.
        if i.type.hardware:
            continue

        if i.address_space not in renderoptions.render_state.cspaces:
            cnode = renderoptions.render_state.obj_space.alloc(
                ObjectType.seL4_CapTableObject,
                name="%s_cnode" % i.address_space,
                label=i.address_space)
            renderoptions.render_state.cspaces[
                i.address_space] = CSpaceAllocator(cnode)
            pd = obj_space.alloc(lookup_architecture(
                options.architecture).vspace().object,
                                 name="%s_group_bin_pd" % i.address_space,
                                 label=i.address_space)
            addr_space = AddressSpaceAllocator(
                re.sub(r'[^A-Za-z0-9]', '_', "%s_group_bin" % i.address_space),
                pd)
            renderoptions.render_state.pds[i.address_space] = pd
            renderoptions.render_state.addr_spaces[
                i.address_space] = addr_space

        for t in ('%s/source' % i.name, '%s/header' % i.name,
                  '%s/c_environment_source' % i.name,
                  '%s/cakeml_start_source' % i.name,
                  '%s/cakeml_end_source' % i.name, '%s/linker' % i.name):
            try:
                template = templates.lookup(t, i)
                g = ''
                if template:
                    g = r.render(
                        i,
                        assembly,
                        template,
                        renderoptions.render_state,
                        i.address_space,
                        outfile_name=None,
                        options=renderoptions,
                        my_pd=renderoptions.render_state.pds[i.address_space])
                for (item, outfile) in (all_items - done_items):
                    if item == t:
                        if not template:
                            log.warning('Warning: no template for %s' % item)
                        done(g, outfile, item, r, read)
                        break
            except TemplateError as inst:
                die(rendering_error(i.name, inst))

    # Instantiate the per-connection files.
    for c in assembly.composition.connections:

        for t in (('%s/from/source' % c.name,
                   c.from_ends), ('%s/from/header' % c.name, c.from_ends),
                  ('%s/to/source' % c.name,
                   c.to_ends), ('%s/to/header' % c.name, c.to_ends),
                  ('%s/to/cakeml' % c.name, c.to_ends)):

            template = templates.lookup(t[0], c)

            if template is not None:
                for id, e in enumerate(t[1]):
                    item = '%s/%d' % (t[0], id)
                    g = ''
                    try:
                        g = r.render(e,
                                     assembly,
                                     template,
                                     renderoptions.render_state,
                                     e.instance.address_space,
                                     outfile_name=None,
                                     options=renderoptions,
                                     my_pd=renderoptions.render_state.pds[
                                         e.instance.address_space])
                    except TemplateError as inst:
                        die(rendering_error(item, inst))
                    except jinja2.exceptions.TemplateNotFound:
                        die('While rendering %s: missing template for %s' %
                            (item, c.type.name))
                    for (target, outfile) in (all_items - done_items):
                        if target == item:
                            if not template:
                                log.warning('Warning: no template for %s' %
                                            item)
                            done(g, outfile, item, r, read)
                            break

        # The following block handles instantiations of per-connection
        # templates that are neither a 'source' or a 'header', as handled
        # above. We assume that none of these need instantiation unless we are
        # actually currently looking for them (== options.item). That is, we
        # assume that following templates, like the CapDL spec, do not require
        # these templates to be rendered prior to themselves.
        # FIXME: This is a pretty ugly way of handling this. It would be nicer
        # for the runner to have a more general notion of per-'thing' templates
        # where the per-component templates, the per-connection template loop
        # above, and this loop could all be done in a single unified control
        # flow.
        for (item, outfile) in (all_items - done_items):
            for t in (('%s/from/' % c.name, c.from_ends), ('%s/to/' % c.name,
                                                           c.to_ends)):

                if not item.startswith(t[0]):
                    # This is not the item we're looking for.
                    continue

                # If we've reached here then this is the exact item we're after.
                template = templates.lookup(item, c)
                if template is None:
                    die('no registered template for %s' % item)

                for e in t[1]:
                    try:
                        g = r.render(e,
                                     assembly,
                                     template,
                                     renderoptions.render_state,
                                     e.instance.address_space,
                                     outfile_name=None,
                                     options=renderoptions,
                                     my_pd=renderoptions.render_state.pds[
                                         e.instance.address_space])
                        done(g, outfile, item, r, read)
                    except TemplateError as inst:
                        die(rendering_error(item, inst))

    # Perform any per component special generation. This needs to happen last
    # as these template needs to run after all other capabilities have been
    # allocated
    for i in assembly.composition.instances:
        # Don't generate any code for hardware components.
        if i.type.hardware:
            continue
        assert i.address_space in renderoptions.render_state.cspaces
        SPECIAL_TEMPLATES = [('debug', 'debug'), ('simple', 'simple'),
                             ('rump_config', 'rumprun')]
        for special in [
                bl for bl in SPECIAL_TEMPLATES
                if assembly.configuration[i.name].get(bl[0])
        ]:
            for t in ('%s/%s' % (i.name, special[1]), ):
                try:
                    template = templates.lookup(t, i)
                    g = ''
                    if template:
                        g = r.render(i,
                                     assembly,
                                     template,
                                     renderoptions.render_state,
                                     i.address_space,
                                     outfile_name=None,
                                     options=renderoptions,
                                     my_pd=renderoptions.render_state.pds[
                                         i.address_space])
                    for (item, outfile) in (all_items - done_items):
                        if item == t:
                            if not template:
                                log.warning('Warning: no template for %s' %
                                            item)
                            done(g, outfile, item, r, read)
                except TemplateError as inst:
                    die(rendering_error(i.name, inst))

    # Check if there are any remaining items
    not_done = all_items - done_items
    if len(not_done) > 0:
        for (item, outfile) in not_done:
            err.write('No valid element matching --item %s.\n' % item)
        return -1
    return 0