Files
build_soong/cc/ndkstubgen/__init__.py
Dan Albert 06f58afd81 Get NDK python script tests running.
Imports weren't working in tests because the package had been created.
The Python "binaries" built by Soong don't seem to take their own
pkg_path into account, so I split the separate pieces of code here out
into their own packages.

Note that the ndk_api_coverage_parser tests do not actually pass
before or after this change (seems like it might be a
non-deterministic ordering issue in the attributes of the generated
output?), but they can at least be run now.

Test: pytest ndkstubgen
Test: pytest symbolfile
Test: pytest ndk_api_coverage_parser
Test: out/host/linux-x86/nativetest64/test_ndkstubgen/test_ndkstubgen
Test: out/host/linux-x86/nativetest64/test_symbolfile/test_symbolfile
Test: out/host/linux-x86/nativetest64/test_ndk_api_coverage_parser/test_ndk_api_coverage_parser
Bug: None
Change-Id: I2ac22f7ced7566e4808070f2f72fd04355846e0b
2020-07-16 13:23:29 -07:00

150 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Generates source for stub shared libraries for the NDK."""
import argparse
import json
import logging
import os
import sys
import symbolfile
class Generator:
"""Output generator that writes stub source files and version scripts."""
def __init__(self, src_file, version_script, arch, api, llndk, apex):
self.src_file = src_file
self.version_script = version_script
self.arch = arch
self.api = api
self.llndk = llndk
self.apex = apex
def write(self, versions):
"""Writes all symbol data to the output files."""
for version in versions:
self.write_version(version)
def write_version(self, version):
"""Writes a single version block's data to the output files."""
if symbolfile.should_omit_version(version, self.arch, self.api,
self.llndk, self.apex):
return
section_versioned = symbolfile.symbol_versioned_in_api(
version.tags, self.api)
version_empty = True
pruned_symbols = []
for symbol in version.symbols:
if symbolfile.should_omit_symbol(symbol, self.arch, self.api,
self.llndk, self.apex):
continue
if symbolfile.symbol_versioned_in_api(symbol.tags, self.api):
version_empty = False
pruned_symbols.append(symbol)
if len(pruned_symbols) > 0:
if not version_empty and section_versioned:
self.version_script.write(version.name + ' {\n')
self.version_script.write(' global:\n')
for symbol in pruned_symbols:
emit_version = symbolfile.symbol_versioned_in_api(
symbol.tags, self.api)
if section_versioned and emit_version:
self.version_script.write(' ' + symbol.name + ';\n')
weak = ''
if 'weak' in symbol.tags:
weak = '__attribute__((weak)) '
if 'var' in symbol.tags:
self.src_file.write('{}int {} = 0;\n'.format(
weak, symbol.name))
else:
self.src_file.write('{}void {}() {{}}\n'.format(
weak, symbol.name))
if not version_empty and section_versioned:
base = '' if version.base is None else ' ' + version.base
self.version_script.write('}' + base + ';\n')
def parse_args():
"""Parses and returns command line arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument(
'--api', required=True, help='API level being targeted.')
parser.add_argument(
'--arch', choices=symbolfile.ALL_ARCHITECTURES, required=True,
help='Architecture being targeted.')
parser.add_argument(
'--llndk', action='store_true', help='Use the LLNDK variant.')
parser.add_argument(
'--apex', action='store_true', help='Use the APEX variant.')
parser.add_argument(
'--api-map', type=os.path.realpath, required=True,
help='Path to the API level map JSON file.')
parser.add_argument(
'symbol_file', type=os.path.realpath, help='Path to symbol file.')
parser.add_argument(
'stub_src', type=os.path.realpath,
help='Path to output stub source file.')
parser.add_argument(
'version_script', type=os.path.realpath,
help='Path to output version script.')
return parser.parse_args()
def main():
"""Program entry point."""
args = parse_args()
with open(args.api_map) as map_file:
api_map = json.load(map_file)
api = symbolfile.decode_api_level(args.api, api_map)
verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
verbosity = args.verbose
if verbosity > 2:
verbosity = 2
logging.basicConfig(level=verbose_map[verbosity])
with open(args.symbol_file) as symbol_file:
try:
versions = symbolfile.SymbolFileParser(symbol_file, api_map,
args.arch, api, args.llndk,
args.apex).parse()
except symbolfile.MultiplyDefinedSymbolError as ex:
sys.exit('{}: error: {}'.format(args.symbol_file, ex))
with open(args.stub_src, 'w') as src_file:
with open(args.version_script, 'w') as version_file:
generator = Generator(src_file, version_file, args.arch, api,
args.llndk, args.apex)
generator.write(versions)
if __name__ == '__main__':
main()