1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2024 The Chromium Authors 2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 4*8975f5c5SAndroid Build Coastguard Worker 5*8975f5c5SAndroid Build Coastguard Workerimport argparse 6*8975f5c5SAndroid Build Coastguard Workerimport json 7*8975f5c5SAndroid Build Coastguard Workerimport os 8*8975f5c5SAndroid Build Coastguard Workerimport subprocess 9*8975f5c5SAndroid Build Coastguard Workerimport sys 10*8975f5c5SAndroid Build Coastguard Workerimport shutil 11*8975f5c5SAndroid Build Coastguard Workerimport tempfile 12*8975f5c5SAndroid Build Coastguard Worker 13*8975f5c5SAndroid Build Coastguard WorkerTARGET_CPU_MAPPING = { 14*8975f5c5SAndroid Build Coastguard Worker 'x64': 'x86_64', 15*8975f5c5SAndroid Build Coastguard Worker 'arm64': 'arm64', 16*8975f5c5SAndroid Build Coastguard Worker} 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard WorkerMETADATA_FILES = ('extract.actionsdata', 'version.json') 19*8975f5c5SAndroid Build Coastguard Worker 20*8975f5c5SAndroid Build Coastguard Worker 21*8975f5c5SAndroid Build Coastguard Workerdef read_json(path): 22*8975f5c5SAndroid Build Coastguard Worker """Reads JSON file at `path`.""" 23*8975f5c5SAndroid Build Coastguard Worker with open(path, encoding='utf8') as stream: 24*8975f5c5SAndroid Build Coastguard Worker return json.load(stream) 25*8975f5c5SAndroid Build Coastguard Worker 26*8975f5c5SAndroid Build Coastguard Worker 27*8975f5c5SAndroid Build Coastguard Workerdef add_argument(parser, name, help, required=True): 28*8975f5c5SAndroid Build Coastguard Worker """Add argument --{name} to `parser` with description `help`.""" 29*8975f5c5SAndroid Build Coastguard Worker parser.add_argument(f'--{name}', required=required, help=help) 30*8975f5c5SAndroid Build Coastguard Worker 31*8975f5c5SAndroid Build Coastguard Worker 32*8975f5c5SAndroid Build Coastguard Workerdef extract_metadata(parsed, module_name, swift_files, const_files): 33*8975f5c5SAndroid Build Coastguard Worker """ 34*8975f5c5SAndroid Build Coastguard Worker Extracts metadata for `module_name` according to `parsed`. 35*8975f5c5SAndroid Build Coastguard Worker 36*8975f5c5SAndroid Build Coastguard Worker If the extraction fails or no metadata is generated, terminate the script 37*8975f5c5SAndroid Build Coastguard Worker with an error (after printing the command stdout/stderr to stderr). 38*8975f5c5SAndroid Build Coastguard Worker """ 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Worker metadata_dir = os.path.join(parsed.output, 'Metadata.appintents') 41*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(metadata_dir): 42*8975f5c5SAndroid Build Coastguard Worker shutil.rmtree(metadata_dir) 43*8975f5c5SAndroid Build Coastguard Worker 44*8975f5c5SAndroid Build Coastguard Worker target_cpu = TARGET_CPU_MAPPING[parsed.target_cpu] 45*8975f5c5SAndroid Build Coastguard Worker target_triple = f'{target_cpu}-apple-ios{parsed.deployment_target}' 46*8975f5c5SAndroid Build Coastguard Worker if parsed.target_environment == 'simulator': 47*8975f5c5SAndroid Build Coastguard Worker target_triple += '-simulator' 48*8975f5c5SAndroid Build Coastguard Worker 49*8975f5c5SAndroid Build Coastguard Worker command = [ 50*8975f5c5SAndroid Build Coastguard Worker os.path.join(parsed.toolchain_dir, 'usr/bin/appintentsmetadataprocessor'), 51*8975f5c5SAndroid Build Coastguard Worker '--toolchain-dir', 52*8975f5c5SAndroid Build Coastguard Worker parsed.toolchain_dir, 53*8975f5c5SAndroid Build Coastguard Worker '--sdk-root', 54*8975f5c5SAndroid Build Coastguard Worker parsed.sdk_root, 55*8975f5c5SAndroid Build Coastguard Worker '--deployment-target', 56*8975f5c5SAndroid Build Coastguard Worker parsed.deployment_target, 57*8975f5c5SAndroid Build Coastguard Worker '--target-triple', 58*8975f5c5SAndroid Build Coastguard Worker target_triple, 59*8975f5c5SAndroid Build Coastguard Worker '--module-name', 60*8975f5c5SAndroid Build Coastguard Worker module_name, 61*8975f5c5SAndroid Build Coastguard Worker '--output', 62*8975f5c5SAndroid Build Coastguard Worker parsed.output, 63*8975f5c5SAndroid Build Coastguard Worker '--binary-file', 64*8975f5c5SAndroid Build Coastguard Worker parsed.binary_file, 65*8975f5c5SAndroid Build Coastguard Worker '--compile-time-extraction', 66*8975f5c5SAndroid Build Coastguard Worker ] 67*8975f5c5SAndroid Build Coastguard Worker 68*8975f5c5SAndroid Build Coastguard Worker inputs = set() 69*8975f5c5SAndroid Build Coastguard Worker inputs.add(parsed.binary_file) 70*8975f5c5SAndroid Build Coastguard Worker 71*8975f5c5SAndroid Build Coastguard Worker for swift_file in swift_files: 72*8975f5c5SAndroid Build Coastguard Worker inputs.add(swift_file) 73*8975f5c5SAndroid Build Coastguard Worker command.extend(('--source-files', swift_file)) 74*8975f5c5SAndroid Build Coastguard Worker 75*8975f5c5SAndroid Build Coastguard Worker for const_file in const_files: 76*8975f5c5SAndroid Build Coastguard Worker inputs.add(const_file) 77*8975f5c5SAndroid Build Coastguard Worker command.extend(('--swift-const-vals', const_file)) 78*8975f5c5SAndroid Build Coastguard Worker 79*8975f5c5SAndroid Build Coastguard Worker if parsed.xcode_version is not None: 80*8975f5c5SAndroid Build Coastguard Worker command.extend(('--xcode-version', parsed.xcode_version)) 81*8975f5c5SAndroid Build Coastguard Worker 82*8975f5c5SAndroid Build Coastguard Worker process = subprocess.Popen(command, 83*8975f5c5SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 84*8975f5c5SAndroid Build Coastguard Worker stderr=subprocess.PIPE) 85*8975f5c5SAndroid Build Coastguard Worker (stdout, stderr) = process.communicate() 86*8975f5c5SAndroid Build Coastguard Worker 87*8975f5c5SAndroid Build Coastguard Worker if process.returncode: 88*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write(stdout.decode('utf8')) 89*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write(stderr.decode('utf8')) 90*8975f5c5SAndroid Build Coastguard Worker return process.returncode 91*8975f5c5SAndroid Build Coastguard Worker 92*8975f5c5SAndroid Build Coastguard Worker # Force failure if the tool extracted no data. This is because gn does 93*8975f5c5SAndroid Build Coastguard Worker # not support optional outputs and thus it would consider the build as 94*8975f5c5SAndroid Build Coastguard Worker # dirty if the output is missing. 95*8975f5c5SAndroid Build Coastguard Worker if not os.path.exists(metadata_dir): 96*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write(f'error: no metadata generated for {module_name}\n') 97*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write(stdout.decode('utf8')) 98*8975f5c5SAndroid Build Coastguard Worker sys.stderr.write(stderr.decode('utf8')) 99*8975f5c5SAndroid Build Coastguard Worker return 1 # failure 100*8975f5c5SAndroid Build Coastguard Worker 101*8975f5c5SAndroid Build Coastguard Worker output_files = METADATA_FILES 102*8975f5c5SAndroid Build Coastguard Worker with open(parsed.depfile, 'w', encoding='utf8') as depfile: 103*8975f5c5SAndroid Build Coastguard Worker for output in output_files: 104*8975f5c5SAndroid Build Coastguard Worker depfile.write(f'{metadata_dir}/{output}:') 105*8975f5c5SAndroid Build Coastguard Worker for item in sorted(inputs): 106*8975f5c5SAndroid Build Coastguard Worker depfile.write(f' {item}') 107*8975f5c5SAndroid Build Coastguard Worker depfile.write('\n') 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Worker return 0 # success 110*8975f5c5SAndroid Build Coastguard Worker 111*8975f5c5SAndroid Build Coastguard Worker 112*8975f5c5SAndroid Build Coastguard Workerdef main(args): 113*8975f5c5SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 114*8975f5c5SAndroid Build Coastguard Worker 115*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'output', 'path to the output directory') 116*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'depfile', 'path to the output depfile') 117*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'toolchain-dir', 'path to the toolchain directory') 118*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'sdk-root', 'path to the SDK root directory') 119*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'target-cpu', 'target cpu architecture') 120*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'target-environment', 'target environment') 121*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'deployment-target', 'deployment target version') 122*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'binary-file', 'path to the binary to process') 123*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'module-info-path', 'path to the module info JSON file') 124*8975f5c5SAndroid Build Coastguard Worker add_argument(parser, 'xcode-version', 'version of Xcode', required=False) 125*8975f5c5SAndroid Build Coastguard Worker 126*8975f5c5SAndroid Build Coastguard Worker parsed = parser.parse_args(args) 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Worker module_info = read_json(parsed.module_info_path) 129*8975f5c5SAndroid Build Coastguard Worker return extract_metadata( 130*8975f5c5SAndroid Build Coastguard Worker parsed, # 131*8975f5c5SAndroid Build Coastguard Worker module_info['module_name'], 132*8975f5c5SAndroid Build Coastguard Worker module_info['swift_files'], 133*8975f5c5SAndroid Build Coastguard Worker module_info['const_files']) 134*8975f5c5SAndroid Build Coastguard Worker 135*8975f5c5SAndroid Build Coastguard Worker 136*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 137*8975f5c5SAndroid Build Coastguard Worker sys.exit(main(sys.argv[1:])) 138