def get_prebuilt_targets(build_context):
    """Return set of target names that are contained within cached base images

    These targets may be considered "pre-built", and skipped during build.
    """
    logger.info('Scanning for cached base images')
    # deps that are part of cached based images
    contained_deps = set()
    # deps that are needed by images that are going to be built,
    # but are not part of their base images
    required_deps = set()
    # mapping from target name to set of all its deps (descendants)
    cached_descendants = CachedDescendants(build_context.target_graph)

    for target_name, target in build_context.targets.items():
        if 'image_caching_behavior' not in target.props:
            continue
        image_name = get_image_name(target)
        image_tag = target.props.image_tag
        icb = ImageCachingBehavior(image_name, image_tag,
                                   target.props.image_caching_behavior)
        target.image_id = handle_build_cache(build_context.conf, image_name,
                                             image_tag, icb)
        if target.image_id:
            # mark deps of cached base image as "contained"
            image_deps = cached_descendants.get(target_name)
            contained_deps.update(image_deps)
            contained_deps.add(target.name)
        else:
            # mark deps of image that is going to be built
            # (and are not deps of its base image) as "required"
            image_deps = cached_descendants.get(target_name)
            base_image_deps = cached_descendants.get(target.props.base_image)
            required_deps.update(image_deps - base_image_deps)
    return contained_deps - required_deps
Return set of target names that are contained within cached base images

    These targets may be considered "pre-built", and skipped during build.