def link_cpp_artifacts(build_context, target, workspace_dir,
                       include_objects: bool):
    """Link required artifacts from dependencies under target workspace dir.
       Return list of object files of dependencies (if `include_objects`).

    Includes:
    - Generated code from proto dependencies
    - Header files from all dependencies
    - Generated header files from all dependencies
    - If `include_objects` is True, also object files from all dependencies
      (these will be returned without linking)
    """
    # include the source & header files of the current target
    # add objects of all dependencies (direct & transitive), if needed
    source_files = target.props.sources + target.props.headers
    generated_srcs = {}
    objects = []

    # add headers of dependencies
    for dep in build_context.generate_all_deps(target):
        source_files.extend(dep.props.get('headers', []))

    link_files(source_files, workspace_dir, None, build_context.conf)

    # add generated headers and collect objects of dependencies
    for dep in build_context.generate_all_deps(target):
        dep.artifacts.link_types(workspace_dir, [AT.gen_h], build_context.conf)
        if include_objects:
            objects.extend(dep.artifacts.get(AT.object).values())

    # add generated code from proto dependencies
    for proto_dep_name in target.props.protos:
        proto_dep = build_context.targets[proto_dep_name]
        proto_dep.artifacts.link_types(workspace_dir, [AT.gen_cc],
                                       build_context.conf)

    return objects