1#!/usr/bin/env python 2# 3# Copyright 2016 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18# Parses the output of parse_ltp_{make,make_install} and generates a 19# corresponding Android.bp. 20# 21# This process is split into two steps so this second step can later be replaced 22# with an Android.bp generator. 23 24import argparse 25import fileinput 26import json 27import os 28import re 29 30import make_parser 31import make_install_parser 32 33MAKE_DRY_RUN_FILE_NAME = os.path.join('dump', 'make_dry_run.dump') 34MAKE_INSTALL_DRY_RUN_FILE_NAME = os.path.join('dump', 'make_install_dry_run.dump') 35DISABLED_TESTS_FILE_NAME = 'disabled_tests.txt' 36DISABLED_LIBS_FILE_NAME = 'disabled_libs.txt' 37DISABLED_CFLAGS_FILE_NAME = 'disabled_cflags.txt' 38TARGET_LIST = [ 39 { 40 "arch": "arm", 41 "bitness": "64", 42 "extra_test_configs": ["lowmem", "hwasan", "lowmem_hwasan"], 43 "targets": ["arm64"], 44 }, 45 { 46 "arch": "arm", 47 "bitness": "32", 48 "extra_test_configs": ["lowmem"], 49 "targets": ["arm", "arm64"], 50 }, 51 { 52 "arch": "riscv", 53 "bitness": "64", 54 "targets": ["riscv64"], 55 }, 56 { 57 "arch": "x86", 58 "bitness": "64", 59 "targets": ["x86_64"], 60 }, 61 { 62 "arch": "x86", 63 "bitness": "32", 64 "targets": ["x86", "x86_64"], 65 }, 66] 67 68 69class BuildGenerator(object): 70 '''A class to parse make output and convert the result to Android.bp modules. 71 72 Attributes: 73 _bp_result: directory of list of strings for blueprint file keyed by target name 74 _prebuilt_bp_result: directory of list of strings for blueprint keyed by target 75 name 76 _custom_cflags: dict of string (module name) to lists of strings (cflags 77 to add for said module) 78 _unused_custom_cflags: set of strings; tracks the modules with custom 79 cflags that we haven't yet seen 80 _packages: list of strings of packages for package list file 81 ''' 82 83 def __init__(self, custom_cflags): 84 self._bp_result = {} 85 self._prebuilt_bp_result = {} 86 self._custom_cflags = custom_cflags 87 self._unused_custom_cflags = set(custom_cflags) 88 self._packages = [] 89 90 def UniqueKeepOrder(self, sequence): 91 '''Get a copy of list where items are unique and order is preserved. 92 93 Args: 94 sequence: a sequence, can be a list, tuple, or other iterable 95 96 Returns: 97 a list where items copied from input sequence are unique 98 and order is preserved. 99 ''' 100 seen = set() 101 return [x for x in sequence if not (x in seen or seen.add(x))] 102 103 def ReadCommentedText(self, file_path): 104 '''Read pound commented text file into a list of lines. 105 106 Comments or empty lines will be excluded 107 108 Args: 109 file_path: string 110 ''' 111 ret = set() 112 with open(file_path, 'r') as f: 113 lines = [line.strip() for line in f.readlines()] 114 ret = set([s for s in lines if s and not s.startswith('#')]) 115 116 return ret 117 118 def ArTargetToLibraryName(self, ar_target): 119 '''Convert ar target to library name. 120 121 Args: 122 ar_target: string 123 ''' 124 return os.path.basename(ar_target)[len('lib'):-len('.a')] 125 126 def BuildExecutable(self, cc_target, local_src_files, local_cflags, 127 local_c_includes, local_libraries, ltp_libs, 128 ltp_libs_used, ltp_names_used): 129 '''Build a test module. 130 131 Args: 132 cc_target: string 133 local_src_files: list of string 134 local_cflags: list of string 135 local_c_includes: list of string 136 local_libraries: list of string 137 ltp_libs: list of string 138 ltp_libs_used: set of string 139 ltp_names_used: set of string, set of already used cc_target basenames 140 ''' 141 base_name = os.path.basename(cc_target) 142 if base_name in ltp_names_used: 143 print(f'ERROR: base name {base_name} of cc_target {cc_target} already used. Skipping...') 144 return 145 ltp_names_used.add(base_name) 146 147 if cc_target in self._custom_cflags: 148 local_cflags.extend(self._custom_cflags[cc_target]) 149 self._unused_custom_cflags.remove(cc_target) 150 151 # ltp_defaults already adds the include directory 152 local_c_includes = [i for i in local_c_includes if i != 'include'] 153 target_name = f'ltp_{base_name}' 154 target_bp = [] 155 156 self._packages.append(target_name) 157 158 target_bp.append('') 159 target_bp.append('cc_test {') 160 target_bp.append(' name: "%s",' % target_name) 161 target_bp.append(' stem: "%s",' % base_name) 162 target_bp.append(' defaults: ["ltp_test_defaults"],') 163 164 if len(local_src_files) == 1: 165 target_bp.append(' srcs: ["%s"],' % list(local_src_files)[0]) 166 else: 167 target_bp.append(' srcs: [') 168 for src in sorted(local_src_files): 169 target_bp.append(' "%s",' % src) 170 target_bp.append(' ],') 171 172 if len(local_cflags) == 1: 173 target_bp.append(' cflags: ["%s"],' % list(local_cflags)[0]) 174 elif len(local_cflags) > 1: 175 target_bp.append(' cflags: [') 176 for cflag in sorted(local_cflags): 177 target_bp.append(' "%s",' % cflag) 178 target_bp.append(' ],') 179 180 if len(local_c_includes) == 1: 181 target_bp.append(' local_include_dirs: ["%s"],' % list(local_c_includes)[0]) 182 elif len(local_c_includes) > 1: 183 target_bp.append(' local_include_dirs: [') 184 for d in sorted(local_c_includes): 185 target_bp.append(' "%s",' % d) 186 target_bp.append(' ],') 187 188 bionic_builtin_libs = set(['m', 'rt', 'pthread', 'util']) 189 filtered_libs = set(local_libraries).difference(bionic_builtin_libs) 190 191 static_libraries = set(i for i in local_libraries if i in ltp_libs) 192 if len(static_libraries) == 1: 193 target_bp.append(' static_libs: ["libltp_%s"],' % list(static_libraries)[0]) 194 elif len(static_libraries) > 1: 195 target_bp.append(' static_libs: [') 196 for lib in sorted(static_libraries): 197 target_bp.append(' "libltp_%s",' % lib) 198 target_bp.append(' ],') 199 200 for lib in static_libraries: 201 ltp_libs_used.add(lib) 202 203 shared_libraries = set(i for i in filtered_libs if i not in ltp_libs) 204 if len(shared_libraries) == 1: 205 target_bp.append(' shared_libs: ["lib%s"],' % list(shared_libraries)[0]) 206 elif len(shared_libraries) > 1: 207 target_bp.append(' shared_libs: [') 208 for lib in sorted(shared_libraries): 209 target_bp.append(' "lib%s",' % lib) 210 target_bp.append(' ],') 211 212 target_bp.append('}') 213 self._bp_result[target_name] = target_bp 214 215 def BuildStaticLibrary(self, ar_target, local_src_files, local_cflags, 216 local_c_includes): 217 '''Build a library module. 218 219 Args: 220 ar_target: string 221 local_src_files: list of string 222 local_cflags: list of string 223 local_c_includes: list of string 224 ''' 225 target_name = 'libltp_%s' % self.ArTargetToLibraryName(ar_target) 226 target_bp = [] 227 target_bp.append('') 228 target_bp.append('cc_library_static {') 229 target_bp.append(' name: "%s",' % target_name) 230 target_bp.append(' defaults: ["ltp_defaults"],') 231 232 if len(local_c_includes): 233 target_bp.append(' local_include_dirs: [') 234 for d in local_c_includes: 235 target_bp.append(' "%s",' % d) 236 target_bp.append(' ],') 237 238 if len(local_cflags): 239 target_bp.append(' cflags: [') 240 for cflag in local_cflags: 241 target_bp.append(' "%s",' % cflag) 242 target_bp.append(' ],') 243 244 target_bp.append(' srcs: [') 245 for src in local_src_files: 246 target_bp.append(' "%s",' % src) 247 target_bp.append(' ],') 248 249 target_bp.append('}') 250 self._bp_result[target_name] = target_bp 251 252 def BuildShellScript(self, install_target, local_src_file): 253 '''Build a shell script. 254 255 Args: 256 install_target: string 257 local_src_file: string 258 ''' 259 base_name = os.path.basename(install_target) 260 bp_result = [] 261 262 module = 'ltp_%s' % install_target.replace('/', '_') 263 self._packages.append(module) 264 265 module_dir = os.path.dirname(install_target) 266 module_stem = os.path.basename(install_target) 267 268 bp_result.append('') 269 bp_result.append('sh_test {') 270 bp_result.append(' name: "%s",' % module) 271 bp_result.append(' src: "%s",' % local_src_file) 272 bp_result.append(' sub_dir: "vts_ltp_tests/%s",' % module_dir) 273 bp_result.append(' filename: "%s",' % module_stem) 274 bp_result.append(' compile_multilib: "both",') 275 bp_result.append('}') 276 277 self._bp_result[module] = bp_result 278 279 def BuildPrebuiltBp(self, install_target, local_src_file): 280 '''Build a prebuild module for using Android.bp. 281 282 Args: 283 install_target: string 284 local_src_file: string 285 ''' 286 base_name = os.path.basename(install_target) 287 # The original local_src_file is from external/ltp, but for bp the root 288 # will be external/ltp/testcases. 289 src = local_src_file.replace('testcases/', '', 1) 290 module = 'ltp_%s' % install_target.replace('/', '_') 291 module_dir = os.path.dirname(install_target) 292 module_stem = os.path.basename(install_target) 293 294 bp_result = [] 295 bp_result.append('') 296 bp_result.append('sh_test {') 297 bp_result.append(' name: "%s",' % module) 298 bp_result.append(' src: "%s",' % src) 299 bp_result.append(' sub_dir: "vts_ltp_tests/%s",' % module_dir) 300 bp_result.append(' filename: "%s",' % module_stem) 301 bp_result.append(' compile_multilib: "both",') 302 bp_result.append(' auto_gen_config: false,') 303 bp_result.append('}') 304 305 self._prebuilt_bp_result[base_name] = bp_result 306 self._packages.append(module) 307 308 def HandleParsedRule(self, line, rules): 309 '''Prepare parse rules. 310 311 Args: 312 line: string 313 rules: dictionary {string, dictionary} 314 ''' 315 groups = re.match(r'(.*)\[\'(.*)\'\] = \[(.*)\]', line).groups() 316 rule = groups[0] 317 rule_key = groups[1] 318 if groups[2] == '': 319 rule_value = [] 320 else: 321 rule_value = list(i.strip()[1:-1] for i in groups[2].split(',')) 322 323 rule_value = self.UniqueKeepOrder(rule_value) 324 rules.setdefault(rule, {})[rule_key] = rule_value 325 326 def ParseInput(self, input_list, ltp_root): 327 '''Parse a interpreted make output and produce Android.bp module. 328 329 Args: 330 input_list: list of string 331 ''' 332 disabled_tests = self.ReadCommentedText(DISABLED_TESTS_FILE_NAME) 333 disabled_libs = self.ReadCommentedText(DISABLED_LIBS_FILE_NAME) 334 disabled_cflags = self.ReadCommentedText(DISABLED_CFLAGS_FILE_NAME) 335 336 rules = {} 337 for line in input_list: 338 self.HandleParsedRule(line.strip(), rules) 339 340 # .a target -> .o files 341 ar = rules.get('ar', {}) 342 # executable target -> .o files 343 cc_link = rules.get('cc_link', {}) 344 # .o target -> .c file 345 cc_compile = rules.get('cc_compile', {}) 346 # executable target -> .c files 347 cc_compilelink = rules.get('cc_compilelink', {}) 348 # Target name -> CFLAGS passed to gcc 349 cc_flags = rules.get('cc_flags', {}) 350 # Target name -> -I paths passed to gcc 351 cc_includes = rules.get('cc_includes', {}) 352 # Target name -> -l paths passed to gcc 353 cc_libraries = rules.get('cc_libraries', {}) 354 # target -> prebuilt source 355 install = rules.get('install', {}) 356 357 # All libraries used by any LTP test (built or not) 358 ltp_libs = set(self.ArTargetToLibraryName(i) for i in ar.keys()) 359 # All libraries used by the LTP tests we actually build 360 ltp_libs_used = set() 361 ltp_names_used = set() 362 363 # Remove -Wno-error from cflags, we don't want to print warnings. 364 # Silence individual warnings in ltp_defaults or fix them. 365 for target in cc_flags: 366 if '-Wno-error' in cc_flags[target]: 367 cc_flags[target].remove('-Wno-error') 368 369 print( 370 "Disabled lib tests: Test cases listed here are " 371 "suggested to be disabled since they require a disabled library. " 372 "Please copy and paste them into disabled_tests.txt\n") 373 for i in cc_libraries: 374 if len(set(cc_libraries[i]).intersection(disabled_libs)) > 0: 375 if not os.path.basename(i) in disabled_tests: 376 print(os.path.basename(i)) 377 378 print("Disabled_cflag tests: Test cases listed here are " 379 "suggested to be disabled since they require a disabled cflag. " 380 "Please copy and paste them into disabled_tests.txt\n") 381 for i in cc_flags: 382 if len(set(cc_flags[i]).intersection(disabled_cflags)) > 0: 383 module_name = os.path.basename(i) 384 idx = module_name.find('_') 385 if idx > 0: 386 module_name = module_name[:idx] 387 print(module_name) 388 389 # Remove include directories that don't exist. They're an error in 390 # Soong. 391 for target in cc_includes: 392 cc_includes[target] = [i for i in cc_includes[target] if os.path.isdir(os.path.join(ltp_root, i))] 393 394 for target in cc_compilelink: 395 module_name = os.path.basename(target) 396 if module_name in disabled_tests: 397 continue 398 local_src_files = [] 399 src_files = cc_compilelink[target] 400 for i in src_files: 401 # some targets may have a mix of .c and .o files in srcs 402 # find the .c files to build those .o from cc_compile targets 403 if i.endswith('.o'): 404 if i not in cc_compile: 405 raise Exception("Not found: %s when trying to compile target %s" % (i, target)) 406 local_src_files.extend(cc_compile[i]) 407 else: 408 local_src_files.append(i) 409 local_cflags = cc_flags[target] 410 local_c_includes = cc_includes[target] 411 local_libraries = cc_libraries[target] 412 if len(set(local_libraries).intersection(disabled_libs)) > 0: 413 continue 414 if len(set(local_cflags).intersection(disabled_cflags)) > 0: 415 continue 416 self.BuildExecutable(target, local_src_files, local_cflags, 417 local_c_includes, local_libraries, ltp_libs, 418 ltp_libs_used, ltp_names_used) 419 420 for target in cc_link: 421 if os.path.basename(target) in disabled_tests: 422 continue 423 local_src_files = set() 424 local_cflags = set() 425 local_c_includes = set() 426 local_libraries = cc_libraries[target] 427 # Accumulate flags for all .c files needed to build the .o files. 428 # (Android.bp requires a consistent set of flags across a given target. 429 # Thankfully using the superset of all flags in the target works fine 430 # with LTP tests.) 431 for obj in cc_link[target]: 432 for i in cc_compile[obj]: 433 local_src_files.add(i) 434 for i in cc_flags[obj]: 435 local_cflags.add(i) 436 for i in cc_includes[obj]: 437 local_c_includes.add(i) 438 if len(set(local_libraries).intersection(disabled_libs)) > 0: 439 continue 440 if len(set(local_cflags).intersection(disabled_cflags)) > 0: 441 continue 442 443 self.BuildExecutable(target, local_src_files, local_cflags, 444 local_c_includes, local_libraries, ltp_libs, 445 ltp_libs_used, ltp_names_used) 446 447 for target in ar: 448 # Disabled ltp library is already excluded 449 # since it won't be in ltp_libs_used 450 if not self.ArTargetToLibraryName(target) in ltp_libs_used: 451 continue 452 453 local_src_files = set() 454 local_cflags = set() 455 local_c_includes = set() 456 457 # TODO: disabled cflags 458 459 for obj in ar[target]: 460 for i in cc_compile[obj]: 461 local_src_files.add(i) 462 for i in cc_flags[obj]: 463 local_cflags.add(i) 464 for i in cc_includes[obj]: 465 local_c_includes.add(i) 466 467 if len(set(local_cflags).intersection(disabled_cflags)) > 0: 468 continue 469 470 local_src_files = sorted(local_src_files) 471 local_cflags = sorted(local_cflags) 472 local_c_includes = sorted(local_c_includes) 473 474 self.BuildStaticLibrary(target, local_src_files, local_cflags, 475 local_c_includes) 476 477 for target in install: 478 # Check if the absolute path to the prebuilt (relative to LTP_ROOT) 479 # is disabled. This is helpful in case there are duplicates with basename 480 # of the prebuilt. 481 # e.g. 482 # ./ testcases / kernel / fs / fs_bind / move / test01 483 # ./ testcases / kernel / fs / fs_bind / cloneNS / test01 484 # ./ testcases / kernel / fs / fs_bind / regression / test01 485 # ./ testcases / kernel / fs / fs_bind / rbind / test01 486 # ./ testcases / kernel / fs / fs_bind / bind / test01 487 if target in disabled_tests: 488 continue 489 if os.path.basename(target) in disabled_tests: 490 continue 491 local_src_files = install[target] 492 assert len(local_src_files) == 1 493 494 if target.startswith("testcases/bin/"): 495 self.BuildShellScript(target, local_src_files[0]) 496 else: 497 self.BuildPrebuiltBp(target, local_src_files[0]) 498 499 def WriteAndroidBp(self, output_path): 500 '''Write parse result to blueprint file. 501 502 Args: 503 output_path: string 504 ''' 505 with open(output_path, 'a') as f: 506 for k in sorted(self._bp_result.keys()): 507 f.write('\n'.join(self._bp_result[k])) 508 f.write('\n') 509 self._bp_result = {} 510 511 def WritePrebuiltAndroidBp(self, output_path): 512 '''Write parse result to blueprint file. 513 514 Args: 515 output_path: string 516 ''' 517 bp_result = [] 518 bp_result.append('') 519 bp_result.append('package {') 520 bp_result.append(' default_applicable_licenses: ["external_ltp_license"],') 521 bp_result.append('}') 522 for k in sorted(self._prebuilt_bp_result.keys()): 523 bp_result.extend(self._prebuilt_bp_result[k]) 524 self._prebuilt_bp_result = {} 525 with open(output_path, 'a') as f: 526 for k in sorted(self._prebuilt_bp_result.keys()): 527 f.write('\n'.join(self._prebuilt_bp_result[k])) 528 f.write('\n') 529 self._prebuilt_bp_result = {} 530 f.write('\n'.join(bp_result)) 531 f.write('\n') 532 533 def ArchString(self, arch, bitness, lowmem=False, hwasan=False): 534 if bitness == '32': 535 arch_string = arch 536 else: 537 arch_string = f'{arch}_{bitness}' 538 if lowmem: 539 arch_string += '_lowmem' 540 if hwasan: 541 arch_string += '_hwasan' 542 return arch_string 543 544 def BuildConfigGenrule(self, arch, bitness, targets, extra_test_configs=None): 545 extra_test_configs = extra_test_configs if extra_test_configs else [] 546 bp_result = [] 547 arch_string = self.ArchString(arch, bitness) 548 549 bp_result.append('') 550 bp_result.append('genrule {') 551 bp_result.append(' name: "ltp_config_%s",' % arch_string) 552 bp_result.append(' out: ["vts_ltp_test_%s.xml"],' % arch_string) 553 bp_result.append(' tools: ["gen_ltp_config"],') 554 bp_result.append(' cmd: "$(location gen_ltp_config) --arch %s --bitness %s --low-mem %r --hwasan %r $(out)",' % (arch, bitness, lowmem, hwasan)) 555 bp_result.append('}') 556 557 for config in extra_test_configs: 558 lowmem = 'lowmem' in config 559 hwasan = 'hwasan' in config 560 arch_string = self.ArchString(arch, bitness, lowmem, hwasan) 561 562 bp_result.append('') 563 bp_result.append('genrule {') 564 bp_result.append(' name: "ltp_config_%s",' % arch_string) 565 bp_result.append(' out: ["vts_ltp_test_%s.xml"],' % arch_string) 566 bp_result.append(' tools: ["gen_ltp_config"],') 567 bp_result.append(' cmd: "$(location gen_ltp_config) --arch %s --bitness %s --low-mem %r --hwasan %r $(out)",' % (arch, bitness, lowmem, hwasan)) 568 bp_result.append('}') 569 return bp_result 570 571 def BuildPackageList(self): 572 bp_result = [] 573 bp_result.append('') 574 bp_result.append('LTP_TESTS = [') 575 bp_result.append(' ":ltp_runtests",') 576 for package in sorted(self._packages): 577 bp_result.append(' ":%s",' % package) 578 bp_result.append(']') 579 return bp_result 580 581 def BuildLTPTestSuite(self, arch, bitness, targets, extra_test_configs=None): 582 extra_test_configs = extra_test_configs if extra_test_configs else [] 583 bp_result = [] 584 arch_string = self.ArchString(arch, bitness) 585 586 bp_result.append('') 587 bp_result.append('sh_test {') 588 bp_result.append(' name: "vts_ltp_test_%s",' % arch_string) 589 bp_result.append(' src: "empty.sh",') 590 bp_result.append(' test_config: ":ltp_config_%s",' % arch_string) 591 bp_result.append(' test_suites: [') 592 bp_result.append(' "general-tests",') 593 bp_result.append(' "vts",') 594 bp_result.append(' ],') 595 bp_result.append(' enabled: false,') 596 597 if bitness == '32': 598 bp_result.append(' compile_multilib: "32",') 599 600 bp_result.append(' arch: {') 601 for target in targets: 602 bp_result.append(' %s: {' % target) 603 bp_result.append(' enabled: true,') 604 bp_result.append(' },') 605 bp_result.append(' },') 606 607 if extra_test_configs: 608 bp_result.append(' extra_test_configs: [') 609 for config in extra_test_configs: 610 lowmem = 'lowmem' in config 611 hwasan = 'hwasan' in config 612 arch_string = self.ArchString(arch, bitness, lowmem, hwasan) 613 bp_result.append(' ":ltp_config_%s",' % arch_string) 614 bp_result.append(' ],') 615 616 bp_result.append(' data: LTP_TESTS,') 617 bp_result.append('}') 618 return bp_result 619 620 def WriteLtpMainAndroidBp(self, output_path): 621 '''Write the blueprint file of ltp main module. 622 623 Args: 624 output_path: string 625 ''' 626 bp_result = [] 627 bp_result.append('') 628 bp_result.append('package {') 629 bp_result.append(' default_applicable_licenses: ["external_ltp_license"],') 630 bp_result.append('}') 631 632 bp_result.extend(self.BuildPackageList()) 633 634 for target in TARGET_LIST: 635 bp_result.extend(self.BuildConfigGenrule(**target)) 636 637 for target in TARGET_LIST: 638 bp_result.extend(self.BuildLTPTestSuite(**target)) 639 640 with open(output_path, 'a') as f: 641 f.write('\n'.join(bp_result)) 642 f.write('\n') 643 644 def ParseAll(self, ltp_root): 645 '''Parse outputs from both 'make' and 'make install'. 646 647 Args: 648 ltp_root: string 649 ''' 650 parser = make_parser.MakeParser(ltp_root) 651 self.ParseInput(parser.ParseFile(MAKE_DRY_RUN_FILE_NAME), ltp_root) 652 parser = make_install_parser.MakeInstallParser(ltp_root) 653 self.ParseInput(parser.ParseFile(MAKE_INSTALL_DRY_RUN_FILE_NAME), ltp_root) 654 655 def GetUnusedCustomCFlagsTargets(self): 656 '''Get targets that have custom cflags, but that weren't built.''' 657 return list(self._unused_custom_cflags) 658 659 660def main(): 661 parser = argparse.ArgumentParser( 662 description='Generate Android.bp from parsed LTP make output') 663 parser.add_argument( 664 '--ltp_root', dest='ltp_root', required=True, help='LTP root dir') 665 parser.add_argument( 666 '--output_prebuilt_ltp_testcase_bp_path', 667 dest='output_prebuilt_ltp_testcase_bp_path', 668 required=True, 669 help='output prebuilt test case blueprint path') 670 parser.add_argument( 671 '--output_ltp_main_bp_path', 672 dest='output_ltp_main_bp_path', 673 required=True, 674 help='output ltp main blueprint path') 675 parser.add_argument( 676 '--output_bp_path', 677 dest='output_bp_path', 678 required=True, 679 help='output blueprint path') 680 parser.add_argument( 681 '--custom_cflags_file', 682 dest='custom_cflags_file', 683 required=True, 684 help='file with custom per-module cflags. empty means no file.') 685 args = parser.parse_args() 686 687 custom_cflags = {} 688 if args.custom_cflags_file: 689 # The file is expected to just be a JSON map of string -> [string], e.g. 690 # {"testcases/kernel/syscalls/getcwd/getcwd02": ["-DFOO", "-O3"]} 691 with open(args.custom_cflags_file) as f: 692 custom_cflags = json.load(f) 693 694 generator = BuildGenerator(custom_cflags) 695 generator.ParseAll(args.ltp_root) 696 generator.WritePrebuiltAndroidBp(args.output_prebuilt_ltp_testcase_bp_path) 697 generator.WriteLtpMainAndroidBp(args.output_ltp_main_bp_path) 698 generator.WriteAndroidBp(args.output_bp_path) 699 700 unused_cflags_targs = generator.GetUnusedCustomCFlagsTargets() 701 if unused_cflags_targs: 702 print('NOTE: Tests had custom cflags, but were never seen: {}'.format( 703 ', '.join(unused_cflags_targs))) 704 705 print('Finished!') 706 707 708if __name__ == '__main__': 709 main() 710