| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 1 | # Copyright (C) 2022 The Android Open Source Project | 
|  | 2 | # | 
|  | 3 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 4 | # you may not use this file except in compliance with the License. | 
|  | 5 | # You may obtain a copy of the License at | 
|  | 6 | # | 
|  | 7 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 8 | # | 
|  | 9 | # Unless required by applicable law or agreed to in writing, software | 
|  | 10 | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 12 | # See the License for the specific language governing permissions and | 
|  | 13 | # limitations under the License. | 
|  | 14 |  | 
|  | 15 | # A collection of utilities for extracting build rule information from GN | 
|  | 16 | # projects. | 
|  | 17 |  | 
|  | 18 | from __future__ import print_function | 
|  | 19 | import collections | 
|  | 20 | import errno | 
|  | 21 | import filecmp | 
|  | 22 | import json | 
| Patrick Rohr | af92fa6 | 2022-11-04 14:27:04 -0700 | [diff] [blame] | 23 | import logging as log | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 24 | import os | 
|  | 25 | import re | 
|  | 26 | import shutil | 
|  | 27 | import subprocess | 
|  | 28 | import sys | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 29 |  | 
|  | 30 | BUILDFLAGS_TARGET = '//gn:gen_buildflags' | 
|  | 31 | GEN_VERSION_TARGET = '//src/base:version_gen_h' | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 32 | LINKER_UNIT_TYPES = ('executable', 'shared_library', 'static_library', 'source_set') | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 33 |  | 
|  | 34 | # TODO(primiano): investigate these, they require further componentization. | 
|  | 35 | ODR_VIOLATION_IGNORE_TARGETS = { | 
|  | 36 | '//test/cts:perfetto_cts_deps', | 
|  | 37 | '//:perfetto_integrationtests', | 
|  | 38 | } | 
| Mohannad Farrag | 4bea14a | 2022-11-22 15:38:30 +0000 | [diff] [blame] | 39 | ARCH_REGEX = r'(android_x86_64|android_x86|android_arm|android_arm64|host)' | 
|  | 40 | DEX_REGEX = '.*__dex__%s$' % ARCH_REGEX | 
|  | 41 | COMPILE_JAVA_REGEX = '.*__compile_java__%s$' % ARCH_REGEX | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 42 | def repo_root(): | 
|  | 43 | """Returns an absolute path to the repository root.""" | 
|  | 44 | return os.path.join( | 
|  | 45 | os.path.realpath(os.path.dirname(__file__)), os.path.pardir) | 
|  | 46 |  | 
|  | 47 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 48 | def label_to_path(label): | 
|  | 49 | """Turn a GN output label (e.g., //some_dir/file.cc) into a path.""" | 
|  | 50 | assert label.startswith('//') | 
| Patrick Rohr | c6331c8 | 2022-10-25 11:34:20 -0700 | [diff] [blame] | 51 | return label[2:] or "./" | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 52 |  | 
|  | 53 |  | 
|  | 54 | def label_without_toolchain(label): | 
|  | 55 | """Strips the toolchain from a GN label. | 
|  | 56 |  | 
|  | 57 | Return a GN label (e.g //buildtools:protobuf(//gn/standalone/toolchain: | 
|  | 58 | gcc_like_host) without the parenthesised toolchain part. | 
|  | 59 | """ | 
|  | 60 | return label.split('(')[0] | 
|  | 61 |  | 
|  | 62 |  | 
|  | 63 | def label_to_target_name_with_path(label): | 
|  | 64 | """ | 
|  | 65 | Turn a GN label into a target name involving the full path. | 
|  | 66 | e.g., //src/perfetto:tests -> src_perfetto_tests | 
|  | 67 | """ | 
|  | 68 | name = re.sub(r'^//:?', '', label) | 
|  | 69 | name = re.sub(r'[^a-zA-Z0-9_]', '_', name) | 
|  | 70 | return name | 
|  | 71 |  | 
| Mohannad Farrag | a0db68b | 2022-11-24 12:28:09 +0000 | [diff] [blame] | 72 | def _is_java_source(src): | 
|  | 73 | return os.path.splitext(src)[1] == '.java' and not src.startswith("//out/test/gen/") | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 74 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 75 | class GnParser(object): | 
|  | 76 | """A parser with some cleverness for GN json desc files | 
|  | 77 |  | 
|  | 78 | The main goals of this parser are: | 
|  | 79 | 1) Deal with the fact that other build systems don't have an equivalent | 
|  | 80 | notion to GN's source_set. Conversely to Bazel's and Soong's filegroups, | 
|  | 81 | GN source_sets expect that dependencies, cflags and other source_set | 
|  | 82 | properties propagate up to the linker unit (static_library, executable or | 
|  | 83 | shared_library). This parser simulates the same behavior: when a | 
|  | 84 | source_set is encountered, some of its variables (cflags and such) are | 
|  | 85 | copied up to the dependent targets. This is to allow gen_xxx to create | 
|  | 86 | one filegroup for each source_set and then squash all the other flags | 
|  | 87 | onto the linker unit. | 
|  | 88 | 2) Detect and special-case protobuf targets, figuring out the protoc-plugin | 
|  | 89 | being used. | 
|  | 90 | """ | 
|  | 91 |  | 
|  | 92 | class Target(object): | 
|  | 93 | """Reperesents A GN target. | 
|  | 94 |  | 
|  | 95 | Maked properties are propagated up the dependency chain when a | 
|  | 96 | source_set dependency is encountered. | 
|  | 97 | """ | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 98 | class Arch(): | 
|  | 99 | """Architecture-dependent properties | 
|  | 100 | """ | 
|  | 101 | def __init__(self): | 
|  | 102 | self.sources = set() | 
| Motomu Utsumi | 1c64e44 | 2022-11-17 21:51:37 +0900 | [diff] [blame] | 103 | self.cflags = set() | 
| Motomu Utsumi | 80e0447 | 2022-11-17 21:54:06 +0900 | [diff] [blame] | 104 | self.defines = set() | 
| Motomu Utsumi | 778f830 | 2022-11-17 22:12:17 +0900 | [diff] [blame] | 105 | self.include_dirs = set() | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 106 | self.deps = set() | 
|  | 107 | self.transitive_static_libs_deps = set() | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 108 | self.source_set_deps = set() | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 109 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 110 |  | 
|  | 111 | def __init__(self, name, type): | 
|  | 112 | self.name = name  # e.g. //src/ipc:ipc | 
|  | 113 |  | 
|  | 114 | VALID_TYPES = ('static_library', 'shared_library', 'executable', 'group', | 
| Patrick Rohr | da778a0 | 2022-10-25 16:17:31 -0700 | [diff] [blame] | 115 | 'action', 'source_set', 'proto_library', 'copy', 'action_foreach') | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 116 | assert (type in VALID_TYPES) | 
|  | 117 | self.type = type | 
|  | 118 | self.testonly = False | 
|  | 119 | self.toolchain = None | 
|  | 120 |  | 
|  | 121 | # These are valid only for type == proto_library. | 
|  | 122 | # This is typically: 'proto', 'protozero', 'ipc'. | 
|  | 123 | self.proto_plugin = None | 
|  | 124 | self.proto_paths = set() | 
|  | 125 | self.proto_exports = set() | 
| Motomu Utsumi | d7e0e42 | 2022-11-08 17:49:52 +0900 | [diff] [blame] | 126 | self.proto_in_dir = "" | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 127 |  | 
|  | 128 | self.sources = set() | 
|  | 129 | # TODO(primiano): consider whether the public section should be part of | 
|  | 130 | # bubbled-up sources. | 
|  | 131 | self.public_headers = set()  # 'public' | 
|  | 132 |  | 
|  | 133 | # These are valid only for type == 'action' | 
|  | 134 | self.inputs = set() | 
|  | 135 | self.outputs = set() | 
|  | 136 | self.script = None | 
|  | 137 | self.args = [] | 
| Patrick Rohr | 09716f5 | 2022-10-27 13:02:36 -0700 | [diff] [blame] | 138 | self.response_file_contents = None | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 139 |  | 
|  | 140 | # These variables are propagated up when encountering a dependency | 
|  | 141 | # on a source_set target. | 
|  | 142 | self.cflags = set() | 
|  | 143 | self.defines = set() | 
|  | 144 | self.deps = set() | 
|  | 145 | self.libs = set() | 
|  | 146 | self.include_dirs = set() | 
|  | 147 | self.ldflags = set() | 
|  | 148 | self.source_set_deps = set()  # Transitive set of source_set deps. | 
|  | 149 | self.proto_deps = set() | 
|  | 150 | self.transitive_proto_deps = set() | 
| Mohannad Farrag | baf0d57 | 2022-11-22 11:53:54 +0000 | [diff] [blame] | 151 | self.rtti = False | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 152 |  | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 153 | # TODO: come up with a better way to only run this once. | 
|  | 154 | # is_finalized tracks whether finalize() was called on this target. | 
|  | 155 | self.is_finalized = False | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 156 | self.arch = dict() | 
|  | 157 |  | 
| Motomu Utsumi | ee47af6 | 2022-11-30 16:41:15 +0900 | [diff] [blame] | 158 | # This is used to get the name/version of libcronet | 
|  | 159 | self.output_name = None | 
|  | 160 |  | 
| Patrick Rohr | c8f41cd | 2022-11-15 22:46:10 -0800 | [diff] [blame] | 161 | def host_supported(self): | 
|  | 162 | return 'host' in self.arch | 
|  | 163 |  | 
|  | 164 | def device_supported(self): | 
|  | 165 | return any([name.startswith('android') for name in self.arch.keys()]) | 
|  | 166 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 167 | def __lt__(self, other): | 
|  | 168 | if isinstance(other, self.__class__): | 
|  | 169 | return self.name < other.name | 
|  | 170 | raise TypeError( | 
|  | 171 | '\'<\' not supported between instances of \'%s\' and \'%s\'' % | 
|  | 172 | (type(self).__name__, type(other).__name__)) | 
|  | 173 |  | 
|  | 174 | def __repr__(self): | 
|  | 175 | return json.dumps({ | 
|  | 176 | k: (list(sorted(v)) if isinstance(v, set) else v) | 
| Patrick Rohr | 23f2619 | 2022-10-25 09:45:22 -0700 | [diff] [blame] | 177 | for (k, v) in self.__dict__.items() | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 178 | }, | 
|  | 179 | indent=4, | 
|  | 180 | sort_keys=True) | 
|  | 181 |  | 
| Motomu Utsumi | 1c64e44 | 2022-11-17 21:51:37 +0900 | [diff] [blame] | 182 | def update(self, other, arch): | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 183 | for key in ('cflags', 'defines', 'deps', 'include_dirs', 'ldflags', | 
|  | 184 | 'source_set_deps', 'proto_deps', 'transitive_proto_deps', | 
|  | 185 | 'libs', 'proto_paths'): | 
|  | 186 | self.__dict__[key].update(other.__dict__.get(key, [])) | 
|  | 187 |  | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 188 | for key_in_arch in ('cflags', 'defines', 'include_dirs', 'source_set_deps'): | 
| Motomu Utsumi | 1c64e44 | 2022-11-17 21:51:37 +0900 | [diff] [blame] | 189 | self.arch[arch].__dict__[key_in_arch].update( | 
|  | 190 | other.arch[arch].__dict__.get(key_in_arch, [])) | 
|  | 191 |  | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 192 | def finalize(self): | 
|  | 193 | """Move common properties out of arch-dependent subobjects to Target object. | 
|  | 194 |  | 
|  | 195 | TODO: find a better name for this function. | 
|  | 196 | """ | 
|  | 197 | if self.is_finalized: | 
|  | 198 | return | 
|  | 199 | self.is_finalized = True | 
|  | 200 |  | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 201 | # Target contains the intersection of arch-dependent properties | 
|  | 202 | self.sources = set.intersection(*[arch.sources for arch in self.arch.values()]) | 
| Motomu Utsumi | f0f4768 | 2022-11-17 22:34:39 +0900 | [diff] [blame] | 203 | self.cflags = set.intersection(*[arch.cflags for arch in self.arch.values()]) | 
|  | 204 | self.defines = set.intersection(*[arch.defines for arch in self.arch.values()]) | 
|  | 205 | self.include_dirs = set.intersection(*[arch.include_dirs for arch in self.arch.values()]) | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 206 | self.deps.update(set.intersection(*[arch.deps for arch in self.arch.values()])) | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 207 | self.source_set_deps.update(set.intersection(*[arch.source_set_deps for arch in self.arch.values()])) | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 208 |  | 
|  | 209 | # Deduplicate arch-dependent properties | 
|  | 210 | for arch in self.arch.keys(): | 
|  | 211 | self.arch[arch].sources -= self.sources | 
| Motomu Utsumi | f0f4768 | 2022-11-17 22:34:39 +0900 | [diff] [blame] | 212 | self.arch[arch].cflags -= self.cflags | 
|  | 213 | self.arch[arch].defines -= self.defines | 
|  | 214 | self.arch[arch].include_dirs -= self.include_dirs | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 215 | self.arch[arch].deps -= self.deps | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 216 | self.arch[arch].source_set_deps -= self.source_set_deps | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 217 |  | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 218 |  | 
| Patrick Rohr | 564d6be | 2022-11-15 12:57:57 -0800 | [diff] [blame] | 219 | def __init__(self): | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 220 | self.all_targets = {} | 
|  | 221 | self.linker_units = {}  # Executables, shared or static libraries. | 
|  | 222 | self.source_sets = {} | 
|  | 223 | self.actions = {} | 
|  | 224 | self.proto_libs = {} | 
| Patrick Rohr | b27587e | 2022-11-04 14:57:24 -0700 | [diff] [blame] | 225 | self.java_sources = set() | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 226 |  | 
| Patrick Rohr | 09716f5 | 2022-10-27 13:02:36 -0700 | [diff] [blame] | 227 | def _get_response_file_contents(self, action_desc): | 
| Patrick Rohr | c20887d | 2022-10-28 12:59:20 -0700 | [diff] [blame] | 228 | # response_file_contents are formatted as: | 
|  | 229 | # ['--flags', '--flag=true && false'] and need to be formatted as: | 
|  | 230 | # '--flags --flag=\"true && false\"' | 
|  | 231 | flags = action_desc.get('response_file_contents', []) | 
|  | 232 | formatted_flags = [] | 
|  | 233 | for flag in flags: | 
|  | 234 | if '=' in flag: | 
|  | 235 | key, val = flag.split('=') | 
|  | 236 | formatted_flags.append('%s=\\"%s\\"' % (key, val)) | 
|  | 237 | else: | 
|  | 238 | formatted_flags.append(flag) | 
|  | 239 |  | 
|  | 240 | return ' '.join(formatted_flags) | 
| Patrick Rohr | 09716f5 | 2022-10-27 13:02:36 -0700 | [diff] [blame] | 241 |  | 
| Patrick Rohr | af92fa6 | 2022-11-04 14:27:04 -0700 | [diff] [blame] | 242 | def _is_java_target(self, target): | 
|  | 243 | # Per https://chromium.googlesource.com/chromium/src/build/+/HEAD/android/docs/java_toolchain.md | 
|  | 244 | # java target names must end in "_java". | 
|  | 245 | # TODO: There are some other possible variations we might need to support. | 
| Patrick Rohr | 67f5312 | 2022-11-09 10:57:40 -0800 | [diff] [blame] | 246 | return target.type == 'group' and re.match('.*_java$', target.name) | 
| Patrick Rohr | af92fa6 | 2022-11-04 14:27:04 -0700 | [diff] [blame] | 247 |  | 
| Patrick Rohr | 81a4ac3 | 2022-11-15 14:38:21 -0800 | [diff] [blame] | 248 | def _get_arch(self, toolchain): | 
| Patrick Rohr | d938d53 | 2022-11-15 22:17:08 -0800 | [diff] [blame] | 249 | if toolchain == '//build/toolchain/android:android_clang_x86': | 
| Patrick Rohr | 4eff210 | 2022-11-15 22:21:52 -0800 | [diff] [blame] | 250 | return 'android_x86' | 
| Patrick Rohr | 81a4ac3 | 2022-11-15 14:38:21 -0800 | [diff] [blame] | 251 | elif toolchain == '//build/toolchain/android:android_clang_x64': | 
| Patrick Rohr | 4eff210 | 2022-11-15 22:21:52 -0800 | [diff] [blame] | 252 | return 'android_x86_64' | 
| Patrick Rohr | 81a4ac3 | 2022-11-15 14:38:21 -0800 | [diff] [blame] | 253 | elif toolchain == '//build/toolchain/android:android_clang_arm': | 
| Patrick Rohr | 4eff210 | 2022-11-15 22:21:52 -0800 | [diff] [blame] | 254 | return 'android_arm' | 
| Patrick Rohr | 81a4ac3 | 2022-11-15 14:38:21 -0800 | [diff] [blame] | 255 | elif toolchain == '//build/toolchain/android:android_clang_arm64': | 
| Patrick Rohr | 4eff210 | 2022-11-15 22:21:52 -0800 | [diff] [blame] | 256 | return 'android_arm64' | 
| Patrick Rohr | 81a4ac3 | 2022-11-15 14:38:21 -0800 | [diff] [blame] | 257 | else: | 
|  | 258 | return 'host' | 
|  | 259 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 260 | def get_target(self, gn_target_name): | 
|  | 261 | """Returns a Target object from the fully qualified GN target name. | 
|  | 262 |  | 
| Patrick Rohr | d0077b7 | 2022-11-15 12:43:26 -0800 | [diff] [blame] | 263 | get_target() requires that parse_gn_desc() has already been called. | 
|  | 264 | """ | 
| Patrick Rohr | 7091356 | 2022-11-15 21:49:28 -0800 | [diff] [blame] | 265 | # Run this every time as parse_gn_desc can be called at any time. | 
|  | 266 | for target in self.all_targets.values(): | 
|  | 267 | target.finalize() | 
|  | 268 |  | 
| Patrick Rohr | 7705bdb | 2022-11-15 13:26:30 -0800 | [diff] [blame] | 269 | return self.all_targets[label_without_toolchain(gn_target_name)] | 
| Patrick Rohr | d0077b7 | 2022-11-15 12:43:26 -0800 | [diff] [blame] | 270 |  | 
| Patrick Rohr | 564d6be | 2022-11-15 12:57:57 -0800 | [diff] [blame] | 271 | def parse_gn_desc(self, gn_desc, gn_target_name): | 
| Patrick Rohr | d0077b7 | 2022-11-15 12:43:26 -0800 | [diff] [blame] | 272 | """Parses a gn desc tree and resolves all target dependencies. | 
|  | 273 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 274 | It bubbles up variables from source_set dependencies as described in the | 
|  | 275 | class-level comments. | 
|  | 276 | """ | 
| Patrick Rohr | 7705bdb | 2022-11-15 13:26:30 -0800 | [diff] [blame] | 277 | # Use name without toolchain for targets to support targets built for | 
|  | 278 | # multiple archs. | 
|  | 279 | target_name = label_without_toolchain(gn_target_name) | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 280 | desc = gn_desc[gn_target_name] | 
| Patrick Rohr | 9860068 | 2022-11-18 18:29:15 -0800 | [diff] [blame] | 281 | type_ = desc['type'] | 
| Patrick Rohr | d938d53 | 2022-11-15 22:17:08 -0800 | [diff] [blame] | 282 | arch = self._get_arch(desc['toolchain']) | 
| Patrick Rohr | 9860068 | 2022-11-18 18:29:15 -0800 | [diff] [blame] | 283 |  | 
|  | 284 | # Action modules can differ depending on the target architecture, yet | 
|  | 285 | # genrule's do not allow to overload cmd per target OS / arch.  Create a | 
|  | 286 | # separate action for every architecture. | 
| Mohannad Farrag | d7efd7b9 | 2022-11-21 16:15:16 +0000 | [diff] [blame] | 287 | # Cover both action and action_foreach | 
|  | 288 | if type_.startswith('action'): | 
| Patrick Rohr | 9860068 | 2022-11-18 18:29:15 -0800 | [diff] [blame] | 289 | target_name += '__' + arch | 
|  | 290 |  | 
|  | 291 | target = self.all_targets.get(target_name) | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 292 | if target is None: | 
| Patrick Rohr | 9860068 | 2022-11-18 18:29:15 -0800 | [diff] [blame] | 293 | target = GnParser.Target(target_name, type_) | 
| Patrick Rohr | 02ad51f | 2022-11-15 13:54:07 -0800 | [diff] [blame] | 294 | self.all_targets[target_name] = target | 
|  | 295 |  | 
|  | 296 | if arch not in target.arch: | 
|  | 297 | target.arch[arch] = GnParser.Target.Arch() | 
|  | 298 | else: | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 299 | return target  # Target already processed. | 
|  | 300 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 301 | target.testonly = desc.get('testonly', False) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 302 |  | 
| Patrick Rohr | 0d40da3 | 2022-11-15 13:08:12 -0800 | [diff] [blame] | 303 | proto_target_type, proto_desc = self.get_proto_target_type(gn_desc, gn_target_name) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 304 | if proto_target_type is not None: | 
|  | 305 | self.proto_libs[target.name] = target | 
|  | 306 | target.type = 'proto_library' | 
|  | 307 | target.proto_plugin = proto_target_type | 
|  | 308 | target.proto_paths.update(self.get_proto_paths(proto_desc)) | 
|  | 309 | target.proto_exports.update(self.get_proto_exports(proto_desc)) | 
| Motomu Utsumi | d7e0e42 | 2022-11-08 17:49:52 +0900 | [diff] [blame] | 310 | target.proto_in_dir = self.get_proto_in_dir(proto_desc) | 
| Patrick Rohr | ad7a29c | 2022-11-16 21:48:09 -0800 | [diff] [blame] | 311 | for gn_proto_deps_name in proto_desc.get('deps', []): | 
|  | 312 | dep = self.parse_gn_desc(gn_desc, gn_proto_deps_name) | 
|  | 313 | target.deps.add(dep.name) | 
| Patrick Rohr | 53dcd10 | 2022-11-15 21:53:02 -0800 | [diff] [blame] | 314 | target.arch[arch].sources.update(proto_desc.get('sources', [])) | 
|  | 315 | assert (all(x.endswith('.proto') for x in target.arch[arch].sources)) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 316 | elif target.type == 'source_set': | 
|  | 317 | self.source_sets[gn_target_name] = target | 
| Patrick Rohr | 53dcd10 | 2022-11-15 21:53:02 -0800 | [diff] [blame] | 318 | target.arch[arch].sources.update(desc.get('sources', [])) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 319 | elif target.type in LINKER_UNIT_TYPES: | 
|  | 320 | self.linker_units[gn_target_name] = target | 
| Patrick Rohr | 53dcd10 | 2022-11-15 21:53:02 -0800 | [diff] [blame] | 321 | target.arch[arch].sources.update(desc.get('sources', [])) | 
| Patrick Rohr | da778a0 | 2022-10-25 16:17:31 -0700 | [diff] [blame] | 322 | elif target.type in ['action', 'action_foreach']: | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 323 | self.actions[gn_target_name] = target | 
|  | 324 | target.inputs.update(desc.get('inputs', [])) | 
| Patrick Rohr | 53dcd10 | 2022-11-15 21:53:02 -0800 | [diff] [blame] | 325 | target.arch[arch].sources.update(desc.get('sources', [])) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 326 | outs = [re.sub('^//out/.+?/gen/', '', x) for x in desc['outputs']] | 
|  | 327 | target.outputs.update(outs) | 
|  | 328 | target.script = desc['script'] | 
| Patrick Rohr | 7aa98f9 | 2022-10-28 11:16:36 -0700 | [diff] [blame] | 329 | target.args = desc['args'] | 
| Patrick Rohr | 09716f5 | 2022-10-27 13:02:36 -0700 | [diff] [blame] | 330 | target.response_file_contents = self._get_response_file_contents(desc) | 
| Patrick Rohr | da778a0 | 2022-10-25 16:17:31 -0700 | [diff] [blame] | 331 | elif target.type == 'copy': | 
|  | 332 | # TODO: copy rules are not currently implemented. | 
|  | 333 | self.actions[gn_target_name] = target | 
| Patrick Rohr | 67f5312 | 2022-11-09 10:57:40 -0800 | [diff] [blame] | 334 | elif self._is_java_target(target): | 
| Patrick Rohr | af92fa6 | 2022-11-04 14:27:04 -0700 | [diff] [blame] | 335 | # java_group identifies the group target generated by the android_library | 
|  | 336 | # or java_library template. A java_group must not be added as a dependency, but sources are collected | 
|  | 337 | log.debug('Found java target %s', target.name) | 
|  | 338 | target.type = 'java_group' | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 339 |  | 
|  | 340 | # Default for 'public' is //* - all headers in 'sources' are public. | 
|  | 341 | # TODO(primiano): if a 'public' section is specified (even if empty), then | 
|  | 342 | # the rest of 'sources' is considered inaccessible by gn. Consider | 
|  | 343 | # emulating that, so that generated build files don't end up with overly | 
|  | 344 | # accessible headers. | 
|  | 345 | public_headers = [x for x in desc.get('public', []) if x != '*'] | 
|  | 346 | target.public_headers.update(public_headers) | 
|  | 347 |  | 
| Motomu Utsumi | 1c64e44 | 2022-11-17 21:51:37 +0900 | [diff] [blame] | 348 | target.arch[arch].cflags.update(desc.get('cflags', []) + desc.get('cflags_cc', [])) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 349 | target.libs.update(desc.get('libs', [])) | 
|  | 350 | target.ldflags.update(desc.get('ldflags', [])) | 
| Motomu Utsumi | 80e0447 | 2022-11-17 21:54:06 +0900 | [diff] [blame] | 351 | target.arch[arch].defines.update(desc.get('defines', [])) | 
| Motomu Utsumi | 778f830 | 2022-11-17 22:12:17 +0900 | [diff] [blame] | 352 | target.arch[arch].include_dirs.update(desc.get('include_dirs', [])) | 
| Motomu Utsumi | ee47af6 | 2022-11-30 16:41:15 +0900 | [diff] [blame] | 353 | target.output_name = desc.get('output_name', None) | 
| Mohannad Farrag | baf0d57 | 2022-11-22 11:53:54 +0000 | [diff] [blame] | 354 | if "-frtti" in target.arch[arch].cflags: | 
|  | 355 | target.rtti = True | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 356 |  | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 357 | # Recurse in dependencies. | 
| Patrick Rohr | 7f4631e | 2022-11-15 14:35:03 -0800 | [diff] [blame] | 358 | for gn_dep_name in desc.get('deps', []): | 
|  | 359 | dep = self.parse_gn_desc(gn_desc, gn_dep_name) | 
| Patrick Rohr | f100437 | 2022-11-16 23:04:05 -0800 | [diff] [blame] | 360 | if dep.type == 'proto_library': | 
| Patrick Rohr | 9006b36 | 2022-11-16 21:49:53 -0800 | [diff] [blame] | 361 | target.proto_deps.add(dep.name) | 
|  | 362 | target.transitive_proto_deps.add(dep.name) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 363 | target.proto_paths.update(dep.proto_paths) | 
|  | 364 | target.transitive_proto_deps.update(dep.transitive_proto_deps) | 
|  | 365 | elif dep.type == 'source_set': | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 366 | target.arch[arch].source_set_deps.add(dep.name) | 
|  | 367 | target.arch[arch].source_set_deps.update(dep.arch[arch].source_set_deps) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 368 | elif dep.type == 'group': | 
| Motomu Utsumi | 1c64e44 | 2022-11-17 21:51:37 +0900 | [diff] [blame] | 369 | target.update(dep, arch)  # Bubble up groups's cflags/ldflags etc. | 
| Patrick Rohr | da778a0 | 2022-10-25 16:17:31 -0700 | [diff] [blame] | 370 | elif dep.type in ['action', 'action_foreach', 'copy']: | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 371 | if proto_target_type is None: | 
| Mohannad Farrag | 1de6cb1 | 2022-11-28 12:27:26 +0000 | [diff] [blame] | 372 | target.arch[arch].deps.add(dep.name) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 373 | elif dep.type in LINKER_UNIT_TYPES: | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 374 | target.arch[arch].deps.add(dep.name) | 
| Patrick Rohr | 3624f95 | 2022-11-04 14:30:18 -0700 | [diff] [blame] | 375 | elif dep.type == 'java_group': | 
|  | 376 | # Explicitly break dependency chain when a java_group is added. | 
|  | 377 | # Java sources are collected and eventually compiled as one large | 
|  | 378 | # java_library. | 
|  | 379 | pass | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 380 |  | 
| Mohannad Farrag | 7f29d83 | 2022-11-23 19:52:41 +0000 | [diff] [blame] | 381 | # Source set bubble up transitive source sets but can't be combined with this | 
|  | 382 | # if they are combined then source sets will bubble up static libraries | 
|  | 383 | # while we only want to have source sets bubble up only source sets. | 
| Patrick Rohr | 5de9f2e | 2022-11-11 15:33:20 -0800 | [diff] [blame] | 384 | if dep.type == 'static_library': | 
|  | 385 | # Bubble up static_libs. Necessary, since soong does not propagate | 
|  | 386 | # static_libs up the build tree. | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 387 | target.arch[arch].transitive_static_libs_deps.add(dep.name) | 
| Patrick Rohr | a9c1dda | 2022-11-14 19:02:40 -0800 | [diff] [blame] | 388 |  | 
| Patrick Rohr | 297f979 | 2022-11-16 23:40:40 -0800 | [diff] [blame] | 389 | if arch in dep.arch: | 
|  | 390 | target.arch[arch].transitive_static_libs_deps.update( | 
|  | 391 | dep.arch[arch].transitive_static_libs_deps) | 
|  | 392 | target.arch[arch].deps.update(target.arch[arch].transitive_static_libs_deps) | 
| Patrick Rohr | 5de9f2e | 2022-11-11 15:33:20 -0800 | [diff] [blame] | 393 |  | 
| Patrick Rohr | b27587e | 2022-11-04 14:57:24 -0700 | [diff] [blame] | 394 | # Collect java sources. Java sources are kept inside the __compile_java target. | 
|  | 395 | # This target can be used for both host and target compilation; only add | 
|  | 396 | # the sources if they are destined for the target (i.e. they are a | 
|  | 397 | # dependency of the __dex target) | 
|  | 398 | # Note: this skips prebuilt java dependencies. These will have to be | 
|  | 399 | # added manually when building the jar. | 
| Mohannad Farrag | 4bea14a | 2022-11-22 15:38:30 +0000 | [diff] [blame] | 400 | if re.match(DEX_REGEX, target.name): | 
|  | 401 | if re.match(COMPILE_JAVA_REGEX, dep.name): | 
| Patrick Rohr | b27587e | 2022-11-04 14:57:24 -0700 | [diff] [blame] | 402 | log.debug('Adding java sources for %s', dep.name) | 
| Mohannad Farrag | a0db68b | 2022-11-24 12:28:09 +0000 | [diff] [blame] | 403 | java_srcs = [src for src in dep.inputs if _is_java_source(src)] | 
| Patrick Rohr | b27587e | 2022-11-04 14:57:24 -0700 | [diff] [blame] | 404 | self.java_sources.update(java_srcs) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 405 | return target | 
|  | 406 |  | 
|  | 407 | def get_proto_exports(self, proto_desc): | 
|  | 408 | # exports in metadata will be available for source_set targets. | 
|  | 409 | metadata = proto_desc.get('metadata', {}) | 
|  | 410 | return metadata.get('exports', []) | 
|  | 411 |  | 
|  | 412 | def get_proto_paths(self, proto_desc): | 
|  | 413 | # import_dirs in metadata will be available for source_set targets. | 
|  | 414 | metadata = proto_desc.get('metadata', {}) | 
|  | 415 | return metadata.get('import_dirs', []) | 
|  | 416 |  | 
| Motomu Utsumi | d7e0e42 | 2022-11-08 17:49:52 +0900 | [diff] [blame] | 417 |  | 
|  | 418 | def get_proto_in_dir(self, proto_desc): | 
|  | 419 | args = proto_desc.get('args') | 
|  | 420 | return re.sub('^\.\./\.\./', '', args[args.index('--proto-in-dir') + 1]) | 
|  | 421 |  | 
| Patrick Rohr | 0d40da3 | 2022-11-15 13:08:12 -0800 | [diff] [blame] | 422 | def get_proto_target_type(self, gn_desc, gn_target_name): | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 423 | """ Checks if the target is a proto library and return the plugin. | 
|  | 424 |  | 
|  | 425 | Returns: | 
|  | 426 | (None, None): if the target is not a proto library. | 
|  | 427 | (plugin, proto_desc) where |plugin| is 'proto' in the default (lite) | 
|  | 428 | case or 'protozero' or 'ipc' or 'descriptor'; |proto_desc| is the GN | 
|  | 429 | json desc of the target with the .proto sources (_gen target for | 
|  | 430 | non-descriptor types or the target itself for descriptor type). | 
|  | 431 | """ | 
| Patrick Rohr | 0d40da3 | 2022-11-15 13:08:12 -0800 | [diff] [blame] | 432 | parts = gn_target_name.split('(', 1) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 433 | name = parts[0] | 
|  | 434 | toolchain = '(' + parts[1] if len(parts) > 1 else '' | 
|  | 435 |  | 
|  | 436 | # Descriptor targets don't have a _gen target; instead we look for the | 
|  | 437 | # characteristic flag in the args of the target itself. | 
| Patrick Rohr | 0d40da3 | 2022-11-15 13:08:12 -0800 | [diff] [blame] | 438 | desc = gn_desc.get(gn_target_name) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 439 | if '--descriptor_set_out' in desc.get('args', []): | 
|  | 440 | return 'descriptor', desc | 
|  | 441 |  | 
|  | 442 | # Source set proto targets have a non-empty proto_library_sources in the | 
|  | 443 | # metadata of the description. | 
|  | 444 | metadata = desc.get('metadata', {}) | 
|  | 445 | if 'proto_library_sources' in metadata: | 
|  | 446 | return 'source_set', desc | 
|  | 447 |  | 
|  | 448 | # In all other cases, we want to look at the _gen target as that has the | 
|  | 449 | # important information. | 
| Patrick Rohr | 564d6be | 2022-11-15 12:57:57 -0800 | [diff] [blame] | 450 | gen_desc = gn_desc.get('%s_gen%s' % (name, toolchain)) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 451 | if gen_desc is None or gen_desc['type'] != 'action': | 
|  | 452 | return None, None | 
| Patrick Rohr | c598078 | 2022-11-07 16:34:03 -0800 | [diff] [blame] | 453 | if gen_desc['script'] != '//tools/protoc_wrapper/protoc_wrapper.py': | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 454 | return None, None | 
|  | 455 | plugin = 'proto' | 
| Patrick Rohr | c598078 | 2022-11-07 16:34:03 -0800 | [diff] [blame] | 456 | args = gen_desc.get('args', []) | 
| Patrick Rohr | 92d7412 | 2022-10-21 15:50:52 -0700 | [diff] [blame] | 457 | for arg in (arg for arg in args if arg.startswith('--plugin=')): | 
|  | 458 | # |arg| at this point looks like: | 
|  | 459 | #  --plugin=protoc-gen-plugin=gcc_like_host/protozero_plugin | 
|  | 460 | # or | 
|  | 461 | #  --plugin=protoc-gen-plugin=protozero_plugin | 
|  | 462 | plugin = arg.split('=')[-1].split('/')[-1].replace('_plugin', '') | 
|  | 463 | return plugin, gen_desc |