#!/usr/bin/env python # # Copyright (C) 2018 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. # """Generate ICU stable C API wrapper source. This script parses all the header files specified by the ICU module names. For each function in the allowlist, it generates a wrapper function to be called by libandroidicu, which in turn calls the available function at runtime. The tool relies on libclang to parse header files, which is a component provided by Clang. Reference to ICU4C stable C APIs: http://icu-project.org/apiref/icu4c/files.html """ from __future__ import absolute_import from __future__ import print_function import logging import os import shutil import subprocess from genutil import ( android_path, generate_shim, generate_symbol_txt, get_allowlisted_apis, DeclaredFunctionsParser, StableDeclarationFilter, ) SYMBOL_SUFFIX = '_android' def copy_header_only_files(): """Copy required header only files""" base_src_path = android_path('external/icu/icu4c/source/') base_dest_path = android_path('external/icu/libandroidicu/include/unicode/') with open(android_path('external/icu/tools/icu4c_srcgen/required_header_only_files.txt'), 'r') as in_file: header_only_files = [ base_src_path + line.strip() for line in in_file.readlines() if not line.startswith('#') ] for src_path in header_only_files: dest_path = base_dest_path + os.path.basename(src_path) cmd = ['sed', "s/U_SHOW_CPLUSPLUS_API/LIBANDROIDICU_U_SHOW_CPLUSPLUS_API/g", src_path ] with open(dest_path, "w") as destfile: subprocess.check_call(cmd, stdout=destfile) def main(): """Parse the ICU4C headers and generate the shim libandroidicu.""" logging.basicConfig(level=logging.DEBUG) decl_filters = [StableDeclarationFilter()] parser = DeclaredFunctionsParser(decl_filters, []) parser.parse() includes = parser.header_includes functions = parser.declared_functions # The shim has the allowlisted functions only allowlisted_apis = get_allowlisted_apis('libandroidicu_allowlisted_api.txt') functions = [f for f in functions if f.name in allowlisted_apis] headers_folder = android_path('external/icu/libandroidicu/include/unicode') if os.path.exists(headers_folder): shutil.rmtree(headers_folder) os.mkdir(headers_folder) with open(android_path('external/icu/libandroidicu/static_shim/shim.cpp'), 'w') as out_file: out_file.write(generate_shim(functions, includes, SYMBOL_SUFFIX, 'libandroidicu_shim.cpp.j2') .encode('utf8')) with open(android_path('external/icu/libandroidicu/libandroidicu.map.txt'), 'w') as out_file: out_file.write(generate_symbol_txt(functions, [], 'libandroidicu.map.txt.j2') .encode('utf8')) for path in parser.header_paths_to_copy: basename = os.path.basename(path) shutil.copyfile(path, os.path.join(headers_folder, basename)) copy_header_only_files() if __name__ == '__main__': main()