1#!/usr/bin/env python3 2# Copyright (C) 2018 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 16# This tool translates a collection of BUILD.gn files into a mostly equivalent 17# BUILD file for the Bazel build system. The input to the tool is a 18# JSON description of the GN build definition generated with the following 19# command: 20# 21# gn desc out --format=json --all-toolchains "//*" > desc.json 22# 23# The tool is then given a list of GN labels for which to generate Bazel 24# build rules. 25 26from __future__ import print_function 27import argparse 28import itertools 29import json 30import os 31import re 32import sys 33 34import gn_utils 35 36from compat import itervalues, iteritems, basestring 37 38# Arguments for the GN output directory. 39# host_os="linux" is to generate the right build files from Mac OS. 40gn_args = ' '.join([ 41 'host_os="linux"', 42 'is_debug=false', 43 'is_perfetto_build_generator=true', 44 'monolithic_binaries=true', 45 'target_os="linux"', 46 'enable_perfetto_heapprofd=false', 47 'enable_perfetto_traced_perf=false', 48 'perfetto_force_dcheck="off"', 49 'enable_perfetto_llvm_demangle=true', 50]) 51 52# Default targets to translate to the blueprint file. 53 54# These targets will be exported with public visibility in the generated BUILD. 55public_targets = [ 56 '//:libperfetto_client_experimental', 57 '//src/perfetto_cmd:perfetto', 58 '//src/traced/probes:traced_probes', 59 '//src/traced/service:traced', 60 '//src/trace_processor:trace_processor_shell', 61 '//src/trace_processor:trace_processor', 62 '//tools/trace_to_text:trace_to_text', 63 '//tools/trace_to_text:libpprofbuilder', 64] 65 66# These targets are required by internal build rules but don't need to be 67# exported publicly. 68default_targets = [ 69 '//src/ipc:perfetto_ipc', 70 '//src/ipc/protoc_plugin:ipc_plugin', 71 '//src/protozero:protozero', 72 '//src/protozero/protoc_plugin:protozero_plugin', 73 '//src/protozero/protoc_plugin:cppgen_plugin', 74 '//test:client_api_example', 75 '//tools/proto_filter:proto_filter', 76 '//tools/proto_merger:proto_merger', 77] + public_targets 78 79# Proto target groups which will be made public. 80proto_groups = { 81 'config': ['//protos/perfetto/config:source_set'], 82 'trace': [ 83 '//protos/perfetto/trace:non_minimal_source_set', 84 '//protos/perfetto/trace:minimal_source_set' 85 ], 86 'metrics': ['//protos/perfetto/metrics:source_set',], 87 'chromium': ['//protos/third_party/chromium:source_set',], 88 'chrome_metrics': ['//protos/perfetto/metrics/chrome:source_set',], 89} 90 91# Path for the protobuf sources in the standalone build. 92buildtools_protobuf_src = '//buildtools/protobuf/src' 93 94# The directory where the generated perfetto_build_flags.h will be copied into. 95buildflags_dir = 'include/perfetto/base/build_configs/bazel' 96 97# Internal equivalents for third-party libraries that the upstream project 98# depends on. 99external_deps = { 100 '//gn:default_deps': [], 101 '//gn:jsoncpp': ['PERFETTO_CONFIG.deps.jsoncpp'], 102 '//gn:linenoise': ['PERFETTO_CONFIG.deps.linenoise'], 103 '//gn:protobuf_full': ['PERFETTO_CONFIG.deps.protobuf_full'], 104 '//gn:protobuf_lite': ['PERFETTO_CONFIG.deps.protobuf_lite'], 105 '//gn:protoc_lib': ['PERFETTO_CONFIG.deps.protoc_lib'], 106 '//gn:protoc': ['PERFETTO_CONFIG.deps.protoc'], 107 '//gn:sqlite': [ 108 'PERFETTO_CONFIG.deps.sqlite', 109 'PERFETTO_CONFIG.deps.sqlite_ext_percentile' 110 ], 111 '//gn:zlib': ['PERFETTO_CONFIG.deps.zlib'], 112 '//gn:llvm_demangle': ['PERFETTO_CONFIG.deps.llvm_demangle'], 113 '//src/trace_processor:demangle': ['PERFETTO_CONFIG.deps.demangle_wrapper'], 114 '//src/trace_processor/metrics/sql:gen_amalgamated_sql_metrics': [[ 115 ':cc_amalgamated_sql_metrics' 116 ]], 117 gn_utils.GEN_VERSION_TARGET: ['PERFETTO_CONFIG.deps.version_header'], 118} 119 120 121def gen_amalgamated_sql_metrics(target): 122 label = BazelLabel(get_bazel_label_name(target.name), 'perfetto_genrule') 123 label.srcs += [re.sub('^//', '', x) for x in sorted(target.inputs)] 124 label.outs += target.outputs 125 label.cmd = r'$(location gen_amalgamated_sql_metrics_py) --cpp_out=$@ $(SRCS)' 126 label.exec_tools += [':gen_amalgamated_sql_metrics_py'] 127 return [label] 128 129 130def gen_version_header(target): 131 label = BazelLabel(get_bazel_label_name(target.name), 'perfetto_genrule') 132 label.srcs += [re.sub('^//', '', x) for x in sorted(target.inputs)] 133 label.outs += target.outputs 134 label.cmd = r'$(location gen_version_header_py)' 135 label.cmd += r' --cpp_out=$@ --changelog=$(location CHANGELOG)' 136 label.exec_tools += [':gen_version_header_py'] 137 return [label] 138 139 140def gen_cc_metrics_descriptor(target): 141 label = BazelLabel( 142 get_bazel_label_name(target.name), 'perfetto_cc_proto_descriptor') 143 label.deps += [':' + get_bazel_label_name(x) for x in target.proto_deps] 144 label.outs += target.outputs 145 return [label] 146 147 148custom_actions = { 149 gn_utils.GEN_VERSION_TARGET: 150 gen_version_header, 151 '//src/trace_processor/metrics/sql:gen_amalgamated_sql_metrics': 152 gen_amalgamated_sql_metrics, 153} 154 155# ------------------------------------------------------------------------------ 156# End of configuration. 157# ------------------------------------------------------------------------------ 158 159 160class Error(Exception): 161 pass 162 163 164class BazelLabel(object): 165 166 def __init__(self, name, type): 167 self.comment = None 168 self.name = name 169 self.type = type 170 self.visibility = [] 171 self.srcs = [] 172 self.hdrs = [] 173 self.deps = [] 174 self.external_deps = [] 175 self.tools = [] 176 self.exec_tools = [] 177 self.outs = [] 178 self.exports = [] 179 180 def __lt__(self, other): 181 if isinstance(other, self.__class__): 182 return self.name < other.name 183 raise TypeError( 184 '\'<\' not supported between instances of \'%s\' and \'%s\'' % 185 (type(self).__name__, type(other).__name__)) 186 187 def __str__(self): 188 """Converts the object into a Bazel Starlark label.""" 189 res = '' 190 res += ('# GN target: %s\n' % self.comment) if self.comment else '' 191 res += '%s(\n' % self.type 192 any_deps = len(self.deps) + len(self.external_deps) > 0 193 ORD = [ 194 'name', 'srcs', 'hdrs', 'visibility', 'deps', 'outs', 'cmd', 'tools', 195 'exec_tools', 'exports' 196 ] 197 hasher = lambda x: sum((99,) + tuple(ord(c) for c in x)) 198 key_sorter = lambda kv: ORD.index(kv[0]) if kv[0] in ORD else hasher(kv[0]) 199 for k, v in sorted(iteritems(self.__dict__), key=key_sorter): 200 if k in ('type', 'comment', 201 'external_deps') or v is None or (v == [] and 202 (k != 'deps' or not any_deps)): 203 continue 204 res += ' %s = ' % k 205 if isinstance(v, basestring): 206 if v.startswith('PERFETTO_CONFIG.'): 207 res += '%s,\n' % v 208 else: 209 res += '"%s",\n' % v 210 elif isinstance(v, bool): 211 res += '%s,\n' % v 212 elif isinstance(v, list): 213 res += '[\n' 214 if k == 'deps' and len(self.external_deps) > 1: 215 indent = ' ' 216 else: 217 indent = ' ' 218 for entry in sorted(v): 219 if entry.startswith('PERFETTO_CONFIG.'): 220 res += '%s %s,\n' % (indent, entry) 221 else: 222 res += '%s "%s",\n' % (indent, entry) 223 res += '%s]' % indent 224 if k == 'deps' and self.external_deps: 225 res += ' + %s' % self.external_deps[0] 226 for edep in self.external_deps[1:]: 227 if isinstance(edep, list): 228 res += ' + [\n' 229 for inner_dep in edep: 230 res += ' "%s",\n' % inner_dep 231 res += ' ]' 232 else: 233 res += ' +\n%s%s' % (indent, edep) 234 res += ',\n' 235 else: 236 raise Error('Unsupported value %s', type(v)) 237 res += ')\n\n' 238 return res 239 240 241# Public visibility for targets in Bazel. 242PUBLIC_VISIBILITY = 'PERFETTO_CONFIG.public_visibility' 243 244 245def get_bazel_label_name(gn_name): 246 """Converts a GN target name into a Bazel label name. 247 248 If target is in the public target list, returns only the GN target name, 249 e.g.: //src/ipc:perfetto_ipc -> perfetto_ipc 250 251 Otherwise, in the case of an intermediate target, returns a mangled path. 252 e.g.: //include/perfetto/base:base -> include_perfetto_base_base. 253 """ 254 if gn_name in default_targets: 255 return gn_utils.label_without_toolchain(gn_name).split(':')[1] 256 return gn_utils.label_to_target_name_with_path(gn_name) 257 258 259def get_bazel_proto_sources_label(target_name): 260 """Converts a GN target name into a Bazel proto label name.""" 261 return re.sub('_(lite|zero|cpp|ipc|source_set|descriptor)$', '', 262 get_bazel_label_name(target_name)) + '_protos' 263 264 265def gen_proto_label(target): 266 """ Generates the xx_proto_library label for proto targets.""" 267 assert (target.type == 'proto_library') 268 269 sources_label_name = get_bazel_proto_sources_label(target.name) 270 271 # For 'source_set' plugins, we don't want to generate any plugin-dependent 272 # targets so just return the label of the proto sources only. 273 if target.proto_plugin == 'source_set': 274 sources_label = BazelLabel(sources_label_name, 'perfetto_proto_library') 275 sources_label.comment = target.name 276 assert (all(x.startswith('//') for x in target.sources)) 277 assert (all(x.endswith('.proto') for x in target.sources)) 278 sources_label.srcs = sorted([x[2:] for x in target.sources]) # Strip //. 279 sources_label.deps = sorted([ 280 ':' + get_bazel_proto_sources_label(x) 281 for x in target.transitive_proto_deps 282 ]) 283 284 # In Bazel, proto_paths are not a supported concept becauase strong 285 # dependency checking is enabled. Instead, we need to depend on the target 286 # which includes the proto we want to depend on. 287 # For example, we include the proto_path |buildtools_protobuf_src| because 288 # we want to depend on the "google/protobuf/descriptor.proto" proto file. 289 # This will be exposed by the |protobuf_descriptor_proto| dep. 290 if buildtools_protobuf_src in target.proto_paths: 291 sources_label.external_deps = [ 292 'PERFETTO_CONFIG.deps.protobuf_descriptor_proto' 293 ] 294 295 sources_label.visibility = ['PERFETTO_CONFIG.proto_library_visibility'] 296 297 sources_label.exports = sorted( 298 [':' + get_bazel_proto_sources_label(d) for d in target.proto_exports]) 299 return sources_label 300 301 # For all other types of plugins, we need to generate 302 if target.proto_plugin == 'proto': 303 plugin_label_type = 'perfetto_cc_proto_library' 304 elif target.proto_plugin == 'protozero': 305 plugin_label_type = 'perfetto_cc_protozero_library' 306 elif target.proto_plugin == 'cppgen': 307 plugin_label_type = 'perfetto_cc_protocpp_library' 308 elif target.proto_plugin == 'ipc': 309 plugin_label_type = 'perfetto_cc_ipc_library' 310 elif target.proto_plugin == 'descriptor': 311 plugin_label_type = 'perfetto_proto_descriptor' 312 else: 313 raise Error('Unknown proto plugin: %s' % target.proto_plugin) 314 plugin_label_name = get_bazel_label_name(target.name) 315 plugin_label = BazelLabel(plugin_label_name, plugin_label_type) 316 plugin_label.comment = target.name 317 318 # When using the plugins we need to pass down also the transitive deps. 319 # For instance consider foo.proto including common.proto. The generated 320 # foo.cc will #include "common.gen.h". Hence the generated cc_protocpp_library 321 # rule need to pass down the dependency on the target that generates 322 # common.gen.{cc,h}. 323 if target.proto_plugin in ('cppgen', 'ipc', 'protozero'): 324 plugin_label.deps += [ 325 ':' + get_bazel_label_name(x) for x in target.transitive_proto_deps 326 ] 327 328 # Add any dependencies on source_set targets (i.e. targets containing proto 329 # files). For descriptors, we will have an explicit edge between the 330 # descriptor and source set wheras for other plugin types, this edge is 331 # implicit. 332 if target.proto_plugin == 'descriptor': 333 plugin_label.deps += [ 334 ':' + get_bazel_proto_sources_label(x) for x in target.proto_deps 335 ] 336 else: 337 plugin_label.deps += [':' + sources_label_name] 338 339 # Since the descriptor generates an explicit output file which can be 340 # referenced by other targets, we specify a name for it. 341 if target.proto_plugin == 'descriptor': 342 plugin_label.outs = [plugin_label_name + '.bin'] 343 344 return plugin_label 345 346 347def gen_proto_group_target(gn, name, target_names): 348 # Get a recursive list of the proto_library targets rooted here which 349 # have src. 350 deps_set = set(target_names) 351 for target_name in target_names: 352 target = gn.get_target(target_name) 353 deps_set.update(target.transitive_proto_deps) 354 355 # First, create a root source set target which references all the child 356 # source set targets. We publish this as well as depending on this in all 357 # subsequent targets. 358 sources_label = BazelLabel(name + '_proto', 'perfetto_proto_library') 359 sources_label.deps = [ 360 ':' + get_bazel_proto_sources_label(name) 361 for name in sorted(list(deps_set)) 362 ] 363 sources_label.visibility = PUBLIC_VISIBILITY 364 sources_label.comment = f'''[{', '.join(target_names)}]''' 365 366 cc_label = BazelLabel(name + '_cc_proto', 'perfetto_cc_proto_library') 367 cc_label.deps = [':' + sources_label.name] 368 cc_label.visibility = PUBLIC_VISIBILITY 369 cc_label.comment = sources_label.comment 370 371 java_label = BazelLabel(name + '_java_proto', 'perfetto_java_proto_library') 372 java_label.deps = [':' + sources_label.name] 373 java_label.visibility = PUBLIC_VISIBILITY 374 java_label.comment = sources_label.comment 375 376 lite_name = name + '_java_proto_lite' 377 java_lite_label = BazelLabel(lite_name, 'perfetto_java_lite_proto_library') 378 java_lite_label.deps = [':' + sources_label.name] 379 java_lite_label.visibility = PUBLIC_VISIBILITY 380 java_lite_label.comment = sources_label.comment 381 382 py_label = BazelLabel(name + '_py_pb2', 'perfetto_py_proto_library') 383 py_label.deps = [':' + sources_label.name] 384 py_label.visibility = PUBLIC_VISIBILITY 385 py_label.comment = sources_label.comment 386 387 return [sources_label, cc_label, java_label, java_lite_label, py_label] 388 389 390def gen_target(gn_target): 391 if gn_target.type == 'proto_library': 392 return [gen_proto_label(gn_target)] 393 elif gn_target.type == 'action': 394 if gn_target.name in custom_actions: 395 return custom_actions[gn_target.name](gn_target) 396 elif re.match('.*gen_cc_.*_descriptor$', gn_target.name): 397 return gen_cc_metrics_descriptor(gn_target) 398 return [] 399 elif gn_target.type == 'group': 400 return [] 401 elif gn_target.type == 'executable': 402 bazel_type = 'perfetto_cc_binary' 403 elif gn_target.type == 'shared_library': 404 bazel_type = 'perfetto_cc_binary' 405 vars['linkshared'] = True 406 elif gn_target.type == 'static_library': 407 bazel_type = 'perfetto_cc_library' 408 elif gn_target.type == 'source_set': 409 bazel_type = 'perfetto_filegroup' 410 else: 411 raise Error('target type not supported: %s' % gn_target.type) 412 413 label = BazelLabel(get_bazel_label_name(gn_target.name), bazel_type) 414 label.comment = gn_target.name 415 416 # Supporting 'public' on source_sets would require not converting them to 417 # filegroups in bazel. 418 if gn_target.public_headers: 419 if bazel_type == 'perfetto_cc_library': 420 label.hdrs += [x[2:] for x in gn_target.public_headers] 421 else: 422 raise Error('%s: \'public\' currently supported only for cc_library' % 423 gn_target.name) 424 425 raw_srcs = [x[2:] for x in gn_target.sources] 426 if bazel_type == 'perfetto_cc_library': 427 label.srcs += [x for x in raw_srcs if not x.startswith('include')] 428 label.hdrs += [x for x in raw_srcs if x.startswith('include')] 429 430 # Most Perfetto libraries cannot by dynamically linked as they would 431 # cause ODR violations. 432 label.__dict__['linkstatic'] = True 433 else: 434 label.srcs = raw_srcs 435 436 if gn_target.name in public_targets: 437 label.visibility = ['//visibility:public'] 438 439 if gn_target.type in gn_utils.LINKER_UNIT_TYPES: 440 # |source_sets| contains the transitive set of source_set deps. 441 for trans_dep in gn_target.source_set_deps: 442 name = ':' + get_bazel_label_name(trans_dep) 443 if name.startswith( 444 ':include_perfetto_') and gn_target.type != 'executable': 445 label.hdrs += [name] 446 else: 447 label.srcs += [name] 448 for dep in sorted(gn_target.deps): 449 if dep.startswith('//gn:'): 450 assert (dep in external_deps), dep 451 if dep in external_deps: 452 assert (isinstance(external_deps[dep], list)) 453 label.external_deps += external_deps[dep] 454 else: 455 label.deps += [':' + get_bazel_label_name(dep)] 456 label.deps += [ 457 ':' + get_bazel_label_name(x) for x in gn_target.transitive_proto_deps 458 ] 459 460 # All items starting with : need to be sorted to the end of the list. 461 # However, Python makes specifying a comparator function hard so cheat 462 # instead and make everything start with : sort as if it started with | 463 # As | > all other normal ASCII characters, this will lead to all : targets 464 # starting with : to be sorted to the end. 465 label.srcs = sorted(label.srcs, key=lambda x: x.replace(':', '|')) 466 467 label.deps = sorted(label.deps) 468 label.hdrs = sorted(label.hdrs) 469 return [label] 470 471 472def gen_target_str(gn_target): 473 return ''.join(str(x) for x in gen_target(gn_target)) 474 475 476def generate_build(gn_desc, targets, extras): 477 gn = gn_utils.GnParser(gn_desc) 478 project_root = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 479 tool_name = os.path.relpath(os.path.abspath(__file__), project_root) 480 res = ''' 481# Copyright (C) 2019 The Android Open Source Project 482# 483# Licensed under the Apache License, Version 2.0 (the "License"); 484# you may not use this file except in compliance with the License. 485# You may obtain a copy of the License at 486# 487# http://www.apache.org/licenses/LICENSE-2.0 488# 489# Unless required by applicable law or agreed to in writing, software 490# distributed under the License is distributed on an "AS IS" BASIS, 491# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 492# See the License for the specific language governing permissions and 493# limitations under the License. 494# 495# This file is automatically generated by {}. Do not edit. 496 497load("@perfetto_cfg//:perfetto_cfg.bzl", "PERFETTO_CONFIG") 498load( 499 "@perfetto//bazel:rules.bzl", 500 "perfetto_build_config_cc_library", 501 "perfetto_cc_binary", 502 "perfetto_filegroup", 503 "perfetto_genrule", 504 "perfetto_cc_ipc_library", 505 "perfetto_cc_library", 506 "perfetto_cc_proto_descriptor", 507 "perfetto_cc_proto_library", 508 "perfetto_cc_protocpp_library", 509 "perfetto_cc_protozero_library", 510 "perfetto_java_proto_library", 511 "perfetto_java_lite_proto_library", 512 "perfetto_proto_library", 513 "perfetto_proto_descriptor", 514 "perfetto_py_binary", 515 "perfetto_py_library", 516 "perfetto_py_proto_library", 517 "perfetto_gensignature_internal_only", 518) 519 520package(default_visibility = ["//visibility:private"]) 521 522licenses(["notice"]) 523 524exports_files(["NOTICE"]) 525 526'''.format(tool_name).lstrip() 527 528 # Public targets need to be computed at the beginning (to figure out the 529 # intermediate deps) but printed at the end (because declaration order matters 530 # in Bazel). 531 public_str = '' 532 for target_name in sorted(public_targets): 533 target = gn.get_target(target_name) 534 public_str += gen_target_str(target) 535 536 res += ''' 537# ############################################################################## 538# Internal targets 539# ############################################################################## 540 541'''.lstrip() 542 # Generate the other non-public targets. 543 for target_name in sorted(set(default_targets) - set(public_targets)): 544 target = gn.get_target(target_name) 545 res += gen_target_str(target) 546 547 # Generate all the intermediate targets. 548 for target in sorted(itervalues(gn.all_targets)): 549 if target.name in default_targets or target.name in gn.proto_libs: 550 continue 551 res += gen_target_str(target) 552 553 res += ''' 554# ############################################################################## 555# Proto libraries 556# ############################################################################## 557 558'''.lstrip() 559 # Generate targets for proto groups. 560 for l_name, t_names in proto_groups.items(): 561 res += ''.join(str(x) for x in gen_proto_group_target(gn, l_name, t_names)) 562 563 # For any non-source set and non-descriptor targets, ensure the source set 564 # associated to that target is discovered. 565 for target in sorted(itervalues(gn.all_targets)): 566 plugin = target.proto_plugin 567 if plugin is None or plugin == 'source_set' or plugin == 'descriptor': 568 continue 569 gn.get_target(re.sub('(lite|zero|cpp|ipc)$', 'source_set', target.name)) 570 571 # Generate targets for the transitive set of proto targets. 572 labels = [ 573 l for target in sorted(itervalues(gn.proto_libs)) 574 for l in gen_target(target) 575 ] 576 res += ''.join(str(x) for x in sorted(labels)) 577 578 res += ''' 579# ############################################################################## 580# Public targets 581# ############################################################################## 582 583'''.lstrip() 584 res += public_str 585 res += '# Content from BUILD.extras\n\n' 586 res += extras 587 588 # Check for ODR violations 589 for target_name in default_targets: 590 checker = gn_utils.ODRChecker(gn, target_name) 591 592 return res 593 594 595def main(): 596 parser = argparse.ArgumentParser( 597 description='Generate BUILD from a GN description.') 598 parser.add_argument( 599 '--check-only', 600 help='Don\'t keep the generated files', 601 action='store_true') 602 parser.add_argument( 603 '--desc', 604 help='GN description ' + 605 '(e.g., gn desc out --format=json --all-toolchains "//*"') 606 parser.add_argument( 607 '--repo-root', 608 help='Standalone Perfetto repository to generate a GN description', 609 default=gn_utils.repo_root(), 610 ) 611 parser.add_argument( 612 '--extras', 613 help='Extra targets to include at the end of the BUILD file', 614 default=os.path.join(gn_utils.repo_root(), 'BUILD.extras'), 615 ) 616 parser.add_argument( 617 '--output', 618 help='BUILD file to create', 619 default=os.path.join(gn_utils.repo_root(), 'BUILD'), 620 ) 621 parser.add_argument( 622 '--output-proto', 623 help='Proto BUILD file to create', 624 default=os.path.join(gn_utils.repo_root(), 'protos', 'BUILD'), 625 ) 626 parser.add_argument( 627 'targets', 628 nargs=argparse.REMAINDER, 629 help='Targets to include in the BUILD file (e.g., "//:perfetto_tests")') 630 args = parser.parse_args() 631 632 if args.desc: 633 with open(args.desc) as f: 634 desc = json.load(f) 635 else: 636 desc = gn_utils.create_build_description(gn_args, args.repo_root) 637 638 out_files = [] 639 640 # Generate the main BUILD file. 641 with open(args.extras, 'r') as extra_f: 642 extras = extra_f.read() 643 644 contents = generate_build(desc, args.targets or default_targets, extras) 645 out_files.append(args.output + '.swp') 646 with open(out_files[-1], 'w') as out_f: 647 out_f.write(contents) 648 649 # Generate the build flags file. 650 out_files.append(os.path.join(buildflags_dir, 'perfetto_build_flags.h.swp')) 651 gn_utils.gen_buildflags(gn_args, out_files[-1]) 652 653 return gn_utils.check_or_commit_generated_files(out_files, args.check_only) 654 655 656if __name__ == '__main__': 657 sys.exit(main()) 658