• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# Copyright (C) 2023 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import json
17import os
18import subprocess
19import sys
20from typing import Any, Dict, List
21import yaml
22
23ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
24
25GRPC_GN_HEADER = '''
26#
27# DO NOT EDIT. AUTOGENERATED file
28#
29# This file is generated with the command:
30# tools/gen_grpc_build_gn.py > buildtools/grpc/BUILD.gn
31#
32
33import("../../gn/perfetto.gni")
34
35# Prevent the gRPC from being depended upon without explicitly being opted in.
36assert(enable_perfetto_grpc)
37
38# BoringSSL has assembly code which is tied to platform-specific. For now, we
39# only care about Linux x64 so assert this as the case.
40assert(is_linux && current_cpu == "x64")
41'''
42
43TARGET_TEMPLATE = """
44{target_type}("{name}") {{
45  sources = {srcs}
46  public_deps = {deps}
47  public_configs = ["..:{config_name}"]
48  configs -= [ "//gn/standalone:extra_warnings" ]
49}}"""
50
51LIBRARY_IGNORE_LIST = set([
52    'grpcpp_channelz',
53    'grpc++_reflection',
54    'benchmark_helpers',
55    'boringssl_test_util',
56])
57
58TARGET_ALLOW_LIST = set([
59    'grpc_cpp_plugin',
60])
61
62STATIC_LIBRARY_TARGETS = set([
63    'upb',
64    're2',
65    'boringssl',
66    'grpc++',
67])
68
69
70def grpc_relpath(*segments: str) -> str:
71  '''From path segments to GRPC root, returns the absolute path.'''
72  return os.path.join(ROOT_DIR, 'buildtools', 'grpc', 'src', *segments)
73
74
75GRPC_BUILD_YAML = grpc_relpath('build_autogenerated.yaml')
76ABSL_GEN_BUILD_YAML = grpc_relpath('src', 'abseil-cpp', 'gen_build_yaml.py')
77UPB_GEN_BUILD_YAML = grpc_relpath('src', 'upb', 'gen_build_yaml.py')
78RE2_GEN_BUILD_YAML = grpc_relpath('src', 're2', 'gen_build_yaml.py')
79BSSL_GEN_BUILD_YAML = grpc_relpath('src', 'boringssl', 'gen_build_yaml.py')
80
81
82def gen_grpc_dep_yaml(gen_path: str) -> Dict[str, Any]:
83  '''Invokes a gen_build_yaml.py file for creating YAML for gRPC deps.'''
84  return yaml.safe_load(subprocess.check_output(['python3', gen_path]))
85
86
87def bazel_label_to_gn_target(dep: str) -> str:
88  '''Converts a Bazel label name into a gn target name.'''
89  if dep == 'libssl':
90    return 'boringssl'
91  return dep.replace('/', '_').replace(':', '_')
92
93
94def get_deps_for_target(target: str) -> List[str]:
95  if target == 'grpc_plugin_support':
96    return ['..:protoc_lib']
97  if target == 'grpc':
98    return [':re2', '../../gn:zlib']
99  if target == 'grpc_authorization_provider':
100    return [':re2']
101  return []
102
103
104def get_library_target_type(target: str) -> str:
105  if target in STATIC_LIBRARY_TARGETS:
106    return 'static_library'
107  return 'source_set'
108
109
110def yaml_to_gn_targets(desc: Dict[str, Any], build_types: list[str],
111                       config_name: str) -> List[str]:
112  '''Given a gRPC YAML description of the build graph, generates GN targets.'''
113  out = []
114  for lib in desc['libs']:
115    if lib['build'] not in build_types:
116      continue
117    if lib['name'] in LIBRARY_IGNORE_LIST:
118      continue
119    srcs = [f'src/{file}' for file in lib['src'] + lib['headers']]
120    if 'asm_src' in lib:
121      srcs += [f'src/{file}' for file in lib['asm_src']['crypto_linux_x86_64']]
122    deps = [f':{bazel_label_to_gn_target(dep)}' for dep in lib.get('deps', [])
123           ] + get_deps_for_target(lib['name'])
124    library_target = TARGET_TEMPLATE.format(
125        name=bazel_label_to_gn_target(lib['name']),
126        config_name=config_name,
127        srcs=json.dumps(srcs),
128        deps=json.dumps(deps),
129        target_type=get_library_target_type(lib['name']))
130    out.append(library_target)
131
132  for bin in desc.get('targets', []):
133    if bin['build'] not in build_types:
134      continue
135    if bin['name'] not in TARGET_ALLOW_LIST:
136      continue
137    srcs = json.dumps([f'src/{file}' for file in bin['src'] + bin['headers']])
138    deps = [f':{bazel_label_to_gn_target(dep)}' for dep in bin.get('deps', [])
139           ] + get_deps_for_target(bin['name'])
140    binary_target = TARGET_TEMPLATE.format(
141        name=bazel_label_to_gn_target(bin['name']),
142        config_name=config_name,
143        srcs=srcs,
144        deps=json.dumps(deps),
145        target_type='executable')
146    out.append(binary_target)
147  return out
148
149
150def main():
151  out: List[str] = []
152
153  # Generate absl rules
154  absl_yaml = gen_grpc_dep_yaml(ABSL_GEN_BUILD_YAML)
155  out.extend(yaml_to_gn_targets(absl_yaml, ['private'], 'grpc_absl_config'))
156
157  # Generate upb rules
158  upb_yaml = gen_grpc_dep_yaml(UPB_GEN_BUILD_YAML)
159  out.extend(yaml_to_gn_targets(upb_yaml, ['all'], 'grpc_upb_config'))
160
161  # Generate re2 rules
162  re2_yaml = gen_grpc_dep_yaml(RE2_GEN_BUILD_YAML)
163  out.extend(yaml_to_gn_targets(re2_yaml, ['private'], 'grpc_re2_config'))
164
165  # Generate boringssl rules
166  boringssl_yaml = gen_grpc_dep_yaml(BSSL_GEN_BUILD_YAML)
167  out.extend(
168      yaml_to_gn_targets(boringssl_yaml, ['private'], 'grpc_boringssl_config'))
169
170  # Generate grpc rules
171  with open(GRPC_BUILD_YAML, 'r', encoding='utf-8') as f:
172    grpc_yaml = yaml.safe_load(f.read())
173  out.extend(
174      yaml_to_gn_targets(grpc_yaml, ['all', 'protoc'], 'grpc_internal_config'))
175
176  print(GRPC_GN_HEADER)
177  print('\n'.join(out))
178  return 0
179
180
181if __name__ == '__main__':
182  sys.exit(main())
183