xref: /aosp_15_r20/external/perfetto/tools/gen_tp_table_headers.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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