Registers a target type, possibly derived from a 'base-type'.
        If 'suffixes' are provided, they list all the suffixes that mean a file is of 'type'.
        Also, the first element gives the suffix to be used when constructing and object of
        'type'.
        type: a string
        suffixes: None or a sequence of strings
        base_type: None or a string

def register (type, suffixes = [], base_type = None):
    """ Registers a target type, possibly derived from a 'base-type'.
        If 'suffixes' are provided, they list all the suffixes that mean a file is of 'type'.
        Also, the first element gives the suffix to be used when constructing and object of
        'type'.
        type: a string
        suffixes: None or a sequence of strings
        base_type: None or a string
    """
    # Type names cannot contain hyphens, because when used as
    # feature-values they will be interpreted as composite features
    # which need to be decomposed.
    if __re_hyphen.search (type):
        raise BaseException ('type name "%s" contains a hyphen' % type)

    # it's possible for a type to be registered with a
    # base type that hasn't been registered yet. in the
    # check for base_type below and the following calls to setdefault()
    # the key `type` will be added to __types. When the base type
    # actually gets registered, it would fail after the simple check
    # of "type in __types"; thus the check for "'base' in __types[type]"
    if type in __types and 'base' in __types[type]:
        raise BaseException ('Type "%s" is already registered.' % type)

    entry = __types.setdefault(type, {})
    entry['base'] = base_type
    entry.setdefault('derived', [])
    entry.setdefault('scanner', None)

    if base_type:
        __types.setdefault(base_type, {}).setdefault('derived', []).append(type)

    if len (suffixes) > 0:
        # Generated targets of 'type' will use the first of 'suffixes'
        # (this may be overriden)
        set_generated_target_suffix (type, [], suffixes [0])

        # Specify mapping from suffixes to type
        register_suffixes (suffixes, type)

    feature.extend('target-type', [type])
    feature.extend('main-target-type', [type])
    feature.extend('base-target-type', [type])

    if base_type:
        feature.compose ('<target-type>' + type, [replace_grist (base_type, '<base-target-type>')])
        feature.compose ('<base-target-type>' + type, ['<base-target-type>' + base_type])

    import b2.build.generators as generators
    # Adding a new derived type affects generator selection so we need to
    # make the generator selection module update any of its cached
    # information related to a new derived type being defined.
    generators.update_cached_information_with_a_new_type(type)

    # FIXME: resolving recursive dependency.
    from b2.manager import get_manager
    get_manager().projects().project_rules().add_rule_for_type(type)