Skip to content

Commit

Permalink
Initial support in build_dependencies.bzl for c/c++.
Browse files Browse the repository at this point in the history
This CL adds basic support for reporting information needed for C++ compilation in a dependencies build. Unlike the java support where we collect jars per dependency target, for C++ we don't traverse the deps but instead just rely on bazel to collect the transitive information for as, and report that directly. This may not be the long term approach, but works well enough for now to make a start with C++ support.

We do however follow the `_cc_toolchain` attributes in order to gather information about the toolchain in use.

Rename soime existing java specific methods to make it clear that they are java specific, and give the new code cc specific names accordingly.

PiperOrigin-RevId: 571010937
  • Loading branch information
Googler authored and copybara-github committed Oct 5, 2023
1 parent ece6e38 commit e73603f
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 16 deletions.
157 changes: 143 additions & 14 deletions aspect/build_dependencies.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,40 @@ PROTO_RULE_KINDS = [
]

def _package_dependencies_impl(target, ctx):
file_name = target.label.name + ".target-info.txt"
artifact_info_file = ctx.actions.declare_file(file_name)
ctx.actions.write(
artifact_info_file,
_encode_target_info_proto(target),
)
artifact_info_file = _write_java_target_info(target, ctx)
cc_info_file = _write_cc_target_info(target, ctx)

return [OutputGroupInfo(
qsync_jars = target[DependenciesInfo].compile_time_jars.to_list(),
artifact_info_file = [artifact_info_file],
artifact_info_file = artifact_info_file,
qsync_aars = target[DependenciesInfo].aars.to_list(),
qsync_gensrcs = target[DependenciesInfo].gensrcs.to_list(),
cc_headers = target[DependenciesInfo].cc_headers,
cc_info_file = cc_info_file,
)]

def _write_java_target_info(target, ctx):
if not target[DependenciesInfo].target_to_artifacts:
return []
file_name = target.label.name + ".target-info.txt"
artifact_info_file = ctx.actions.declare_file(file_name)
ctx.actions.write(
artifact_info_file,
_encode_target_info_proto(target[DependenciesInfo].target_to_artifacts),
)
return [artifact_info_file]

def _write_cc_target_info(target, ctx):
if not target[DependenciesInfo].cc_info:
return []
file_name = target.label.name + ".cc-info.txt"
cc_info_file = ctx.actions.declare_file(file_name)
ctx.actions.write(
cc_info_file,
_encode_cc_info_proto(target.label, target[DependenciesInfo].cc_info),
)
return [cc_info_file]

DependenciesInfo = provider(
"The out-of-project dependencies",
fields = {
Expand All @@ -32,12 +52,15 @@ DependenciesInfo = provider(
"aars": "a list of aars with resource files",
"gensrcs": "a list of sources generated by project targets",
"test_mode_own_files": "a structure describing artifacts required when the target is requested within the project scope",
"cc_info": "a structure containing info required to compile cc sources",
"cc_headers": "a list of generated headers required to compile cc sources",
"cc_toolchain_info": "a structure containing info about the cc toolchain",
},
)

def _encode_target_info_proto(target):
def _encode_target_info_proto(target_to_artifacts):
contents = []
for label, target_info in target[DependenciesInfo].target_to_artifacts.items():
for label, target_info in target_to_artifacts.items():
contents.append(
struct(
target = label,
Expand All @@ -50,6 +73,21 @@ def _encode_target_info_proto(target):
)
return proto.encode_text(struct(artifacts = contents))

def _encode_cc_info_proto(label, cc_info):
return proto.encode_text(
struct(targets = [
struct(
label = str(label),
defines = cc_info.transitive_defines,
include_directories = cc_info.transitive_include_directory,
quote_include_directories = cc_info.transitive_quote_include_directory,
system_include_directories = cc_info.transitive_system_include_directory,
gen_hdrs = cc_info.gen_headers,
cc_toolchain_info = cc_info.cc_toolchain_info,
),
]),
)

package_dependencies = aspect(
implementation = _package_dependencies_impl,
required_aspect_providers = [[DependenciesInfo]],
Expand Down Expand Up @@ -138,7 +176,7 @@ def _get_followed_dependency_infos(rule):
if DependenciesInfo in dep and dep[DependenciesInfo].target_to_artifacts
]

def _collect_own_artifacts(
def _collect_own_java_artifacts(
target,
ctx,
dependency_infos,
Expand Down Expand Up @@ -242,14 +280,14 @@ def _collect_own_artifacts(
srcjars = own_srcjar_files,
)

def _collect_own_and_dependency_artifacts(
def _collect_own_and_dependency_java_artifacts(
target,
ctx,
dependency_infos,
always_build_rules,
generate_aidl_classes,
target_is_within_project_scope):
own_files = _collect_own_artifacts(
own_files = _collect_own_java_artifacts(
target,
ctx,
dependency_infos,
Expand Down Expand Up @@ -302,10 +340,45 @@ def _collect_dependencies_core_impl(
always_build_rules,
generate_aidl_classes,
test_mode):
if JavaInfo in target or AndroidIdeInfo in target:
return _collect_java_dependencies_core_impl(
target,
ctx,
include,
exclude,
always_build_rules,
generate_aidl_classes,
test_mode,
)
elif CcInfo in target:
return _collect_cc_dependencies_core_impl(target, ctx)
elif cc_common.CcToolchainInfo in target:
return _collect_cc_toolchain_info(target)
else:
# This happens for rules such as proto_library which java_proto_library
# depends on.
return DependenciesInfo(
target_to_artifacts = {},
compile_time_jars = depset(),
aars = depset(),
gensrcs = depset(),
test_mode_own_files = None,
cc_info = None,
cc_headers = depset(),
)

def _collect_java_dependencies_core_impl(
target,
ctx,
include,
exclude,
always_build_rules,
generate_aidl_classes,
test_mode):
target_is_within_project_scope = _target_within_project_scope(str(target.label), include, exclude) and not test_mode
dependency_infos = _get_followed_dependency_infos(ctx.rule)

target_to_artifacts, compile_jars, aars, gensrcs = _collect_own_and_dependency_artifacts(
target_to_artifacts, compile_jars, aars, gensrcs = _collect_own_and_dependency_java_artifacts(
target,
ctx,
dependency_infos,
Expand All @@ -316,7 +389,7 @@ def _collect_dependencies_core_impl(

test_mode_own_files = None
if test_mode:
within_scope_own_files = _collect_own_artifacts(
within_scope_own_files = _collect_own_java_artifacts(
target,
ctx,
dependency_infos,
Expand All @@ -337,9 +410,64 @@ def _collect_dependencies_core_impl(
aars = aars,
gensrcs = gensrcs,
test_mode_own_files = test_mode_own_files,
cc_info = None,
cc_headers = depset(),
cc_toolchain_info = None,
),
]

def _collect_cc_dependencies_core_impl(target, ctx):
cc_toolchain_info = None
if hasattr(ctx.rule.attr, "_cc_toolchain"):
cc_toolchain_target = getattr(ctx.rule.attr, "_cc_toolchain")
if DependenciesInfo in cc_toolchain_target:
cc_toolchain_info = cc_toolchain_target[DependenciesInfo].cc_toolchain_info

compilation_context = target[CcInfo].compilation_context
cc_info = None
gen_headers = []
if compilation_context:
gen_headers = [f for f in compilation_context.headers.to_list() if not f.is_source]

cc_info = struct(
transitive_defines = compilation_context.defines.to_list(),
transitive_include_directory = compilation_context.includes.to_list(),
transitive_quote_include_directory = compilation_context.quote_includes.to_list(),
transitive_system_include_directory = compilation_context.system_includes.to_list(),
gen_headers = [f.path for f in gen_headers],
cc_toolchain_info = cc_toolchain_info,
)

return DependenciesInfo(
target_to_artifacts = {},
compile_time_jars = depset(),
aars = depset(),
gensrcs = depset(),
test_mode_own_files = None,
cc_info = cc_info,
cc_headers = gen_headers,
cc_toolchain_info = cc_toolchain_info,
)

def _collect_cc_toolchain_info(target):
toolchain_info = target[cc_common.CcToolchainInfo]
cc_toolchain_info = struct(
compiler_executable = toolchain_info.compiler_executable,
cpu = toolchain_info.cpu,
compiler = toolchain_info.compiler,
target_name = toolchain_info.target_gnu_system_name,
)
return DependenciesInfo(
target_to_artifacts = {},
compile_time_jars = depset(),
aars = depset(),
gensrcs = depset(),
test_mode_own_files = None,
cc_info = None,
cc_headers = depset(),
cc_toolchain_info = cc_toolchain_info,
)

def _get_ide_aar_file(target, ctx):
"""
Builds a resource only .aar file for the ide.
Expand Down Expand Up @@ -453,6 +581,7 @@ FOLLOW_ATTRIBUTES_BY_RULE_KIND = [
("runtime", ["proto_lang_toolchain", "java_rpc_toolchain"]),
("_toolchain", ["_java_grpc_library", "_java_lite_grpc_library", "kt_jvm_library_helper", "android_library"]),
("kotlin_libs", ["kt_jvm_toolchain"]),
("_cc_toolchain", []),
]

FOLLOW_ATTRIBUTES = [attr for (attr, _) in FOLLOW_ATTRIBUTES_BY_RULE_KIND]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import com.google.idea.common.experiments.BoolExperiment;
import com.google.protobuf.ExtensionRegistry;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -511,6 +512,13 @@ private void updateMaps(Set<Label> targets, BuildArtifacts newArtifacts) {
}
}

private static final ImmutableSet<String> JAR_ZIP_EXTENSIONS =
ImmutableSet.of("jar", "zip", "srcjar");

private static boolean hasJarOrZipExtension(Path p) {
return JAR_ZIP_EXTENSIONS.contains(FileUtil.getExtension((CharSequence) p.toString()));
}

@Override
public ProjectProto.Project updateProjectProto(ProjectProto.Project projectProto)
throws BuildException {
Expand All @@ -535,11 +543,12 @@ public ProjectProto.Project updateProjectProto(ProjectProto.Project projectProto
.map(ProjectPath::workspaceRelative)
.collect(ImmutableSet.toImmutableSet());

ImmutableSet<ProjectPath> generatedSrcJars =
ImmutableSet<ProjectPath> generatedExternalSrcJars =
artifacts.values().stream()
.filter(not(ai -> projectDefinition.isIncluded(ai.label())))
.map(ArtifactInfo::genSrcs)
.flatMap(List::stream)
.filter(ArtifactTrackerImpl::hasJarOrZipExtension)
.map(generatedExternalSrcFileCache::getCacheFile)
.filter(Optional::isPresent)
.map(Optional::get)
Expand All @@ -550,7 +559,9 @@ public ProjectProto.Project updateProjectProto(ProjectProto.Project projectProto
if (ATTACH_DEP_SRCJARS.getValue()) {
SrcJarProjectUpdater srcJarUpdater =
new SrcJarProjectUpdater(
projectProto, Sets.union(workspaceSrcJars, generatedSrcJars), projectPathResolver);
projectProto,
Sets.union(workspaceSrcJars, generatedExternalSrcJars),
projectPathResolver);
projectProto = srcJarUpdater.addSrcJars();
} else {
logger.info("srcjar attachment disabled.");
Expand Down

0 comments on commit e73603f

Please sign in to comment.