ADD: added new version of protobuf

This commit is contained in:
Henry Winkel
2022-12-20 10:09:28 +01:00
parent 4a79559129
commit 1e2b3dda7b
1513 changed files with 123720 additions and 83381 deletions

View File

@@ -7,7 +7,7 @@ load(
"strip_prefix",
)
load("//:protobuf_release.bzl", "package_naming")
load(":build_systems.bzl", "gen_file_lists")
load(":build_systems.bzl", "gen_automake_file_lists", "gen_file_lists")
load(":cc_dist_library.bzl", "cc_dist_library")
package_naming(
@@ -17,8 +17,17 @@ package_naming(
pkg_files(
name = "wkt_protos_files",
srcs = [
"//:well_known_type_protos",
"//src/google/protobuf:descriptor_proto_srcs",
"//:src/google/protobuf/any.proto",
"//:src/google/protobuf/api.proto",
"//:src/google/protobuf/descriptor.proto",
"//:src/google/protobuf/duration.proto",
"//:src/google/protobuf/empty.proto",
"//:src/google/protobuf/field_mask.proto",
"//:src/google/protobuf/source_context.proto",
"//:src/google/protobuf/struct.proto",
"//:src/google/protobuf/timestamp.proto",
"//:src/google/protobuf/type.proto",
"//:src/google/protobuf/wrappers.proto",
],
prefix = "include/google/protobuf",
visibility = ["//visibility:private"],
@@ -26,9 +35,7 @@ pkg_files(
pkg_files(
name = "compiler_plugin_protos_files",
srcs = [
"//src/google/protobuf/compiler:compiler_plugin_protos_files",
],
srcs = ["//:src/google/protobuf/compiler/plugin.proto"],
prefix = "include/google/protobuf/compiler",
visibility = ["//visibility:private"],
)
@@ -88,10 +95,10 @@ pkg_filegroup(
srcs = [
":dist_files",
"//:common_dist_files",
"//:cpp_dist_files", # to build protoc
"//benchmarks:all_dist_files",
"//build_defs:dist_files",
"//conformance:all_dist_files",
"//src:all_dist_files",
"//third_party/utf8_range:dist_files",
"@com_google_protobuf_examples//:dist_files",
],
)
@@ -100,7 +107,7 @@ pkg_filegroup(
name = "cpp_srcs",
srcs = [
":dist_common",
"//src:all_dist_files",
"//:cpp_dist_files",
],
)
@@ -222,7 +229,7 @@ pkg_filegroup(
name = "python_srcs",
srcs = [
":dist_common",
"//python:dist_files",
"//:python_dist_files",
],
)
@@ -304,31 +311,30 @@ gen_file_lists(
testonly = 1,
out_stem = "src_file_lists",
src_libs = {
# {[source rule]: [name in generated file]}
# Libraries:
":protobuf": "libprotobuf",
":protobuf_lite": "libprotobuf_lite",
":protoc": "libprotoc",
# Protos:
"//src/google/protobuf:well_known_type_protos": "wkt_protos",
"//src/google/protobuf:descriptor_proto": "descriptor_proto",
"//src/google/protobuf/compiler:plugin_proto": "plugin_proto",
# Test libraries:
":common_test": "common_test",
":lite_test_util": "lite_test_util",
":test_util": "test_util",
# Tests and test-only protos:
"//src/google/protobuf:full_test_srcs": "protobuf_test",
"//src/google/protobuf:test_proto_srcs": "protobuf_test_protos",
"//src/google/protobuf:lite_test_srcs": "protobuf_lite_test",
"//src/google/protobuf:lite_test_proto_srcs": "protobuf_lite_test_protos",
"//src/google/protobuf/compiler:test_srcs": "compiler_test",
"//src/google/protobuf/compiler:test_proto_srcs": "compiler_test_protos",
"//src/google/protobuf/compiler:test_plugin_srcs": "test_plugin",
"//src/google/protobuf/io:test_srcs": "io_test",
"//src/google/protobuf/util:test_srcs": "util_test",
"//src/google/protobuf/util:test_proto_srcs": "util_test_protos",
"//src/google/protobuf/stubs:test_srcs": "stubs_test",
# source rule: name in generated file
"//:protobuf": "libprotobuf",
"//:protoc_lib": "libprotoc",
"//:protobuf_lite": "libprotobuf_lite",
},
)
gen_automake_file_lists(
name = "gen_automake_extra_dist_lists",
testonly = 1,
out = "extra_dist_file_lists.am",
src_libs = {
# source rule: name in generated file
"//:common_dist_files": "dist_common",
"//conformance:dist_files": "dist_conformance",
"//benchmarks:all_dist_files": "dist_benchmark",
"@com_google_protobuf_examples//:dist_files": "dist_example",
"//:csharp_dist_files": "dist_csharp",
"//csharp:dist_files": "dist_csharp2",
"//:objectivec_dist_files": "dist_objectivec",
"//objectivec:dist_files": "dist_objectivec2",
"//php:dist_files": "dist_php",
"//:python_dist_files": "dist_python",
"//ruby:dist_files": "dist_ruby",
},
)
@@ -342,17 +348,8 @@ cc_dist_library(
"//build_defs:config_msvc": [],
"//conditions:default": ["-lpthread"],
}),
tags = ["manual"],
deps = [
"//src/google/protobuf:arena",
"//src/google/protobuf:arena_align",
"//src/google/protobuf:arena_allocation_policy",
"//src/google/protobuf:arena_cleanup",
"//src/google/protobuf:arena_config",
"//src/google/protobuf:protobuf_lite",
"//src/google/protobuf/io",
"//src/google/protobuf/io:io_win32",
"//src/google/protobuf/stubs:lite",
"//:protobuf_lite",
],
)
@@ -365,99 +362,12 @@ cc_dist_library(
"-lpthread",
],
}),
tags = ["manual"],
deps = [
"//src/google/protobuf:wkt_cc_proto",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf:arena",
"//src/google/protobuf:arena_align",
"//src/google/protobuf:arena_allocation_policy",
"//src/google/protobuf:arena_cleanup",
"//src/google/protobuf:arena_config",
"//src/google/protobuf:protobuf_lite",
"//src/google/protobuf:port_def",
"//src/google/protobuf/compiler:importer",
"//src/google/protobuf/io",
"//src/google/protobuf/io:gzip_stream",
"//src/google/protobuf/io:io_win32",
"//src/google/protobuf/io:printer",
"//src/google/protobuf/io:tokenizer",
"//src/google/protobuf/io:zero_copy_sink",
"//src/google/protobuf/json",
"//src/google/protobuf/json:descriptor_traits",
"//src/google/protobuf/json:lexer",
"//src/google/protobuf/json:message_path",
"//src/google/protobuf/json:parser",
"//src/google/protobuf/json:unparser",
"//src/google/protobuf/json:untyped_message",
"//src/google/protobuf/json:writer",
"//src/google/protobuf/json:zero_copy_buffered_stream",
"//src/google/protobuf/stubs",
"//src/google/protobuf/stubs:lite",
"//src/google/protobuf/util:delimited_message_util",
"//src/google/protobuf/util:differencer",
"//src/google/protobuf/util:field_mask_util",
"//src/google/protobuf/util:json_util",
"//src/google/protobuf/util:time_util",
"//src/google/protobuf/util:type_resolver_util",
"//:protobuf",
"//:protobuf_lite",
],
)
cc_dist_library(
name = "protoc",
tags = ["manual"],
deps = [
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf/compiler:command_line_interface",
"//src/google/protobuf/compiler/cpp",
"//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf/compiler/cpp:names_internal",
"//src/google/protobuf/compiler/csharp",
"//src/google/protobuf/compiler/csharp:names",
"//src/google/protobuf/compiler/java",
"//src/google/protobuf/compiler/java:names",
"//src/google/protobuf/compiler/java:names_internal",
"//src/google/protobuf/compiler/objectivec",
"//src/google/protobuf/compiler/objectivec:line_consumer",
"//src/google/protobuf/compiler/objectivec:names",
"//src/google/protobuf/compiler/objectivec:names_internal",
"//src/google/protobuf/compiler/php",
"//src/google/protobuf/compiler/php:names",
"//src/google/protobuf/compiler/python",
"//src/google/protobuf/compiler/ruby",
],
)
cc_dist_library(
name = "lite_test_util",
testonly = 1,
tags = ["manual"],
deps = ["//src/google/protobuf:lite_test_util"],
)
cc_dist_library(
name = "test_util",
testonly = 1,
tags = ["manual"],
deps = [
"//src/google/protobuf:test_util",
"//src/google/protobuf:test_util2",
"//src/google/protobuf/compiler:annotation_test_util",
"//src/google/protobuf/compiler/cpp:unittest_lib",
],
)
cc_dist_library(
name = "common_test",
testonly = 1,
tags = ["manual"],
deps = [
"//src/google/protobuf/testing",
"//src/google/protobuf/compiler:mock_code_generator",
],
)
################################################################################
# Distribution sources
################################################################################

View File

@@ -1,7 +1,6 @@
# Starlark utilities for working with other build systems
load("@rules_pkg//:providers.bzl", "PackageFilegroupInfo", "PackageFilesInfo")
load(":cc_dist_library.bzl", "CcFileList")
################################################################################
# Macro to create CMake and Automake source lists.
@@ -14,18 +13,39 @@ def gen_file_lists(name, out_stem, **kwargs):
source_prefix = "${protobuf_SOURCE_DIR}/",
**kwargs
)
gen_automake_file_lists(
name = name + "_automake",
out = out_stem + ".am",
source_prefix = "$(top_srcdir)/",
**kwargs
)
native.filegroup(
name = name,
srcs = [
out_stem + ".cmake",
out_stem + ".am",
],
visibility = ["//src:__pkg__"],
)
################################################################################
# Aspect that extracts srcs, hdrs, etc.
################################################################################
CcFileList = provider(
doc = "List of files to be built into a library.",
fields = {
# As a rule of thumb, `hdrs` and `textual_hdrs` are the files that
# would be installed along with a prebuilt library.
"hdrs": "public header files, including those used by generated code",
"textual_hdrs": "files which are included but are not self-contained",
# The `internal_hdrs` are header files which appear in `srcs`.
# These are only used when compiling the library.
"internal_hdrs": "internal header files (only used to build .cc files)",
"srcs": "source files",
},
)
ProtoFileList = provider(
doc = "List of proto files and generated code to be built into a library.",
fields = {
@@ -45,11 +65,56 @@ def _flatten_target_files(targets):
files.append(tfile)
return files
def _combine_cc_file_lists(file_lists):
hdrs = {}
textual_hdrs = {}
internal_hdrs = {}
srcs = {}
for file_list in file_lists:
hdrs.update({f: 1 for f in file_list.hdrs})
textual_hdrs.update({f: 1 for f in file_list.textual_hdrs})
internal_hdrs.update({f: 1 for f in file_list.internal_hdrs})
srcs.update({f: 1 for f in file_list.srcs})
return CcFileList(
hdrs = sorted(hdrs.keys()),
textual_hdrs = sorted(textual_hdrs.keys()),
internal_hdrs = sorted(internal_hdrs.keys()),
srcs = sorted(srcs.keys()),
)
def _file_list_aspect_impl(target, ctx):
# We're going to reach directly into the attrs on the traversed rule.
rule_attr = ctx.rule.attr
providers = []
# Extract sources from a `cc_library` (or similar):
if CcInfo in target:
# CcInfo is a proxy for what we expect this rule to look like.
# However, some deps may expose `CcInfo` without having `srcs`,
# `hdrs`, etc., so we use `getattr` to handle that gracefully.
internal_hdrs = []
srcs = []
# Filter `srcs` so it only contains source files. Headers will go
# into `internal_headers`.
for src in _flatten_target_files(getattr(rule_attr, "srcs", [])):
if src.extension.lower() in ["c", "cc", "cpp", "cxx"]:
srcs.append(src)
else:
internal_hdrs.append(src)
providers.append(CcFileList(
hdrs = _flatten_target_files(getattr(rule_attr, "hdrs", [])),
textual_hdrs = _flatten_target_files(getattr(
rule_attr,
"textual_hdrs",
[],
)),
internal_hdrs = internal_hdrs,
srcs = srcs,
))
# Extract sources from a `proto_library`:
if ProtoInfo in target:
proto_srcs = []
@@ -113,7 +178,7 @@ Output is CcFileList and/or ProtoFileList. Example:
# fragment generator function.
################################################################################
def _create_file_list_impl(ctx, fragment_generator):
def _create_file_list_impl(fragment_generator):
# `fragment_generator` is a function like:
# def fn(originating_rule: Label,
# varname: str,
@@ -126,98 +191,92 @@ def _create_file_list_impl(ctx, fragment_generator):
# When dealing with `File` objects, the `short_path` is used to strip
# the output prefix for generated files.
out = ctx.outputs.out
def _impl(ctx):
out = ctx.outputs.out
fragments = []
for srcrule, libname in ctx.attr.src_libs.items():
if CcFileList in srcrule:
cc_file_list = srcrule[CcFileList]
fragments = []
for srcrule, libname in ctx.attr.src_libs.items():
if CcFileList in srcrule:
cc_file_list = srcrule[CcFileList]
fragments.extend([
fragment_generator(
srcrule.label,
libname + "_srcs",
ctx.attr.source_prefix,
[f.short_path for f in cc_file_list.srcs],
),
fragment_generator(
srcrule.label,
libname + "_hdrs",
ctx.attr.source_prefix,
[f.short_path for f in (cc_file_list.hdrs +
cc_file_list.textual_hdrs)],
),
])
# Turn depsets of files into sorted lists.
srcs = sorted(cc_file_list.srcs.to_list())
hdrs = sorted(
depset(transitive = [
cc_file_list.textual_hdrs,
cc_file_list.hdrs,
]).to_list(),
)
if ProtoFileList in srcrule:
proto_file_list = srcrule[ProtoFileList]
fragments.extend([
fragment_generator(
srcrule.label,
libname + "_proto_srcs",
ctx.attr.source_prefix,
[f.short_path for f in proto_file_list.proto_srcs],
),
fragment_generator(
srcrule.label,
libname + "_srcs",
ctx.attr.source_prefix,
proto_file_list.srcs,
),
fragment_generator(
srcrule.label,
libname + "_hdrs",
ctx.attr.source_prefix,
proto_file_list.hdrs,
),
])
fragments.extend([
fragment_generator(
srcrule.label,
libname + "_srcs",
ctx.attr.source_prefix,
[f.short_path for f in srcs],
),
fragment_generator(
srcrule.label,
libname + "_hdrs",
ctx.attr.source_prefix,
[f.short_path for f in hdrs],
),
])
files = {}
if ProtoFileList in srcrule:
proto_file_list = srcrule[ProtoFileList]
fragments.extend([
fragment_generator(
srcrule.label,
libname + "_proto_srcs",
ctx.attr.source_prefix,
[f.short_path for f in proto_file_list.proto_srcs],
),
fragment_generator(
srcrule.label,
libname + "_srcs",
ctx.attr.source_prefix,
proto_file_list.srcs,
),
fragment_generator(
srcrule.label,
libname + "_hdrs",
ctx.attr.source_prefix,
proto_file_list.hdrs,
),
])
if PackageFilegroupInfo in srcrule:
for pkg_files_info, origin in srcrule[PackageFilegroupInfo].pkg_files:
# keys are the destination path:
files.update(pkg_files_info.dest_src_map)
files = {}
if PackageFilesInfo in srcrule:
# keys are the destination:
files.update(srcrule[PackageFilesInfo].dest_src_map)
if PackageFilegroupInfo in srcrule:
for pkg_files_info, origin in srcrule[PackageFilegroupInfo].pkg_files:
# keys are the destination path:
files.update(pkg_files_info.dest_src_map)
if files == {} and DefaultInfo in srcrule and CcInfo not in srcrule:
# This could be an individual file or filegroup.
# We explicitly ignore rules with CcInfo, since their
# output artifacts are libraries or binaries.
files.update(
{
f.short_path: 1
for f in srcrule[DefaultInfo].files.to_list()
},
)
if PackageFilesInfo in srcrule:
# keys are the destination:
files.update(srcrule[PackageFilesInfo].dest_src_map)
if files:
fragments.append(
fragment_generator(
srcrule.label,
libname + "_files",
ctx.attr.source_prefix,
sorted(files.keys()),
),
)
if files == {} and DefaultInfo in srcrule and CcFileList not in srcrule:
# This could be an individual file or filegroup.
# We explicitly ignore rules with CcInfo, since their
# output artifacts are libraries or binaries.
files.update(
{
f.short_path: 1
for f in srcrule[DefaultInfo].files.to_list()
},
)
ctx.actions.write(
output = out,
content = (ctx.attr._header % ctx.label) + "\n".join(fragments),
)
if files:
fragments.append(
fragment_generator(
srcrule.label,
libname + "_files",
ctx.attr.source_prefix,
sorted(files.keys()),
),
)
return [DefaultInfo(files = depset([out]))]
ctx.actions.write(
output = out,
content = (ctx.attr._header % ctx.label) + "\n".join(fragments),
)
return [DefaultInfo(files = depset([out]))]
return _impl
# Common rule attrs for rules that use `_create_file_list_impl`:
# (note that `_header` is also required)
@@ -284,9 +343,6 @@ def _cmake_var_fragment(owner, varname, prefix, entries):
entries = "\n".join([" %s%s" % (prefix, f) for f in entries]),
)
def _cmake_file_list_impl(ctx):
_create_file_list_impl(ctx, _cmake_var_fragment)
gen_cmake_file_lists = rule(
doc = """
Generates a CMake-syntax file with lists of files.
@@ -305,7 +361,7 @@ For proto_library, the following are generated:
{libname}_hdrs: contains syntesized paths for generated C++ headers.
""",
implementation = _cmake_file_list_impl,
implementation = _create_file_list_impl(_cmake_var_fragment),
attrs = dict(
_source_list_common_attrs,
_header = attr.string(
@@ -325,3 +381,72 @@ endif()
),
),
)
################################################################################
# Automake source lists generation
################################################################################
def _automake_var_fragment(owner, varname, prefix, entries):
"""Returns a single variable assignment fragment (Automake syntax).
Args:
owner: Label, the rule that owns these srcs.
varname: str, the var name to set.
prefix: str, prefix to prepend to each of `entries`.
entries: [str], the entries in the list.
Returns:
A string.
"""
if len(entries) == 0:
# A backslash followed by a blank line is illegal. We still want
# to emit the variable, though.
return "# {owner}\n{varname} =\n".format(
owner = owner,
varname = varname,
)
fragment = (
"# {owner}\n" +
"{varname} = \\\n" +
"{entries}"
).format(
owner = owner,
varname = varname,
entries = " \\\n".join([" %s%s" % (prefix, f) for f in entries]),
)
return fragment.rstrip("\\ ") + "\n"
gen_automake_file_lists = rule(
doc = """
Generates an Automake-syntax file with lists of files.
The generated file defines variables with lists of files from `srcs`. The
intent is for these files to be included from a non-generated Makefile.am
file which actually defines the libraries based on these lists.
For C++ rules, the following are generated:
{libname}_srcs: contains srcs.
{libname}_hdrs: contains hdrs and textual_hdrs.
For proto_library, the following are generated:
{libname}_proto_srcs: contains the srcs from the `proto_library` rule.
{libname}_srcs: contains syntesized paths for generated C++ sources.
{libname}_hdrs: contains syntesized paths for generated C++ headers.
""",
implementation = _create_file_list_impl(_automake_var_fragment),
attrs = dict(
_source_list_common_attrs.items(),
_header = attr.string(
default = """\
# Auto-generated by %s
#
# This file contains lists of sources based on Bazel rules. It should
# be included from a hand-written Makefile.am that defines targets.
#
# Changes to this file will be overwritten based on Bazel definitions.
""",
),
),
)

View File

@@ -3,32 +3,12 @@
load("@rules_cc//cc:action_names.bzl", cc_action_names = "ACTION_NAMES")
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
################################################################################
# Archive/linking support
################################################################################
def _collect_linker_input_objects(dep_label, cc_info, objs, pic_objs):
"""Accumulate .o and .pic.o files into `objs` and `pic_objs`."""
link_ctx = cc_info.linking_context
if link_ctx == None:
return
linker_inputs = link_ctx.linker_inputs.to_list()
for link_input in linker_inputs:
if link_input.owner != dep_label:
# This is a transitive dep: skip it.
continue
for lib in link_input.libraries:
objs.extend(lib.objects or [])
pic_objs.extend(lib.pic_objects or [])
# Creates an action to build the `output_file` static library (archive)
# using `object_files`.
def _create_archive_action(
ctx,
feature_configuration,
cc_toolchain_info,
cc_toolchain,
output_file,
object_files):
# Based on Bazel's src/main/starlark/builtins_bzl/common/cc/cc_import.bzl:
@@ -36,7 +16,7 @@ def _create_archive_action(
# Build the command line and add args for all of the input files:
archiver_variables = cc_common.create_link_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain_info,
cc_toolchain = cc_toolchain,
output_file = output_file.path,
is_using_linker = False,
)
@@ -68,23 +48,80 @@ def _create_archive_action(
inputs = depset(
direct = object_files,
transitive = [
cc_toolchain_info.all_files,
cc_toolchain.all_files,
],
),
use_default_shell_env = False,
use_default_shell_env = True,
outputs = [output_file],
mnemonic = "CppArchiveDist",
)
def _create_dso_link_action(
ctx,
feature_configuration,
cc_toolchain_info,
object_files,
pic_object_files):
# Implementation for cc_dist_library rule.
def _cc_dist_library_impl(ctx):
cc_toolchain_info = find_cc_toolchain(ctx)
if cc_toolchain_info.ar_executable == None:
return []
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain_info,
)
# Collect the set of object files from the immediate deps.
objs = []
pic_objs = []
for dep in ctx.attr.deps:
if CcInfo not in dep:
continue
link_ctx = dep[CcInfo].linking_context
if link_ctx == None:
continue
linker_inputs = link_ctx.linker_inputs.to_list()
for link_input in linker_inputs:
if link_input.owner != dep.label:
# This is a transitive dep: skip it.
continue
for lib in link_input.libraries:
objs.extend(lib.objects or [])
pic_objs.extend(lib.pic_objects or [])
# For static libraries, build separately with and without pic.
stemname = "lib" + ctx.label.name
outputs = []
if len(objs) > 0:
archive_out = ctx.actions.declare_file(stemname + ".a")
_create_archive_action(
ctx,
feature_configuration,
cc_toolchain_info,
archive_out,
objs,
)
outputs.append(archive_out)
if len(pic_objs) > 0:
pic_archive_out = ctx.actions.declare_file(stemname + ".pic.a")
_create_archive_action(
ctx,
feature_configuration,
cc_toolchain_info,
pic_archive_out,
pic_objs,
)
outputs.append(pic_archive_out)
# For dynamic libraries, use the `cc_common.link` command to ensure
# everything gets built correctly according to toolchain definitions.
compilation_outputs = cc_common.create_compilation_outputs(
objects = depset(object_files),
pic_objects = depset(pic_object_files),
objects = depset(objs),
pic_objects = depset(pic_objs),
)
link_output = cc_common.link(
actions = ctx.actions,
@@ -97,8 +134,6 @@ def _create_dso_link_action(
)
library_to_link = link_output.library_to_link
outputs = []
# Note: library_to_link.dynamic_library and interface_library are often
# symlinks in the solib directory. For DefaultInfo, prefer reporting
# the resolved artifact paths.
@@ -112,207 +147,6 @@ def _create_dso_link_action(
elif library_to_link.interface_library != None:
outputs.append(library_to_link.interface_library)
return outputs
################################################################################
# Source file/header support
################################################################################
CcFileList = provider(
doc = "List of files to be built into a library.",
fields = {
# As a rule of thumb, `hdrs` and `textual_hdrs` are the files that
# would be installed along with a prebuilt library.
"hdrs": "public header files, including those used by generated code",
"textual_hdrs": "files which are included but are not self-contained",
# The `internal_hdrs` are header files which appear in `srcs`.
# These are only used when compiling the library.
"internal_hdrs": "internal header files (only used to build .cc files)",
"srcs": "source files",
},
)
def _flatten_target_files(targets):
return depset(transitive = [target.files for target in targets])
files = []
for target in targets:
files.extend(target.files.to_list())
return files
def _cc_file_list_aspect_impl(target, ctx):
# Extract sources from a `cc_library` (or similar):
if CcInfo not in target:
return []
# We're going to reach directly into the attrs on the traversed rule.
rule_attr = ctx.rule.attr
# CcInfo is a proxy for what we expect this rule to look like.
# However, some deps may expose `CcInfo` without having `srcs`,
# `hdrs`, etc., so we use `getattr` to handle that gracefully.
internal_hdrs = []
srcs = []
# Filter `srcs` so it only contains source files. Headers will go
# into `internal_headers`.
for src in _flatten_target_files(getattr(rule_attr, "srcs", [])).to_list():
if src.extension.lower() in ["c", "cc", "cpp", "cxx"]:
srcs.append(src)
else:
internal_hdrs.append(src)
return [CcFileList(
hdrs = _flatten_target_files(getattr(rule_attr, "hdrs", depset())),
textual_hdrs = _flatten_target_files(getattr(
rule_attr,
"textual_hdrs",
depset(),
)),
internal_hdrs = depset(internal_hdrs),
srcs = depset(srcs),
)]
cc_file_list_aspect = aspect(
doc = """
Aspect to provide the list of sources and headers from a rule.
Output is CcFileList. Example:
cc_library(
name = "foo",
srcs = [
"foo.cc",
"foo_internal.h",
],
hdrs = ["foo.h"],
textual_hdrs = ["foo_inl.inc"],
)
# produces:
# CcFileList(
# hdrs = depset([File("foo.h")]),
# textual_hdrs = depset([File("foo_inl.inc")]),
# internal_hdrs = depset([File("foo_internal.h")]),
# srcs = depset([File("foo.cc")]),
# )
""",
implementation = _cc_file_list_aspect_impl,
)
################################################################################
# Rule impl
################################################################################
def _collect_inputs(deps):
"""Collects files from a list of immediate deps.
This rule collects source files and linker inputs for C++ deps. Only
these immediate deps are considered, not transitive deps.
The return value is a struct with object files (linker inputs),
partitioned by PIC and non-pic, and the rules' source and header files:
struct(
objects = ..., # non-PIC object files
pic_objects = ..., # PIC objects
cc_file_list = ..., # a CcFileList
)
Args:
deps: Iterable of immediate deps. These will be treated as the "inputs,"
but not the transitive deps.
Returns:
A struct with linker inputs, source files, and header files.
"""
objs = []
pic_objs = []
# The returned CcFileList will contain depsets of the deps' file lists.
# These lists hold `depset()`s from each of `deps`.
srcs = []
hdrs = []
internal_hdrs = []
textual_hdrs = []
for dep in deps:
if CcInfo in dep:
_collect_linker_input_objects(
dep.label,
dep[CcInfo],
objs,
pic_objs,
)
if CcFileList in dep:
cfl = dep[CcFileList]
srcs.append(cfl.srcs)
hdrs.append(cfl.hdrs)
internal_hdrs.append(cfl.internal_hdrs)
textual_hdrs.append(cfl.textual_hdrs)
return struct(
objects = objs,
pic_objects = pic_objs,
cc_file_list = CcFileList(
srcs = depset(transitive = srcs),
hdrs = depset(transitive = hdrs),
internal_hdrs = depset(transitive = internal_hdrs),
textual_hdrs = depset(transitive = textual_hdrs),
),
)
# Implementation for cc_dist_library rule.
def _cc_dist_library_impl(ctx):
cc_toolchain_info = find_cc_toolchain(ctx)
feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain_info,
)
inputs = _collect_inputs(ctx.attr.deps)
# For static libraries, build separately with and without pic.
stemname = "lib" + ctx.label.name
outputs = []
if len(inputs.objects) > 0:
archive_out = ctx.actions.declare_file(stemname + ".a")
_create_archive_action(
ctx,
feature_configuration,
cc_toolchain_info,
archive_out,
inputs.objects,
)
outputs.append(archive_out)
if len(inputs.pic_objects) > 0:
pic_archive_out = ctx.actions.declare_file(stemname + ".pic.a")
_create_archive_action(
ctx,
feature_configuration,
cc_toolchain_info,
pic_archive_out,
inputs.pic_objects,
)
outputs.append(pic_archive_out)
# For dynamic libraries, use the `cc_common.link` command to ensure
# everything gets built correctly according to toolchain definitions.
outputs.extend(_create_dso_link_action(
ctx,
feature_configuration,
cc_toolchain_info,
inputs.objects,
inputs.pic_objects,
))
# We could expose the libraries for use from cc rules:
#
# linking_context = cc_common.create_linking_context(
@@ -335,7 +169,6 @@ def _cc_dist_library_impl(ctx):
return [
DefaultInfo(files = depset(outputs)),
inputs.cc_file_list,
]
cc_dist_library = rule(
@@ -381,7 +214,6 @@ Example:
"Only these targets' compilation outputs will be " +
"included (i.e., the transitive dependencies are not " +
"included in the output)."),
aspects = [cc_file_list_aspect],
),
"linkopts": attr.string_list(
doc = ("Add these flags to the C++ linker command when creating " +