pebble/tools/generate_native_sdk/extract_symbol_info.py
2025-01-27 11:38:16 -08:00

97 lines
4.1 KiB
Python

# Copyright 2024 Google LLC
#
# 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.
import functools
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '../'))
import parse_c_decl
from parse_c_decl import clang
def extract_exported_functions(node, functions=[], types=[], defines=[]):
def update_matching_export(exports, node):
spelling = parse_c_decl.get_node_spelling(node)
for e in exports:
impl_name = e.impl_name if hasattr(e, 'impl_name') else ""
definition_name = impl_name if impl_name else e.name
if spelling == definition_name:
# Found a matching node! Before we update our export make sure this attribute is larger
# than the one we may already have. This is to handle the case where we have typedef and
# a struct as part of the same definition, we want to make sure we get the outer typedef.
definition = parse_c_decl.get_string_from_file(node.extent)
if e.full_definition is None or len(definition) > len(e.full_definition):
if node.kind == clang.cindex.CursorKind.MACRO_DEFINITION:
e.full_definition = "#define " + definition
else:
e.full_definition = definition
# Update the exports with comments / definition info from both the
# 'implName' and 'name'. Keep whatever is longer and does not start
# with @internal (meaning the whole docstring is internal).
if spelling == e.name or (impl_name and spelling == impl_name):
comment = parse_c_decl.get_comment_string_for_decl(node)
if comment is not None and not comment.startswith("//! @internal"):
if e.comment is None or len(comment) > len(e.comment):
e.comment = comment
return None
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
update_matching_export(functions, node)
elif node.kind == clang.cindex.CursorKind.STRUCT_DECL or \
node.kind == clang.cindex.CursorKind.ENUM_DECL or \
node.kind == clang.cindex.CursorKind.TYPEDEF_DECL:
update_matching_export(types, node)
elif node.kind == clang.cindex.CursorKind.MACRO_DEFINITION:
update_matching_export(defines, node)
def extract_symbol_info(filenames, functions, types, defines, output_dir, internal_sdk_build=False,
compiler_flags=None):
# Parse all the headers at the same time since that is much faster than
# parsing each one individually
all_headers_file = os.path.join(output_dir, "all_sdk_headers.h")
with open(all_headers_file, 'w') as outfile:
for f in filenames:
outfile.write('#include "%s"\n' % f)
parse_c_decl.parse_file(all_headers_file, filenames,
functools.partial(extract_exported_functions,
functions=functions,
types=types,
defines=defines),
internal_sdk_build=internal_sdk_build,
compiler_flags=compiler_flags)
if __name__ == '__main__':
parse_c_decl.dump_tree = True
class Export(object):
def __init__(self, name):
self.name = name
self.full_definition = None
self.comment = None
#clang.cindex.Config.library_file = "/home/brad/src/llvmbuild/Debug+Asserts/lib/libclang.so"
extract_symbol_info((sys.argv[1],), [], [], [])