1#!/usr/bin/env python 2# 3# Copyright (C) 2018 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"""Generate ICU stable C API wrapper source. 18 19This script parses all the header files specified by the ICU module names. For 20each function in the allowlist, it generates a wrapper function to be 21called by libandroidicu, which in turn calls the available function at runtime. The tool 22relies on libclang to parse header files, which is a component provided by 23Clang. 24 25Reference to ICU4C stable C APIs: 26http://icu-project.org/apiref/icu4c/files.html 27""" 28from __future__ import absolute_import 29from __future__ import print_function 30 31import logging 32import os 33import shutil 34import subprocess 35 36from genutil import ( 37 android_path, 38 generate_shim, 39 generate_symbol_txt, 40 get_allowlisted_apis, 41 DeclaredFunctionsParser, 42 StableDeclarationFilter, 43) 44 45SYMBOL_SUFFIX = '_android' 46 47def copy_header_only_files(): 48 """Copy required header only files""" 49 base_src_path = android_path('external/icu/icu4c/source/') 50 base_dest_path = android_path('external/icu/libandroidicu/include/unicode/') 51 with open(android_path('external/icu/tools/icu4c_srcgen/required_header_only_files.txt'), 52 'r') as in_file: 53 header_only_files = [ 54 base_src_path + line.strip() for line in in_file.readlines() if not line.startswith('#') 55 ] 56 57 for src_path in header_only_files: 58 dest_path = base_dest_path + os.path.basename(src_path) 59 cmd = ['sed', 60 "s/U_SHOW_CPLUSPLUS_API/LIBANDROIDICU_U_SHOW_CPLUSPLUS_API/g", 61 src_path 62 ] 63 64 with open(dest_path, "w") as destfile: 65 subprocess.check_call(cmd, stdout=destfile) 66 67def main(): 68 """Parse the ICU4C headers and generate the shim libandroidicu.""" 69 logging.basicConfig(level=logging.DEBUG) 70 71 decl_filters = [StableDeclarationFilter()] 72 parser = DeclaredFunctionsParser(decl_filters, []) 73 74 parser.parse() 75 76 includes = parser.header_includes 77 functions = parser.declared_functions 78 79 # The shim has the allowlisted functions only 80 allowlisted_apis = get_allowlisted_apis('libandroidicu_allowlisted_api.txt') 81 functions = [f for f in functions if f.name in allowlisted_apis] 82 83 headers_folder = android_path('external/icu/libandroidicu/include/unicode') 84 if os.path.exists(headers_folder): 85 shutil.rmtree(headers_folder) 86 os.mkdir(headers_folder) 87 88 with open(android_path('external/icu/libandroidicu/static_shim/shim.cpp'), 89 'w') as out_file: 90 out_file.write(generate_shim(functions, includes, SYMBOL_SUFFIX, 91 'libandroidicu_shim.cpp.j2') 92 .encode('utf8')) 93 94 with open(android_path('external/icu/libandroidicu/libandroidicu.map.txt'), 95 'w') as out_file: 96 out_file.write(generate_symbol_txt(functions, [], 'libandroidicu.map.txt.j2') 97 .encode('utf8')) 98 99 for path in parser.header_paths_to_copy: 100 basename = os.path.basename(path) 101 shutil.copyfile(path, os.path.join(headers_folder, basename)) 102 103 copy_header_only_files() 104 105if __name__ == '__main__': 106 main() 107