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 marked as ICU stable, it generates a wrapper function to be 21called by NDK, 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 34 35import jinja2 36 37from genutil import ( 38 android_path, 39 DeclaredFunctionsParser, 40 StableDeclarationFilter, 41 WhitelistedDeclarationFilter, 42 KNOWN_VA_FUNCTIONS, 43 WHITELISTED_FUNCTION_NAMES, 44) 45 46THIS_DIR = os.path.dirname(os.path.realpath(__file__)) 47 48JINJA_ENV = jinja2.Environment(loader=jinja2.FileSystemLoader( 49 os.path.join(THIS_DIR, 'jinja_templates'))) 50JINJA_ENV.trim_blocks = True 51JINJA_ENV.lstrip_blocks = True 52 53 54def generate_shim(functions, includes): 55 """Generates the library source file from the given functions.""" 56 data = { 57 'functions': functions, 58 'icu_headers': includes, 59 } 60 return JINJA_ENV.get_template('shim.cpp.j2').render(data) 61 62 63def generate_symbol_txt(shim_functions, extra_function_names): 64 """Generates the symbol txt file from the given functions.""" 65 data = { 66 # Each shim_function is given an _android suffix. 67 'shim_functions' : shim_functions, 68 # Each extra function name is included as given. 69 'extra_function_names': extra_function_names, 70 } 71 return JINJA_ENV.get_template('libandroidicu.map.txt.j2').render(data) 72 73 74def main(): 75 """Parse the ICU4C headers and generate the shim libandroidicu.""" 76 logging.basicConfig(level=logging.DEBUG) 77 78 decl_filters = [StableDeclarationFilter()] 79 whitelisted_filters = [WhitelistedDeclarationFilter(WHITELISTED_FUNCTION_NAMES)] 80 parser = DeclaredFunctionsParser(decl_filters, whitelisted_filters) 81 parser.set_va_functions_mapping(KNOWN_VA_FUNCTIONS) 82 83 parser.parse() 84 85 includes = parser.header_includes 86 functions = parser.declared_functions 87 88 headers_folder = android_path('external/icu/libandroidicu/include/unicode') 89 if os.path.exists(headers_folder): 90 shutil.rmtree(headers_folder) 91 os.mkdir(headers_folder) 92 93 with open(android_path('external/icu/libandroidicu/static_shim/shim.cpp'), 94 'w') as out_file: 95 out_file.write(generate_shim(functions, includes).encode('utf8')) 96 97 with open(android_path('external/icu/libandroidicu/aicu/extra_function_names.txt'), 98 'r') as in_file: 99 extra_function_names = [ 100 line.strip() for line in in_file.readlines() if not line.startswith('#') 101 ] 102 103 with open(android_path('external/icu/libandroidicu/libandroidicu.map.txt'), 104 'w') as out_file: 105 out_file.write(generate_symbol_txt(functions, extra_function_names).encode('utf8')) 106 107 for path in parser.header_paths_to_copy: 108 basename = os.path.basename(path) 109 shutil.copyfile(path, os.path.join(headers_folder, basename)) 110 111 112if __name__ == '__main__': 113 main() 114