blob: 2f4326a9ce7b660d19c82e967e8d594eb1b1ea7f [file] [log] [blame]
Dan Albert06f58af2020-06-22 15:10:31 -07001#!/usr/bin/env python
2#
3# Copyright (C) 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"""Generates source for stub shared libraries for the NDK."""
18import argparse
19import json
20import logging
21import os
22import sys
23
24import symbolfile
25
26
27class Generator:
28 """Output generator that writes stub source files and version scripts."""
29 def __init__(self, src_file, version_script, arch, api, llndk, apex):
30 self.src_file = src_file
31 self.version_script = version_script
32 self.arch = arch
33 self.api = api
34 self.llndk = llndk
35 self.apex = apex
36
37 def write(self, versions):
38 """Writes all symbol data to the output files."""
39 for version in versions:
40 self.write_version(version)
41
42 def write_version(self, version):
43 """Writes a single version block's data to the output files."""
44 if symbolfile.should_omit_version(version, self.arch, self.api,
45 self.llndk, self.apex):
46 return
47
48 section_versioned = symbolfile.symbol_versioned_in_api(
49 version.tags, self.api)
50 version_empty = True
51 pruned_symbols = []
52 for symbol in version.symbols:
53 if symbolfile.should_omit_symbol(symbol, self.arch, self.api,
54 self.llndk, self.apex):
55 continue
56
57 if symbolfile.symbol_versioned_in_api(symbol.tags, self.api):
58 version_empty = False
59 pruned_symbols.append(symbol)
60
61 if len(pruned_symbols) > 0:
62 if not version_empty and section_versioned:
63 self.version_script.write(version.name + ' {\n')
64 self.version_script.write(' global:\n')
65 for symbol in pruned_symbols:
66 emit_version = symbolfile.symbol_versioned_in_api(
67 symbol.tags, self.api)
68 if section_versioned and emit_version:
69 self.version_script.write(' ' + symbol.name + ';\n')
70
71 weak = ''
72 if 'weak' in symbol.tags:
73 weak = '__attribute__((weak)) '
74
75 if 'var' in symbol.tags:
76 self.src_file.write('{}int {} = 0;\n'.format(
77 weak, symbol.name))
78 else:
79 self.src_file.write('{}void {}() {{}}\n'.format(
80 weak, symbol.name))
81
82 if not version_empty and section_versioned:
83 base = '' if version.base is None else ' ' + version.base
84 self.version_script.write('}' + base + ';\n')
85
86
87def parse_args():
88 """Parses and returns command line arguments."""
89 parser = argparse.ArgumentParser()
90
91 parser.add_argument('-v', '--verbose', action='count', default=0)
92
93 parser.add_argument(
94 '--api', required=True, help='API level being targeted.')
95 parser.add_argument(
96 '--arch', choices=symbolfile.ALL_ARCHITECTURES, required=True,
97 help='Architecture being targeted.')
98 parser.add_argument(
99 '--llndk', action='store_true', help='Use the LLNDK variant.')
100 parser.add_argument(
101 '--apex', action='store_true', help='Use the APEX variant.')
102
103 parser.add_argument(
104 '--api-map', type=os.path.realpath, required=True,
105 help='Path to the API level map JSON file.')
106
107 parser.add_argument(
108 'symbol_file', type=os.path.realpath, help='Path to symbol file.')
109 parser.add_argument(
110 'stub_src', type=os.path.realpath,
111 help='Path to output stub source file.')
112 parser.add_argument(
113 'version_script', type=os.path.realpath,
114 help='Path to output version script.')
115
116 return parser.parse_args()
117
118
119def main():
120 """Program entry point."""
121 args = parse_args()
122
123 with open(args.api_map) as map_file:
124 api_map = json.load(map_file)
125 api = symbolfile.decode_api_level(args.api, api_map)
126
127 verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
128 verbosity = args.verbose
129 if verbosity > 2:
130 verbosity = 2
131 logging.basicConfig(level=verbose_map[verbosity])
132
133 with open(args.symbol_file) as symbol_file:
134 try:
135 versions = symbolfile.SymbolFileParser(symbol_file, api_map,
136 args.arch, api, args.llndk,
137 args.apex).parse()
138 except symbolfile.MultiplyDefinedSymbolError as ex:
139 sys.exit('{}: error: {}'.format(args.symbol_file, ex))
140
141 with open(args.stub_src, 'w') as src_file:
142 with open(args.version_script, 'w') as version_file:
143 generator = Generator(src_file, version_file, args.arch, api,
144 args.llndk, args.apex)
145 generator.write(versions)
146
147
148if __name__ == '__main__':
149 main()