@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# Copyright 2020 The gRPC Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -34,14 +34,18 @@ import subprocess
import yaml
import xml . etree . ElementTree as ET
import os
import collections
import sys
import re
from typing import List , Any , Dict , Optional , Iterable
import build_cleaner
_ROOT = os . path . abspath ( os . path . join ( os . path . dirname ( sys . argv [ 0 ] ) , ' ../.. ' ) )
os . chdir ( _ROOT )
BuildMetadata = Dict [ str , Any ]
BuildDict = Dict [ str , BuildMetadata ]
BuildYaml = Dict [ str , Any ]
def _bazel_query_xml_tree ( query ) :
def _bazel_query_xml_tree ( query : str ) - > ET . Element :
""" Get xml output of bazel query invocation, parsed as XML tree """
output = subprocess . check_output (
[ ' tools/bazel ' , ' query ' , ' --noimplicit_deps ' , ' --output ' , ' xml ' , query ] )
@ -98,14 +102,14 @@ def _extract_rules_from_bazel_xml(xml_tree):
return result
def _get_bazel_label ( target_name ) :
def _get_bazel_label ( target_name : str ) - > str :
if ' : ' in target_name :
return ' // %s ' % target_name
else :
return ' //: %s ' % target_name
def _extract_source_file_path ( label ) :
def _extract_source_file_path ( label : str ) - > str :
""" Gets relative path to source file from bazel deps listing """
if label . startswith ( ' // ' ) :
label = label [ len ( ' // ' ) : ]
@ -117,7 +121,7 @@ def _extract_source_file_path(label):
return label
def _extract_public_headers ( bazel_rule ) :
def _extract_public_headers ( bazel_rule : BuildMetadata ) - > List [ str ] :
""" Gets list of public headers from a bazel rule """
result = [ ]
for dep in bazel_rule [ ' hdrs ' ] :
@ -126,7 +130,7 @@ def _extract_public_headers(bazel_rule):
return list ( sorted ( result ) )
def _extract_nonpublic_headers ( bazel_rule ) :
def _extract_nonpublic_headers ( bazel_rule : BuildMetadata ) - > List [ str ] :
""" Gets list of non-public headers from a bazel rule """
result = [ ]
for dep in bazel_rule [ ' hdrs ' ] :
@ -136,7 +140,7 @@ def _extract_nonpublic_headers(bazel_rule):
return list ( sorted ( result ) )
def _extract_sources ( bazel_rule ) :
def _extract_sources ( bazel_rule : BuildMetadata ) - > List [ str ] :
""" Gets list of source files from a bazel rule """
result = [ ]
for dep in bazel_rule [ ' srcs ' ] :
@ -146,12 +150,14 @@ def _extract_sources(bazel_rule):
return list ( sorted ( result ) )
def _extract_deps ( bazel_rule ) :
def _extract_deps ( bazel_rule : BuildMetadata ,
bazel_rules : BuildDict ) - > List [ str ] :
""" Gets list of deps from from a bazel rule """
return list ( sorted ( bazel_rule [ ' deps ' ] ) )
def _create_target_from_bazel_rule ( target_name , bazel_rules ) :
def _create_target_from_bazel_rule ( target_name : str ,
bazel_rules : BuildDict ) - > BuildMetadata :
""" Create build.yaml-like target definition from bazel metadata """
bazel_rule = bazel_rules [ _get_bazel_label ( target_name ) ]
@ -164,71 +170,16 @@ def _create_target_from_bazel_rule(target_name, bazel_rules):
' _PUBLIC_HEADERS_BAZEL ' : _extract_public_headers ( bazel_rule ) ,
' _HEADERS_BAZEL ' : _extract_nonpublic_headers ( bazel_rule ) ,
' _SRC_BAZEL ' : _extract_sources ( bazel_rule ) ,
' _DEPS_BAZEL ' : _extract_deps ( bazel_rule ) ,
' _DEPS_BAZEL ' : _extract_deps ( bazel_rule , bazel_rules ) ,
' public_headers ' : bazel_rule [ ' _COLLAPSED_PUBLIC_HEADERS ' ] ,
' headers ' : bazel_rule [ ' _COLLAPSED_HEADERS ' ] ,
' src ' : bazel_rule [ ' _COLLAPSED_SRCS ' ] ,
' deps ' : bazel_rule [ ' _COLLAPSED_DEPS ' ] ,
}
return result
def _sort_by_build_order ( lib_names , lib_dict , deps_key_name , verbose = False ) :
""" Sort library names to form correct build order. Use metadata from lib_dict """
# we find correct build order by performing a topological sort
# expected output: if library B depends on A, A should be listed first
# all libs that are not in the dictionary are considered external.
external_deps = list (
sorted ( [ lib_name for lib_name in lib_names if lib_name not in lib_dict
] ) )
if verbose :
print ( ' topo_ordering ' + str ( lib_names ) )
print ( ' external_deps ' + str ( external_deps ) )
result = list ( external_deps ) # external deps will be listed first
while len ( result ) < len ( lib_names ) :
more_results = [ ]
for lib in lib_names :
if lib not in result :
dep_set = set ( lib_dict [ lib ] . get ( deps_key_name , [ ] ) )
dep_set = dep_set . intersection ( lib_names )
# if lib only depends on what's already built, add it to the results
if not dep_set . difference ( set ( result ) ) :
more_results . append ( lib )
if not more_results :
raise Exception (
' Cannot sort topologically, there seems to be a cyclic dependency '
)
if verbose :
print ( ' adding ' + str ( more_results ) )
result = result + list (
sorted ( more_results
) ) # when build order doesn't matter, sort lexicographically
return result
# TODO(jtattermusch): deduplicate with transitive_dependencies.py (which has a slightly different logic)
def _populate_transitive_deps ( bazel_rules ) :
""" Add ' transitive_deps ' field for each of the rules """
transitive_deps = { }
for rule_name in bazel_rules . keys ( ) :
transitive_deps [ rule_name ] = set ( bazel_rules [ rule_name ] [ ' deps ' ] )
while True :
deps_added = 0
for rule_name in bazel_rules . keys ( ) :
old_deps = transitive_deps [ rule_name ]
new_deps = set ( old_deps )
for dep_name in old_deps :
new_deps . update ( transitive_deps . get ( dep_name , set ( ) ) )
deps_added + = len ( new_deps ) - len ( old_deps )
transitive_deps [ rule_name ] = new_deps
# if none of the transitive dep sets has changed, we're done
if deps_added == 0 :
break
for rule_name , bazel_rule in bazel_rules . items ( ) :
bazel_rule [ ' transitive_deps ' ] = list ( sorted ( transitive_deps [ rule_name ] ) )
def _external_dep_name_from_bazel_dependency ( bazel_dep ) :
def _external_dep_name_from_bazel_dependency ( bazel_dep : str ) - > Optional [ str ] :
""" Returns name of dependency if external bazel dependency is provided or None """
if bazel_dep . startswith ( ' @com_google_absl// ' ) :
# special case for add dependency on one of the absl libraries (there is not just one absl library)
@ -247,98 +198,186 @@ def _external_dep_name_from_bazel_dependency(bazel_dep):
return None
def _expand_intermediate_deps ( target_dict , public_dep_names , bazel_rules ) :
# Some of the libraries defined by bazel won't be exposed in build.yaml
# We call these "intermediate" dependencies. This method expands
# the intermediate deps for given target (populates library's
# headers, sources and dicts as if the intermediate dependency never existed)
def _compute_transitive_metadata (
rule_name : str , bazel_rules : Any ,
bazel_label_to_dep_name : Dict [ str , str ] ) - > None :
""" Computes the final build metadata for Bazel target with rule_name.
The dependencies that will appear on the deps list are :
* Public build targets including binaries and tests ;
* External targets , like absl , re2 .
All other intermediate dependencies will be merged , which means their
source file , headers , etc . will be collected into one build target . This
step of processing will greatly reduce the complexity of the generated
build specifications for other build systems , like CMake , Make , setuptools .
The final build metadata are :
* _TRANSITIVE_DEPS : all the transitive dependencies including intermediate
targets ;
* _COLLAPSED_DEPS : dependencies that fits our requirement above , and it
will remove duplicated items and produce the shortest
possible dependency list in alphabetical order ;
* _COLLAPSED_SRCS : the merged source files ;
* _COLLAPSED_PUBLIC_HEADERS : the merged public headers ;
* _COLLAPSED_HEADERS : the merged non - public headers ;
* _EXCLUDE_DEPS : intermediate targets to exclude when performing collapsing
of sources and dependencies .
For the collapsed_deps , the algorithm improved cases like :
The result in the past :
end2end_tests - > [ grpc_test_util , grpc , gpr , address_sorting , upb ]
grpc_test_util - > [ grpc , gpr , address_sorting , upb , . . . ]
grpc - > [ gpr , address_sorting , upb , . . . ]
The result of the algorithm :
end2end_tests - > [ grpc_test_util ]
grpc_test_util - > [ grpc ]
grpc - > [ gpr , address_sorting , upb , . . . ]
"""
bazel_rule = bazel_rules [ rule_name ]
direct_deps = _extract_deps ( bazel_rule , bazel_rules )
transitive_deps = set ( )
collapsed_deps = set ( )
exclude_deps = set ( )
collapsed_srcs = set ( _extract_sources ( bazel_rule ) )
collapsed_public_headers = set ( _extract_public_headers ( bazel_rule ) )
collapsed_headers = set ( _extract_nonpublic_headers ( bazel_rule ) )
for dep in direct_deps :
external_dep_name_maybe = _external_dep_name_from_bazel_dependency ( dep )
if dep in bazel_rules :
# Descend recursively, but no need to do that for external deps
if external_dep_name_maybe is None :
if " _PROCESSING_DONE " not in bazel_rules [ dep ] :
# This item is not processed before, compute now
_compute_transitive_metadata ( dep , bazel_rules ,
bazel_label_to_dep_name )
transitive_deps . update ( bazel_rules [ dep ] . get (
' _TRANSITIVE_DEPS ' , [ ] ) )
collapsed_deps . update (
collapsed_deps , bazel_rules [ dep ] . get ( ' _COLLAPSED_DEPS ' , [ ] ) )
exclude_deps . update ( bazel_rules [ dep ] . get ( ' _EXCLUDE_DEPS ' , [ ] ) )
# This dep is a public target, add it as a dependency
if dep in bazel_label_to_dep_name :
transitive_deps . update ( [ bazel_label_to_dep_name [ dep ] ] )
collapsed_deps . update ( collapsed_deps ,
[ bazel_label_to_dep_name [ dep ] ] )
# Add all the transitive deps of our every public dep to exclude
# list since we want to avoid building sources that are already
# built by our dependencies
exclude_deps . update ( bazel_rules [ dep ] [ ' _TRANSITIVE_DEPS ' ] )
continue
# use this dictionary to translate from bazel labels to dep names
bazel_label_to_dep_name = { }
for dep_name in public_dep_names :
bazel_label_to_dep_name [ _get_bazel_label ( dep_name ) ] = dep_name
# This dep is an external target, add it as a dependency
if external_dep_name_maybe is not None :
transitive_deps . update ( [ external_dep_name_maybe ] )
collapsed_deps . update ( collapsed_deps , [ external_dep_name_maybe ] )
continue
target_name = target_dict [ ' name ' ]
bazel_deps = target_dict [ ' _DEPS_BAZEL ' ]
# Direct dependencies are part of transitive dependencies
transitive_deps . update ( direct_deps )
# initial values
public_headers = set ( target_dict [ ' _PUBLIC_HEADERS_BAZEL ' ] )
headers = set ( target_dict [ ' _HEADERS_BAZEL ' ] )
src = set ( target_dict [ ' _SRC_BAZEL ' ] )
deps = set ( )
# Calculate transitive public deps (needed for collapsing sources)
transitive_public_deps = set (
filter ( lambda x : x in bazel_label_to_dep_name , transitive_deps ) )
expansion_blocklist = set ( )
to_expand = set ( bazel_deps )
while to_expand :
# Remove intermediate targets that our public dependencies already depend
# on. This is the step that further shorten the deps list.
collapsed_deps = set ( filter ( lambda x : x not in exclude_deps ,
collapsed_deps ) )
# start with the last dependency to be built
build_order = _sort_by_build_order ( list ( to_expand ) , bazel_rules ,
' transitive_deps ' )
# Compute the final source files and headers for this build target whose
# name is `rule_name` (input argument of this function).
#
# Imaging a public target PX has transitive deps [IA, IB, PY, IC, PZ]. PX,
# PY and PZ are public build targets. And IA, IB, IC are intermediate
# targets. In addition, PY depends on IC.
#
# Translate the condition into dependency graph:
# PX -> [IA, IB, PY, IC, PZ]
# PY -> [IC]
# Public targets: [PX, PY, PZ]
#
# The collapsed dependencies of PX: [PY, PZ].
# The excluded dependencies of X: [PY, IC, PZ].
# (IC is excluded as a dependency of PX. It is already included in PY, hence
# it would be redundant to include it again.)
#
# Target PX should include source files and headers of [PX, IA, IB] as final
# build metadata.
for dep in transitive_deps :
if dep not in exclude_deps and dep not in transitive_public_deps :
if dep in bazel_rules :
collapsed_srcs . update ( _extract_sources ( bazel_rules [ dep ] ) )
collapsed_public_headers . update (
_extract_public_headers ( bazel_rules [ dep ] ) )
collapsed_headers . update (
_extract_nonpublic_headers ( bazel_rules [ dep ] ) )
# This item is a "visited" flag
bazel_rule [ ' _PROCESSING_DONE ' ] = True
# Following items are described in the docstinrg.
bazel_rule [ ' _TRANSITIVE_DEPS ' ] = list ( sorted ( transitive_deps ) )
bazel_rule [ ' _COLLAPSED_DEPS ' ] = list ( sorted ( collapsed_deps ) )
bazel_rule [ ' _COLLAPSED_SRCS ' ] = list ( sorted ( collapsed_srcs ) )
bazel_rule [ ' _COLLAPSED_PUBLIC_HEADERS ' ] = list (
sorted ( collapsed_public_headers ) )
bazel_rule [ ' _COLLAPSED_HEADERS ' ] = list ( sorted ( collapsed_headers ) )
bazel_rule [ ' _EXCLUDE_DEPS ' ] = list ( sorted ( exclude_deps ) )
# TODO(jtattermusch): deduplicate with transitive_dependencies.py (which has a slightly different logic)
# TODO(jtattermusch): This is done to avoid introducing too many intermediate
# libraries into the build.yaml-based builds (which might in cause issues
# building language-specific artifacts) and also because the libraries
# in build.yaml-based build are generally considered units of distributions
# (= public libraries that are visible to the user and are installable),
# while in bazel builds it is customary to define larger number of smaller
# "sublibraries". The need for elision (and expansion)
# of intermediate libraries can be re-evaluated in the future.
def _populate_transitive_metadata ( bazel_rules : Any ,
public_dep_names : Iterable [ str ] ) - > None :
""" Add ' transitive_deps ' field for each of the rules """
# Create the map between Bazel label and public dependency name
bazel_label_to_dep_name = { }
for dep_name in public_dep_names :
bazel_label_to_dep_name [ _get_bazel_label ( dep_name ) ] = dep_name
bazel_dep = build_order [ - 1 ]
to_expand . remove ( bazel_dep )
# Make sure we reached all the Bazel rules
# TODO(lidiz) potentially we could only update a subset of rules
for rule_name in bazel_rules :
if ' _PROCESSING_DONE ' not in bazel_rules [ rule_name ] :
_compute_transitive_metadata ( rule_name , bazel_rules ,
bazel_label_to_dep_name )
is_public = bazel_dep in bazel_label_to_dep_name
external_dep_name_maybe = _external_dep_name_from_bazel_dependency (
bazel_dep )
if is_public :
# this is not an intermediate dependency we so we add it
# to the list of public dependencies to the list, in the right format
deps . add ( bazel_label_to_dep_name [ bazel_dep ] )
def update_test_metadata_with_transitive_metadata (
all_extra_metadata : BuildDict , bazel_rules : BuildDict ) - > None :
""" Patches test build metadata with transitive metadata. """
for lib_name , lib_dict in all_extra_metadata . items ( ) :
# Skip if it isn't not an test
if lib_dict . get ( ' build ' ) != ' test ' or lib_dict . get ( ' _TYPE ' ) != ' target ' :
continue
# we do not want to expand any intermediate libraries that are already included
# by the dependency we just added
expansion_blocklist . update (
bazel_rules [ bazel_dep ] [ ' transitive_deps ' ] )
bazel_rule = bazel_rules [ _get_bazel_label ( lib_name ) ]
elif external_dep_name_maybe :
deps . add ( external_dep_name_maybe )
if ' //external:benchmark ' in bazel_rule [ ' _TRANSITIVE_DEPS ' ] :
lib_dict [ ' benchmark ' ] = True
lib_dict [ ' defaults ' ] = ' benchmark '
elif bazel_dep . startswith (
' //external: ' ) or not bazel_dep . startswith ( ' // ' ) :
# all the other external deps can be skipped
pass
if ' //external:gtest ' in bazel_rule [ ' _TRANSITIVE_DEPS ' ] :
lib_dict [ ' gtest ' ] = True
lib_dict [ ' language ' ] = ' c++ '
elif bazel_dep in expansion_blocklist :
# do not expand if a public dependency that depends on this has already been expanded
pass
else :
if bazel_dep in bazel_rules :
# this is an intermediate library, expand it
public_headers . update (
_extract_public_headers ( bazel_rules [ bazel_dep ] ) )
headers . update (
_extract_nonpublic_headers ( bazel_rules [ bazel_dep ] ) )
src . update ( _extract_sources ( bazel_rules [ bazel_dep ] ) )
new_deps = _extract_deps ( bazel_rules [ bazel_dep ] )
to_expand . update ( new_deps )
else :
raise Exception ( bazel_dep + ' not in bazel_rules ' )
# make the 'deps' field transitive, but only list non-intermediate deps and selected external deps
bazel_transitive_deps = bazel_rules [ _get_bazel_label (
target_name ) ] [ ' transitive_deps ' ]
for transitive_bazel_dep in bazel_transitive_deps :
public_name = bazel_label_to_dep_name . get ( transitive_bazel_dep , None )
if public_name :
deps . add ( public_name )
external_dep_name_maybe = _external_dep_name_from_bazel_dependency (
transitive_bazel_dep )
if external_dep_name_maybe :
# expanding all absl libraries is technically correct but creates too much noise
if not external_dep_name_maybe . startswith ( ' absl ' ) :
deps . add ( external_dep_name_maybe )
target_dict [ ' public_headers ' ] = list ( sorted ( public_headers ) )
target_dict [ ' headers ' ] = list ( sorted ( headers ) )
target_dict [ ' src ' ] = list ( sorted ( src ) )
target_dict [ ' deps ' ] = list ( sorted ( deps ) )
def _generate_build_metadata ( build_extra_metadata , bazel_rules ) :
def _generate_build_metadata ( build_extra_metadata : BuildDict ,
bazel_rules : BuildDict ) - > BuildDict :
""" Generate build metadata in build.yaml-like format bazel build metadata and build.yaml-specific " extra metadata " . """
lib_names = list ( build_extra_metadata . keys ( ) )
result = { }
@ -346,20 +385,6 @@ def _generate_build_metadata(build_extra_metadata, bazel_rules):
for lib_name in lib_names :
lib_dict = _create_target_from_bazel_rule ( lib_name , bazel_rules )
# Figure out the final list of headers and sources for given target.
# While this is mostly based on bazel build metadata, build.yaml does
# not necessarily expose all the targets that are present in bazel build.
# These "intermediate dependencies" might get flattened.
# TODO(jtattermusch): This is done to avoid introducing too many intermediate
# libraries into the build.yaml-based builds (which might in cause issues
# building language-specific artifacts) and also because the libraries
# in build.yaml-based build are generally considered units of distributions
# (= public libraries that are visible to the user and are installable),
# while in bazel builds it is customary to define larger number of smaller
# "sublibraries". The need for elision (and expansion)
# of intermediate libraries can be re-evaluated in the future.
_expand_intermediate_deps ( lib_dict , lib_names , bazel_rules )
# populate extra properties from the build.yaml-specific "extra metadata"
lib_dict . update ( build_extra_metadata . get ( lib_name , { } ) )
@ -376,8 +401,8 @@ def _generate_build_metadata(build_extra_metadata, bazel_rules):
if to_name :
# store lib under the new name and also change its 'name' property
if to_name in result :
raise Exception ( ' Cannot rename target ' + lib_name + ' , ' +
to_name + ' already exists. ' )
raise Exception ( ' Cannot rename target ' + str ( lib_name ) + ' , ' +
str ( to_name ) + ' already exists. ' )
lib_dict = result . pop ( lib_name )
lib_dict [ ' name ' ] = to_name
result [ to_name ] = lib_dict
@ -389,15 +414,10 @@ def _generate_build_metadata(build_extra_metadata, bazel_rules):
for dep in lib_dict_to_update [ ' deps ' ]
] )
# make sure deps are listed in reverse topological order (e.g. "grpc gpr" and not "gpr grpc")
for lib_dict in result . values ( ) :
lib_dict [ ' deps ' ] = list (
reversed ( _sort_by_build_order ( lib_dict [ ' deps ' ] , result , ' deps ' ) ) )
return result
def _convert_to_build_yaml_like ( lib_dict ) :
def _convert_to_build_yaml_like ( lib_dict : BuildMetadata ) - > BuildYaml :
lib_names = [
lib_name for lib_name in list ( lib_dict . keys ( ) )
if lib_dict [ lib_name ] . get ( ' _TYPE ' , ' library ' ) == ' library '
@ -440,7 +460,7 @@ def _convert_to_build_yaml_like(lib_dict):
return build_yaml_like
def _extract_cc_tests ( bazel_rules ) :
def _extract_cc_tests ( bazel_rules : BuildDict ) - > List [ str ] :
""" Gets list of cc_test tests from bazel rules """
result = [ ]
for bazel_rule in bazel_rules . values ( ) :
@ -452,7 +472,7 @@ def _extract_cc_tests(bazel_rules):
return list ( sorted ( result ) )
def _exclude_unwanted_cc_tests ( tests ) :
def _exclude_unwanted_cc_tests ( tests : List [ str ] ) - > List [ str ] :
""" Filters out bazel tests that we don ' t want to run with other build systems or we cannot build them reasonably """
# most qps tests are autogenerated, we are fine without them
@ -518,7 +538,8 @@ def _exclude_unwanted_cc_tests(tests):
return tests
def _generate_build_extra_metadata_for_tests ( tests , bazel_rules ) :
def _generate_build_extra_metadata_for_tests (
tests : List [ str ] , bazel_rules : BuildDict ) - > BuildDict :
""" For given tests, generate the " extra metadata " that we need for our " build.yaml " -like output. The extra metadata is generated from the bazel rule metadata by using a bunch of heuristics. """
test_metadata = { }
for test in tests :
@ -567,19 +588,11 @@ def _generate_build_extra_metadata_for_tests(tests, bazel_rules):
platforms . append ( ' windows ' )
test_dict [ ' platforms ' ] = platforms
if ' //external:benchmark ' in bazel_rule [ ' transitive_deps ' ] :
test_dict [ ' benchmark ' ] = True
test_dict [ ' defaults ' ] = ' benchmark '
cmdline_args = bazel_rule [ ' args ' ]
if cmdline_args :
test_dict [ ' args ' ] = list ( cmdline_args )
uses_gtest = ' //external:gtest ' in bazel_rule [ ' transitive_deps ' ]
if uses_gtest :
test_dict [ ' gtest ' ] = True
if test . startswith ( ' test/cpp ' ) or uses_gtest :
if test . startswith ( ' test/cpp ' ) :
test_dict [ ' language ' ] = ' c++ '
elif test . startswith ( ' test/core ' ) :
@ -615,7 +628,7 @@ def _generate_build_extra_metadata_for_tests(tests, bazel_rules):
return test_metadata
def _detect_and_print_issues ( build_yaml_like ) :
def _detect_and_print_issues ( build_yaml_like : BuildYaml ) - > None :
""" Try detecting some unusual situations and warn about them. """
for tgt in build_yaml_like [ ' targets ' ] :
if tgt [ ' build ' ] == ' test ' :
@ -968,6 +981,8 @@ _BAZEL_DEPS_QUERIES = [
' deps( " //:all " ) ' ,
' deps( " //src/compiler/... " ) ' ,
' deps( " //src/proto/... " ) ' ,
# The ^ is needed to differentiate proto_library from go_proto_library
' deps(kind( " ^proto_library " , @envoy_api//envoy/...)) ' ,
]
# Step 1: run a bunch of "bazel query --output xml" queries to collect
@ -987,14 +1002,6 @@ for query in _BAZEL_DEPS_QUERIES:
bazel_rules . update (
_extract_rules_from_bazel_xml ( _bazel_query_xml_tree ( query ) ) )
# Step 1a: Knowing the transitive closure of dependencies will make
# the postprocessing simpler, so compute the info for all our rules.
#
# Example:
# '//:grpc' : { ...,
# 'transitive_deps': ['//:gpr_base', ...] }
_populate_transitive_deps ( bazel_rules )
# Step 2: Extract the known bazel cc_test tests. While most tests
# will be buildable with other build systems just fine, some of these tests
# would be too difficult to build and run with other build systems,
@ -1049,7 +1056,25 @@ all_extra_metadata.update(_BUILD_EXTRA_METADATA)
all_extra_metadata . update (
_generate_build_extra_metadata_for_tests ( tests , bazel_rules ) )
# Step 4: Generate the final metadata for all the targets.
# Step 4: Compute the build metadata that will be used in the final build.yaml.
# The final build metadata includes transitive dependencies, and sources/headers
# expanded without intermediate dependencies.
# Example:
# '//:grpc' : { ...,
# '_TRANSITIVE_DEPS': ['//:gpr_base', ...],
# '_COLLAPSED_DEPS': ['gpr', ...],
# '_COLLAPSED_SRCS': [...],
# '_COLLAPSED_PUBLIC_HEADERS': [...],
# '_COLLAPSED_HEADERS': [...]
# }
_populate_transitive_metadata ( bazel_rules , all_extra_metadata . keys ( ) )
# Step 4a: Update the existing test metadata with the updated build metadata.
# Certain build metadata of certain test targets depend on the transitive
# metadata that wasn't available earlier.
update_test_metadata_with_transitive_metadata ( all_extra_metadata , bazel_rules )
# Step 5: Generate the final metadata for all the targets.
# This is done by combining the bazel build metadata and the "extra metadata"
# we obtained in the previous step.
# In this step, we also perform some interesting massaging of the target metadata
@ -1079,7 +1104,7 @@ all_extra_metadata.update(
# ... }
all_targets_dict = _generate_build_metadata ( all_extra_metadata , bazel_rules )
# Step 5 : convert the dictionary with all the targets to a dict that has
# Step 6 : convert the dictionary with all the targets to a dict that has
# the desired "build.yaml"-like layout.
# TODO(jtattermusch): We use the custom "build.yaml"-like layout because
# currently all other build systems use that format as their source of truth.
@ -1096,7 +1121,7 @@ build_yaml_like = _convert_to_build_yaml_like(all_targets_dict)
# detect and report some suspicious situations we've seen before
_detect_and_print_issues ( build_yaml_like )
# Step 6 : Store the build_autogenerated.yaml in a deterministic (=sorted)
# Step 7 : Store the build_autogenerated.yaml in a deterministic (=sorted)
# and cleaned-up form.
# A basic overview of the resulting "build.yaml"-like format is here:
# https://github.com/grpc/grpc/blob/master/templates/README.md