1#!/usr/bin/env python3 2# Copyright (C) 2022 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import argparse 17from dataclasses import dataclass 18import os 19import re 20import sys 21from typing import Dict 22from typing import List 23from typing import Set 24 25# Allow importing of root-relative modules. 26ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 27sys.path.append(os.path.join(ROOT_DIR)) 28 29#pylint: disable=wrong-import-position 30from python.generators.trace_processor_table.serialize import serialize_header 31from python.generators.trace_processor_table.util import find_table_deps 32from python.generators.trace_processor_table.util import ParsedTable 33from python.generators.trace_processor_table.util import parse_tables_from_modules 34#pylint: enable=wrong-import-position 35 36# Suffix which replaces the .py extension for all input modules. 37OUT_HEADER_SUFFIX = '_py.h' 38 39 40@dataclass 41class Header: 42 """Represents a Python module which will be converted to a header.""" 43 tables: List[ParsedTable] 44 45 46def main(): 47 """Main function.""" 48 parser = argparse.ArgumentParser() 49 parser.add_argument('--inputs', required=True, nargs='*') 50 parser.add_argument('--gen-dir', required=True) 51 parser.add_argument('--relative-input-dir') 52 parser.add_argument('--import-prefix', default='') 53 args = parser.parse_args() 54 55 def get_relin_path(in_path: str): 56 if not args.relative_input_dir: 57 return in_path 58 return os.path.relpath(in_path, args.relative_input_dir) 59 60 def get_relout_path(in_path: str): 61 return os.path.splitext(in_path)[0] + OUT_HEADER_SUFFIX 62 63 def get_out_path(in_path: str): 64 return os.path.join(args.gen_dir, get_relout_path(in_path)) 65 66 def get_header_path(in_path: str): 67 return os.path.join(args.import_prefix, get_relout_path(in_path)) 68 69 def get_relin_path_from_module_path(module_path: str): 70 return module_path[module_path.rfind(os.sep + 'src') + 1:] 71 72 modules = [ 73 # On Windows the path can contain '/' or os.sep, depending on how this 74 # script is executed. So we need to replace both. 75 os.path.splitext( 76 get_relin_path(i).replace('/', '.').replace(os.sep, '.'))[0] 77 for i in args.inputs 78 ] 79 headers: Dict[str, Header] = {} 80 for table in parse_tables_from_modules(modules): 81 input_path = get_relin_path_from_module_path(table.table.python_module) 82 header = headers.get(input_path, Header([])) 83 header.tables.append(table) 84 headers[input_path] = header 85 86 for in_path, header in headers.items(): 87 out_path = get_out_path(in_path) 88 relout_path = get_relout_path(in_path) 89 90 # Find all headers depended on by this table. These will be #include-ed when 91 # generating the header file below so ensure we remove ourself. 92 header_relout_deps: Set[str] = set() 93 for table in header.tables: 94 header_relout_deps = header_relout_deps.union([ 95 get_header_path(get_relin_path_from_module_path(c.python_module)) 96 for c in find_table_deps(table.table) 97 ]) 98 header_relout_deps.discard(relout_path) 99 100 with open(out_path, 'w', encoding='utf8') as out: 101 ifdef_guard = re.sub(r'[^a-zA-Z0-9_-]', '_', relout_path).upper() + '_' 102 out.write( 103 serialize_header(ifdef_guard, header.tables, 104 sorted(header_relout_deps))) 105 out.write('\n') 106 107 108if __name__ == '__main__': 109 sys.exit(main()) 110