1*333d2b36SAndroid Build Coastguard Worker#!/usr/bin/env python 2*333d2b36SAndroid Build Coastguard Worker# 3*333d2b36SAndroid Build Coastguard Worker# Copyright (C) 2016 The Android Open Source Project 4*333d2b36SAndroid Build Coastguard Worker# 5*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*333d2b36SAndroid Build Coastguard Worker# 9*333d2b36SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*333d2b36SAndroid Build Coastguard Worker# 11*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*333d2b36SAndroid Build Coastguard Worker# limitations under the License. 16*333d2b36SAndroid Build Coastguard Worker# 17*333d2b36SAndroid Build Coastguard Worker"""Generates source for stub shared libraries for the NDK.""" 18*333d2b36SAndroid Build Coastguard Workerimport argparse 19*333d2b36SAndroid Build Coastguard Workerimport json 20*333d2b36SAndroid Build Coastguard Workerimport logging 21*333d2b36SAndroid Build Coastguard Workerfrom pathlib import Path 22*333d2b36SAndroid Build Coastguard Workerimport sys 23*333d2b36SAndroid Build Coastguard Workerfrom typing import Iterable, TextIO 24*333d2b36SAndroid Build Coastguard Worker 25*333d2b36SAndroid Build Coastguard Workerimport symbolfile 26*333d2b36SAndroid Build Coastguard Workerfrom symbolfile import Arch, Version 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Workerclass Generator: 30*333d2b36SAndroid Build Coastguard Worker """Output generator that writes stub source files and version scripts.""" 31*333d2b36SAndroid Build Coastguard Worker def __init__(self, src_file: TextIO, version_script: TextIO, 32*333d2b36SAndroid Build Coastguard Worker symbol_list: TextIO, filt: symbolfile.Filter) -> None: 33*333d2b36SAndroid Build Coastguard Worker self.src_file = src_file 34*333d2b36SAndroid Build Coastguard Worker self.version_script = version_script 35*333d2b36SAndroid Build Coastguard Worker self.symbol_list = symbol_list 36*333d2b36SAndroid Build Coastguard Worker self.filter = filt 37*333d2b36SAndroid Build Coastguard Worker self.api = filt.api 38*333d2b36SAndroid Build Coastguard Worker 39*333d2b36SAndroid Build Coastguard Worker def write(self, versions: Iterable[Version]) -> None: 40*333d2b36SAndroid Build Coastguard Worker """Writes all symbol data to the output files.""" 41*333d2b36SAndroid Build Coastguard Worker self.symbol_list.write('[abi_symbol_list]\n') 42*333d2b36SAndroid Build Coastguard Worker for version in versions: 43*333d2b36SAndroid Build Coastguard Worker self.write_version(version) 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Worker def write_version(self, version: Version) -> None: 46*333d2b36SAndroid Build Coastguard Worker """Writes a single version block's data to the output files.""" 47*333d2b36SAndroid Build Coastguard Worker if self.filter.should_omit_version(version): 48*333d2b36SAndroid Build Coastguard Worker return 49*333d2b36SAndroid Build Coastguard Worker 50*333d2b36SAndroid Build Coastguard Worker section_versioned = symbolfile.symbol_versioned_in_api( 51*333d2b36SAndroid Build Coastguard Worker version.tags, self.api) 52*333d2b36SAndroid Build Coastguard Worker version_empty = True 53*333d2b36SAndroid Build Coastguard Worker pruned_symbols = [] 54*333d2b36SAndroid Build Coastguard Worker for symbol in version.symbols: 55*333d2b36SAndroid Build Coastguard Worker if self.filter.should_omit_symbol(symbol): 56*333d2b36SAndroid Build Coastguard Worker continue 57*333d2b36SAndroid Build Coastguard Worker 58*333d2b36SAndroid Build Coastguard Worker if symbolfile.symbol_versioned_in_api(symbol.tags, self.api): 59*333d2b36SAndroid Build Coastguard Worker version_empty = False 60*333d2b36SAndroid Build Coastguard Worker pruned_symbols.append(symbol) 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Worker if len(pruned_symbols) > 0: 63*333d2b36SAndroid Build Coastguard Worker if not version_empty and section_versioned: 64*333d2b36SAndroid Build Coastguard Worker self.version_script.write(version.name + ' {\n') 65*333d2b36SAndroid Build Coastguard Worker self.version_script.write(' global:\n') 66*333d2b36SAndroid Build Coastguard Worker for symbol in pruned_symbols: 67*333d2b36SAndroid Build Coastguard Worker emit_version = symbolfile.symbol_versioned_in_api( 68*333d2b36SAndroid Build Coastguard Worker symbol.tags, self.api) 69*333d2b36SAndroid Build Coastguard Worker if section_versioned and emit_version: 70*333d2b36SAndroid Build Coastguard Worker self.version_script.write(' ' + symbol.name + ';\n') 71*333d2b36SAndroid Build Coastguard Worker 72*333d2b36SAndroid Build Coastguard Worker weak = '' 73*333d2b36SAndroid Build Coastguard Worker if 'weak' in symbol.tags: 74*333d2b36SAndroid Build Coastguard Worker weak = '__attribute__((weak)) ' 75*333d2b36SAndroid Build Coastguard Worker 76*333d2b36SAndroid Build Coastguard Worker if 'var' in symbol.tags: 77*333d2b36SAndroid Build Coastguard Worker self.src_file.write(f'{weak}int {symbol.name} = 0;\n') 78*333d2b36SAndroid Build Coastguard Worker else: 79*333d2b36SAndroid Build Coastguard Worker self.src_file.write(f'{weak}void {symbol.name}() {{}}\n') 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Worker self.symbol_list.write(f'{symbol.name}\n') 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Worker if not version_empty and section_versioned: 84*333d2b36SAndroid Build Coastguard Worker base = '' if version.base is None else ' ' + version.base 85*333d2b36SAndroid Build Coastguard Worker self.version_script.write('}' + base + ';\n') 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Workerdef parse_args() -> argparse.Namespace: 89*333d2b36SAndroid Build Coastguard Worker """Parses and returns command line arguments.""" 90*333d2b36SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 91*333d2b36SAndroid Build Coastguard Worker 92*333d2b36SAndroid Build Coastguard Worker def resolved_path(raw: str) -> Path: 93*333d2b36SAndroid Build Coastguard Worker """Returns a resolved Path for the given string.""" 94*333d2b36SAndroid Build Coastguard Worker return Path(raw).resolve() 95*333d2b36SAndroid Build Coastguard Worker 96*333d2b36SAndroid Build Coastguard Worker parser.add_argument('-v', '--verbose', action='count', default=0) 97*333d2b36SAndroid Build Coastguard Worker 98*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 99*333d2b36SAndroid Build Coastguard Worker '--api', required=True, help='API level being targeted.') 100*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 101*333d2b36SAndroid Build Coastguard Worker '--arch', choices=symbolfile.ALL_ARCHITECTURES, required=True, 102*333d2b36SAndroid Build Coastguard Worker help='Architecture being targeted.') 103*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 104*333d2b36SAndroid Build Coastguard Worker '--llndk', action='store_true', help='Use the LLNDK variant.') 105*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 106*333d2b36SAndroid Build Coastguard Worker '--apex', 107*333d2b36SAndroid Build Coastguard Worker action='store_true', 108*333d2b36SAndroid Build Coastguard Worker help='Use the APEX variant.') 109*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 110*333d2b36SAndroid Build Coastguard Worker '--systemapi', 111*333d2b36SAndroid Build Coastguard Worker action='store_true', 112*333d2b36SAndroid Build Coastguard Worker dest='systemapi', 113*333d2b36SAndroid Build Coastguard Worker help='Use the SystemAPI variant.') 114*333d2b36SAndroid Build Coastguard Worker parser.add_argument( 115*333d2b36SAndroid Build Coastguard Worker '--no-ndk', 116*333d2b36SAndroid Build Coastguard Worker action='store_false', 117*333d2b36SAndroid Build Coastguard Worker dest='ndk', 118*333d2b36SAndroid Build Coastguard Worker help='Do not include NDK APIs.') 119*333d2b36SAndroid Build Coastguard Worker 120*333d2b36SAndroid Build Coastguard Worker parser.add_argument('--api-map', 121*333d2b36SAndroid Build Coastguard Worker type=resolved_path, 122*333d2b36SAndroid Build Coastguard Worker required=True, 123*333d2b36SAndroid Build Coastguard Worker help='Path to the API level map JSON file.') 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Worker parser.add_argument('symbol_file', 126*333d2b36SAndroid Build Coastguard Worker type=resolved_path, 127*333d2b36SAndroid Build Coastguard Worker help='Path to symbol file.') 128*333d2b36SAndroid Build Coastguard Worker parser.add_argument('stub_src', 129*333d2b36SAndroid Build Coastguard Worker type=resolved_path, 130*333d2b36SAndroid Build Coastguard Worker help='Path to output stub source file.') 131*333d2b36SAndroid Build Coastguard Worker parser.add_argument('version_script', 132*333d2b36SAndroid Build Coastguard Worker type=resolved_path, 133*333d2b36SAndroid Build Coastguard Worker help='Path to output version script.') 134*333d2b36SAndroid Build Coastguard Worker parser.add_argument('symbol_list', 135*333d2b36SAndroid Build Coastguard Worker type=resolved_path, 136*333d2b36SAndroid Build Coastguard Worker help='Path to output abigail symbol list.') 137*333d2b36SAndroid Build Coastguard Worker 138*333d2b36SAndroid Build Coastguard Worker return parser.parse_args() 139*333d2b36SAndroid Build Coastguard Worker 140*333d2b36SAndroid Build Coastguard Worker 141*333d2b36SAndroid Build Coastguard Workerdef main() -> None: 142*333d2b36SAndroid Build Coastguard Worker """Program entry point.""" 143*333d2b36SAndroid Build Coastguard Worker args = parse_args() 144*333d2b36SAndroid Build Coastguard Worker 145*333d2b36SAndroid Build Coastguard Worker with args.api_map.open() as map_file: 146*333d2b36SAndroid Build Coastguard Worker api_map = json.load(map_file) 147*333d2b36SAndroid Build Coastguard Worker api = symbolfile.decode_api_level(args.api, api_map) 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Worker verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG) 150*333d2b36SAndroid Build Coastguard Worker verbosity = args.verbose 151*333d2b36SAndroid Build Coastguard Worker if verbosity > 2: 152*333d2b36SAndroid Build Coastguard Worker verbosity = 2 153*333d2b36SAndroid Build Coastguard Worker logging.basicConfig(level=verbose_map[verbosity]) 154*333d2b36SAndroid Build Coastguard Worker 155*333d2b36SAndroid Build Coastguard Worker filt = symbolfile.Filter(args.arch, api, args.llndk, args.apex, args.systemapi, args.ndk) 156*333d2b36SAndroid Build Coastguard Worker with args.symbol_file.open() as symbol_file: 157*333d2b36SAndroid Build Coastguard Worker try: 158*333d2b36SAndroid Build Coastguard Worker versions = symbolfile.SymbolFileParser(symbol_file, api_map, filt).parse() 159*333d2b36SAndroid Build Coastguard Worker except symbolfile.MultiplyDefinedSymbolError as ex: 160*333d2b36SAndroid Build Coastguard Worker sys.exit(f'{args.symbol_file}: error: {ex}') 161*333d2b36SAndroid Build Coastguard Worker 162*333d2b36SAndroid Build Coastguard Worker with args.stub_src.open('w') as src_file: 163*333d2b36SAndroid Build Coastguard Worker with args.version_script.open('w') as version_script: 164*333d2b36SAndroid Build Coastguard Worker with args.symbol_list.open('w') as symbol_list: 165*333d2b36SAndroid Build Coastguard Worker generator = Generator(src_file, version_script, symbol_list, 166*333d2b36SAndroid Build Coastguard Worker filt) 167*333d2b36SAndroid Build Coastguard Worker generator.write(versions) 168*333d2b36SAndroid Build Coastguard Worker 169*333d2b36SAndroid Build Coastguard Worker 170*333d2b36SAndroid Build Coastguard Workerif __name__ == '__main__': 171*333d2b36SAndroid Build Coastguard Worker main() 172