1*0e209d39SAndroid Build Coastguard Worker#!/usr/bin/env -S python3 -B 2*0e209d39SAndroid Build Coastguard Worker# 3*0e209d39SAndroid Build Coastguard Worker# Copyright (C) 2018 The Android Open Source Project 4*0e209d39SAndroid Build Coastguard Worker# 5*0e209d39SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*0e209d39SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*0e209d39SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*0e209d39SAndroid Build Coastguard Worker# 9*0e209d39SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*0e209d39SAndroid Build Coastguard Worker# 11*0e209d39SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*0e209d39SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*0e209d39SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*0e209d39SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*0e209d39SAndroid Build Coastguard Worker# limitations under the License. 16*0e209d39SAndroid Build Coastguard Worker# 17*0e209d39SAndroid Build Coastguard Worker"""Generate ICU stable C API wrapper source. 18*0e209d39SAndroid Build Coastguard Worker 19*0e209d39SAndroid Build Coastguard Worker 20*0e209d39SAndroid Build Coastguard WorkerThis script parses all the header files specified by the ICU module names. For 21*0e209d39SAndroid Build Coastguard Workereach function in the allowlist, it generates the NDK headers, and shim functions 22*0e209d39SAndroid Build Coastguard Workerto shim.cpp, which in turn calls the real implementation at runtime. 23*0e209d39SAndroid Build Coastguard WorkerThe tool relies on libclang to parse header files. 24*0e209d39SAndroid Build Coastguard Worker 25*0e209d39SAndroid Build Coastguard WorkerReference to ICU4C stable C APIs: 26*0e209d39SAndroid Build Coastguard Workerhttp://icu-project.org/apiref/icu4c/files.html 27*0e209d39SAndroid Build Coastguard Worker""" 28*0e209d39SAndroid Build Coastguard Workerfrom __future__ import absolute_import 29*0e209d39SAndroid Build Coastguard Workerfrom __future__ import print_function 30*0e209d39SAndroid Build Coastguard Worker 31*0e209d39SAndroid Build Coastguard Workerimport logging 32*0e209d39SAndroid Build Coastguard Workerimport os 33*0e209d39SAndroid Build Coastguard Workerimport re 34*0e209d39SAndroid Build Coastguard Workerimport shutil 35*0e209d39SAndroid Build Coastguard Workerimport subprocess 36*0e209d39SAndroid Build Coastguard Workerfrom pathlib import Path 37*0e209d39SAndroid Build Coastguard Workerfrom typing import Dict 38*0e209d39SAndroid Build Coastguard Worker 39*0e209d39SAndroid Build Coastguard Workerfrom genutil import ( 40*0e209d39SAndroid Build Coastguard Worker android_path, 41*0e209d39SAndroid Build Coastguard Worker generate_shim, 42*0e209d39SAndroid Build Coastguard Worker get_jinja_env, 43*0e209d39SAndroid Build Coastguard Worker get_allowlisted_apis, 44*0e209d39SAndroid Build Coastguard Worker AllowlistedDeclarationFilter, 45*0e209d39SAndroid Build Coastguard Worker DeclaredFunctionsParser, 46*0e209d39SAndroid Build Coastguard Worker StableDeclarationFilter, 47*0e209d39SAndroid Build Coastguard Worker THIS_DIR, 48*0e209d39SAndroid Build Coastguard Worker) 49*0e209d39SAndroid Build Coastguard Worker 50*0e209d39SAndroid Build Coastguard Worker# No suffix for ndk shim 51*0e209d39SAndroid Build Coastguard WorkerSYMBOL_SUFFIX = '' 52*0e209d39SAndroid Build Coastguard Worker 53*0e209d39SAndroid Build Coastguard WorkerSECRET_PROCESSING_TOKEN = "@@@SECRET@@@" 54*0e209d39SAndroid Build Coastguard Worker 55*0e209d39SAndroid Build Coastguard WorkerDOC_BLOCK_COMMENT = r"\/\*\*(?:\*(?!\/)|[^*])*\*\/[ ]*\n" 56*0e209d39SAndroid Build Coastguard WorkerTILL_CLOSE_PARENTHESIS = r"[^)^;]*\)" 57*0e209d39SAndroid Build Coastguard WorkerSTABLE_MACRO = r"(?:U_STABLE|U_CAPI)" 58*0e209d39SAndroid Build Coastguard WorkerSTABLE_FUNCTION_DECLARATION = r"^(" + DOC_BLOCK_COMMENT + STABLE_MACRO \ 59*0e209d39SAndroid Build Coastguard Worker + TILL_CLOSE_PARENTHESIS + ");$" 60*0e209d39SAndroid Build Coastguard WorkerNONSTABLE_FUNCTION_DECLARATION = r"^(" + DOC_BLOCK_COMMENT + r"(U_INTERNAL|U_DEPRECATED|U_DRAFT)" \ 61*0e209d39SAndroid Build Coastguard Worker + TILL_CLOSE_PARENTHESIS + ");$" 62*0e209d39SAndroid Build Coastguard Worker 63*0e209d39SAndroid Build Coastguard WorkerREGEX_STABLE_FUNCTION_DECLARATION = re.compile(STABLE_FUNCTION_DECLARATION, re.MULTILINE) 64*0e209d39SAndroid Build Coastguard WorkerREGEX_NONSTABLE_FUNCTION_DECLARATION = re.compile(NONSTABLE_FUNCTION_DECLARATION, re.MULTILINE) 65*0e209d39SAndroid Build Coastguard Worker 66*0e209d39SAndroid Build Coastguard WorkerAPI_LEVEL_MACRO_MAP = { 67*0e209d39SAndroid Build Coastguard Worker '31': '31', 68*0e209d39SAndroid Build Coastguard Worker 'T': '__ANDROID_API_T__', 69*0e209d39SAndroid Build Coastguard Worker} 70*0e209d39SAndroid Build Coastguard Worker 71*0e209d39SAndroid Build Coastguard Workerdef get_allowlisted_regex_string(decl_names): 72*0e209d39SAndroid Build Coastguard Worker """Return a regex in string to capture the C function declarations in the decl_names list""" 73*0e209d39SAndroid Build Coastguard Worker tag = "|".join(decl_names) 74*0e209d39SAndroid Build Coastguard Worker return r"(" + DOC_BLOCK_COMMENT + STABLE_MACRO + r"[^(]*(?=" + tag + r")(" + tag + ")" \ 75*0e209d39SAndroid Build Coastguard Worker + r"\("+ TILL_CLOSE_PARENTHESIS +");$" 76*0e209d39SAndroid Build Coastguard Worker 77*0e209d39SAndroid Build Coastguard Workerdef get_replacement_adding_api_level_macro(api_level: str): 78*0e209d39SAndroid Build Coastguard Worker """Return the replacement string adding the NDK C macro 79*0e209d39SAndroid Build Coastguard Worker guarding C function declaration by the api_level""" 80*0e209d39SAndroid Build Coastguard Worker return r"\1 __INTRODUCED_IN({0});\n\n".format(api_level) 81*0e209d39SAndroid Build Coastguard Worker 82*0e209d39SAndroid Build Coastguard Workerdef modify_func_declarations(src_path: str, dst_path: str, 83*0e209d39SAndroid Build Coastguard Worker exported_decl_api_map: Dict[str, str]): 84*0e209d39SAndroid Build Coastguard Worker """Process the source file, 85*0e209d39SAndroid Build Coastguard Worker remove the C function declarations not in the decl_names, 86*0e209d39SAndroid Build Coastguard Worker add guard the functions listed in decl_names by the API level, 87*0e209d39SAndroid Build Coastguard Worker and output to the dst_path """ 88*0e209d39SAndroid Build Coastguard Worker decl_names = list(exported_decl_api_map.keys()) 89*0e209d39SAndroid Build Coastguard Worker allowlist_regex_string = get_allowlisted_regex_string(decl_names) 90*0e209d39SAndroid Build Coastguard Worker allowlist_decl_regex = re.compile('^' + allowlist_regex_string, re.MULTILINE) 91*0e209d39SAndroid Build Coastguard Worker with open(src_path, "r") as file: 92*0e209d39SAndroid Build Coastguard Worker src = file.read() 93*0e209d39SAndroid Build Coastguard Worker 94*0e209d39SAndroid Build Coastguard Worker # Remove all non-stable function declarations 95*0e209d39SAndroid Build Coastguard Worker modified = REGEX_NONSTABLE_FUNCTION_DECLARATION.sub('', src) 96*0e209d39SAndroid Build Coastguard Worker 97*0e209d39SAndroid Build Coastguard Worker # Insert intermediate token to all functions in the allowlist 98*0e209d39SAndroid Build Coastguard Worker if decl_names: 99*0e209d39SAndroid Build Coastguard Worker modified = allowlist_decl_regex.sub(SECRET_PROCESSING_TOKEN + r"\1;", modified) 100*0e209d39SAndroid Build Coastguard Worker # Remove all other stable declarations not in the allowlist 101*0e209d39SAndroid Build Coastguard Worker modified = REGEX_STABLE_FUNCTION_DECLARATION.sub('', modified) 102*0e209d39SAndroid Build Coastguard Worker 103*0e209d39SAndroid Build Coastguard Worker api_levels = list(set(exported_decl_api_map.values())) 104*0e209d39SAndroid Build Coastguard Worker for api_level in api_levels: 105*0e209d39SAndroid Build Coastguard Worker exported_decl_at_this_level = {key: value for key, value in 106*0e209d39SAndroid Build Coastguard Worker exported_decl_api_map.items() 107*0e209d39SAndroid Build Coastguard Worker if value == api_level } 108*0e209d39SAndroid Build Coastguard Worker 109*0e209d39SAndroid Build Coastguard Worker # Insert C macro and annotation to indicate the API level to each functions 110*0e209d39SAndroid Build Coastguard Worker macro = API_LEVEL_MACRO_MAP[api_level] 111*0e209d39SAndroid Build Coastguard Worker decl_name_regex_string = get_allowlisted_regex_string( 112*0e209d39SAndroid Build Coastguard Worker list(exported_decl_at_this_level.keys())) 113*0e209d39SAndroid Build Coastguard Worker secret_allowlist_decl_regex = re.compile( 114*0e209d39SAndroid Build Coastguard Worker '^' + SECRET_PROCESSING_TOKEN + decl_name_regex_string, 115*0e209d39SAndroid Build Coastguard Worker re.MULTILINE) 116*0e209d39SAndroid Build Coastguard Worker modified = secret_allowlist_decl_regex.sub( 117*0e209d39SAndroid Build Coastguard Worker get_replacement_adding_api_level_macro(macro), modified) 118*0e209d39SAndroid Build Coastguard Worker 119*0e209d39SAndroid Build Coastguard Worker with open(dst_path, "w") as out: 120*0e209d39SAndroid Build Coastguard Worker out.write(modified) 121*0e209d39SAndroid Build Coastguard Worker 122*0e209d39SAndroid Build Coastguard Workerdef remove_ignored_includes(file_path, include_list): 123*0e209d39SAndroid Build Coastguard Worker """ 124*0e209d39SAndroid Build Coastguard Worker Remove the included header, i.e. #include lines, listed in include_list from the file_path 125*0e209d39SAndroid Build Coastguard Worker header. 126*0e209d39SAndroid Build Coastguard Worker """ 127*0e209d39SAndroid Build Coastguard Worker 128*0e209d39SAndroid Build Coastguard Worker # Do nothing if the list is empty 129*0e209d39SAndroid Build Coastguard Worker if not include_list: 130*0e209d39SAndroid Build Coastguard Worker return 131*0e209d39SAndroid Build Coastguard Worker 132*0e209d39SAndroid Build Coastguard Worker tag = "|".join(include_list) 133*0e209d39SAndroid Build Coastguard Worker 134*0e209d39SAndroid Build Coastguard Worker with open(file_path, "r") as file: 135*0e209d39SAndroid Build Coastguard Worker content = file.read() 136*0e209d39SAndroid Build Coastguard Worker 137*0e209d39SAndroid Build Coastguard Worker regex = re.compile(r"^#include \"unicode\/(" + tag + ")\"\n", re.MULTILINE) 138*0e209d39SAndroid Build Coastguard Worker content = regex.sub('', content) 139*0e209d39SAndroid Build Coastguard Worker 140*0e209d39SAndroid Build Coastguard Worker with open(file_path, "w") as out: 141*0e209d39SAndroid Build Coastguard Worker out.write(content) 142*0e209d39SAndroid Build Coastguard Worker 143*0e209d39SAndroid Build Coastguard Workerdef copy_header_only_files(): 144*0e209d39SAndroid Build Coastguard Worker """Copy required header only files""" 145*0e209d39SAndroid Build Coastguard Worker base_src_path = android_path('external/icu/icu4c/source/') 146*0e209d39SAndroid Build Coastguard Worker base_dest_path = android_path('external/icu/libicu/ndk_headers/unicode/') 147*0e209d39SAndroid Build Coastguard Worker with open(android_path('external/icu/tools/icu4c_srcgen/libicu_required_header_only_files.txt'), 148*0e209d39SAndroid Build Coastguard Worker 'r') as in_file: 149*0e209d39SAndroid Build Coastguard Worker header_only_files = [ 150*0e209d39SAndroid Build Coastguard Worker base_src_path + line.strip() for line in in_file.readlines() if not line.startswith('#') 151*0e209d39SAndroid Build Coastguard Worker ] 152*0e209d39SAndroid Build Coastguard Worker 153*0e209d39SAndroid Build Coastguard Worker for src_path in header_only_files: 154*0e209d39SAndroid Build Coastguard Worker dest_path = base_dest_path + os.path.basename(src_path) 155*0e209d39SAndroid Build Coastguard Worker cmd = ['sed', 156*0e209d39SAndroid Build Coastguard Worker "s/U_SHOW_CPLUSPLUS_API/LIBICU_U_SHOW_CPLUSPLUS_API/g", 157*0e209d39SAndroid Build Coastguard Worker src_path 158*0e209d39SAndroid Build Coastguard Worker ] 159*0e209d39SAndroid Build Coastguard Worker 160*0e209d39SAndroid Build Coastguard Worker with open(dest_path, "w") as destfile: 161*0e209d39SAndroid Build Coastguard Worker subprocess.check_call(cmd, stdout=destfile) 162*0e209d39SAndroid Build Coastguard Worker 163*0e209d39SAndroid Build Coastguard Workerdef copy_cts_headers(): 164*0e209d39SAndroid Build Coastguard Worker """Copy headers from common/ and i18n/ to cts_headers/ for compiling cintltst as CTS.""" 165*0e209d39SAndroid Build Coastguard Worker dst_folder = android_path('external/icu/libicu/cts_headers') 166*0e209d39SAndroid Build Coastguard Worker if os.path.exists(dst_folder): 167*0e209d39SAndroid Build Coastguard Worker shutil.rmtree(dst_folder) 168*0e209d39SAndroid Build Coastguard Worker os.mkdir(dst_folder) 169*0e209d39SAndroid Build Coastguard Worker os.mkdir(os.path.join(dst_folder, 'unicode')) 170*0e209d39SAndroid Build Coastguard Worker 171*0e209d39SAndroid Build Coastguard Worker shutil.copyfile(android_path('external/icu/android_icu4c/include/uconfig_local.h'), 172*0e209d39SAndroid Build Coastguard Worker android_path('external/icu/libicu/cts_headers/uconfig_local.h')) 173*0e209d39SAndroid Build Coastguard Worker 174*0e209d39SAndroid Build Coastguard Worker header_subfolders = ( 175*0e209d39SAndroid Build Coastguard Worker 'common', 176*0e209d39SAndroid Build Coastguard Worker 'common/unicode', 177*0e209d39SAndroid Build Coastguard Worker 'i18n', 178*0e209d39SAndroid Build Coastguard Worker 'i18n/unicode', 179*0e209d39SAndroid Build Coastguard Worker ) 180*0e209d39SAndroid Build Coastguard Worker for subfolder in header_subfolders: 181*0e209d39SAndroid Build Coastguard Worker path = android_path('external/icu/icu4c/source', subfolder) 182*0e209d39SAndroid Build Coastguard Worker files = [os.path.join(path, f) for f in os.listdir(path) if f.endswith('.h')] 183*0e209d39SAndroid Build Coastguard Worker 184*0e209d39SAndroid Build Coastguard Worker for src_path in files: 185*0e209d39SAndroid Build Coastguard Worker base_header_name = os.path.basename(src_path) 186*0e209d39SAndroid Build Coastguard Worker dst_path = dst_folder 187*0e209d39SAndroid Build Coastguard Worker if subfolder.endswith('unicode'): 188*0e209d39SAndroid Build Coastguard Worker dst_path = os.path.join(dst_path, 'unicode') 189*0e209d39SAndroid Build Coastguard Worker dst_path = os.path.join(dst_path, base_header_name) 190*0e209d39SAndroid Build Coastguard Worker 191*0e209d39SAndroid Build Coastguard Worker shutil.copyfile(src_path, dst_path) 192*0e209d39SAndroid Build Coastguard Worker 193*0e209d39SAndroid Build Coastguard Workerdef get_rename_macro_regex(decl_names): 194*0e209d39SAndroid Build Coastguard Worker """Return a regex in string to capture the C macro defining the name in the decl_names list""" 195*0e209d39SAndroid Build Coastguard Worker tag = "|".join(decl_names) 196*0e209d39SAndroid Build Coastguard Worker return re.compile(r"^(#define (?:" + tag + r") .*)$", re.MULTILINE) 197*0e209d39SAndroid Build Coastguard Worker 198*0e209d39SAndroid Build Coastguard Workerdef generate_cts_headers(decl_names): 199*0e209d39SAndroid Build Coastguard Worker """Generate headers for compiling cintltst as CTS.""" 200*0e209d39SAndroid Build Coastguard Worker copy_cts_headers() 201*0e209d39SAndroid Build Coastguard Worker 202*0e209d39SAndroid Build Coastguard Worker # Disable all C macro renaming the NDK functions in order to test the functions in the CTS 203*0e209d39SAndroid Build Coastguard Worker urename_path = android_path('external/icu/libicu/cts_headers/unicode/urename.h') 204*0e209d39SAndroid Build Coastguard Worker with open(urename_path, "r") as file: 205*0e209d39SAndroid Build Coastguard Worker src = file.read() 206*0e209d39SAndroid Build Coastguard Worker 207*0e209d39SAndroid Build Coastguard Worker regex = get_rename_macro_regex(decl_names) 208*0e209d39SAndroid Build Coastguard Worker modified = regex.sub(r"// \1", src) 209*0e209d39SAndroid Build Coastguard Worker 210*0e209d39SAndroid Build Coastguard Worker with open(urename_path, "w") as out: 211*0e209d39SAndroid Build Coastguard Worker out.write(modified) 212*0e209d39SAndroid Build Coastguard Worker 213*0e209d39SAndroid Build Coastguard WorkerIGNORED_INCLUDE_DEPENDENCY = { 214*0e209d39SAndroid Build Coastguard Worker "ubrk.h": ["parseerr.h", ], 215*0e209d39SAndroid Build Coastguard Worker "ucol.h": ["uiter.h", "unorm.h", "uset.h", ], 216*0e209d39SAndroid Build Coastguard Worker "ulocdata.h": ["ures.h", "uset.h", ], 217*0e209d39SAndroid Build Coastguard Worker "unorm2.h": ["uset.h", ], 218*0e209d39SAndroid Build Coastguard Worker "ustring.h": ["uiter.h", ], 219*0e209d39SAndroid Build Coastguard Worker "utrans.h": ["uset.h", ], 220*0e209d39SAndroid Build Coastguard Worker} 221*0e209d39SAndroid Build Coastguard Worker 222*0e209d39SAndroid Build Coastguard WorkerIGNORED_HEADER_FOR_DOXYGEN_GROUPING = set([ 223*0e209d39SAndroid Build Coastguard Worker "ubidi.h", # ubidi.h has the @{ ... @} group block already. 224*0e209d39SAndroid Build Coastguard Worker "uconfig.h", # pre-defined config that NDK users shouldn't change 225*0e209d39SAndroid Build Coastguard Worker "platform.h", # pre-defined variable not to be changed by the NDK users 226*0e209d39SAndroid Build Coastguard Worker "utf_old.h", # deprecated UTF macros 227*0e209d39SAndroid Build Coastguard Worker "uvernum.h", # ICU version information not useful for version-independent usage in NDK 228*0e209d39SAndroid Build Coastguard Worker "urename.h" # Renaming symbols, but not used in NDK 229*0e209d39SAndroid Build Coastguard Worker]) 230*0e209d39SAndroid Build Coastguard Worker 231*0e209d39SAndroid Build Coastguard Worker""" 232*0e209d39SAndroid Build Coastguard WorkerThis map should mirror the mapping in external/icu/icu4c/source/Doxyfile.in. 233*0e209d39SAndroid Build Coastguard WorkerThis is needed because NDK doesn't allow per-module Doxyfile, 234*0e209d39SAndroid Build Coastguard Workerapart from the shared frameworks/native/docs/Doxyfile. 235*0e209d39SAndroid Build Coastguard Worker""" 236*0e209d39SAndroid Build Coastguard WorkerDOXYGEN_ALIASES = { 237*0e209d39SAndroid Build Coastguard Worker "@memo": '\\par Note:\n', 238*0e209d39SAndroid Build Coastguard Worker "@draft": '\\xrefitem draft "Draft" "Draft List" This API may be changed in the future versions and was introduced in', 239*0e209d39SAndroid Build Coastguard Worker "@stable": '\\xrefitem stable "Stable" "Stable List"', 240*0e209d39SAndroid Build Coastguard Worker "@deprecated": '\\xrefitem deprecated "Deprecated" "Deprecated List"', 241*0e209d39SAndroid Build Coastguard Worker "@obsolete": '\\xrefitem obsolete "Obsolete" "Obsolete List"', 242*0e209d39SAndroid Build Coastguard Worker "@system": '\\xrefitem system "System" "System List" Do not use unless you know what you are doing.', 243*0e209d39SAndroid Build Coastguard Worker "@internal": '\\xrefitem internal "Internal" "Internal List" Do not use. This API is for internal use only.', 244*0e209d39SAndroid Build Coastguard Worker} 245*0e209d39SAndroid Build Coastguard Worker 246*0e209d39SAndroid Build Coastguard Workerdef add_ndk_required_doxygen_grouping(): 247*0e209d39SAndroid Build Coastguard Worker """Add @addtogroup annotation to the header files for NDK API docs""" 248*0e209d39SAndroid Build Coastguard Worker path = android_path('external/icu/libicu/ndk_headers/unicode') 249*0e209d39SAndroid Build Coastguard Worker files = Path(path).glob("*.h") 250*0e209d39SAndroid Build Coastguard Worker 251*0e209d39SAndroid Build Coastguard Worker for src_path in files: 252*0e209d39SAndroid Build Coastguard Worker header_content = src_path.read_text() 253*0e209d39SAndroid Build Coastguard Worker 254*0e209d39SAndroid Build Coastguard Worker for old, new in DOXYGEN_ALIASES.items(): 255*0e209d39SAndroid Build Coastguard Worker header_content = header_content.replace(old, new) 256*0e209d39SAndroid Build Coastguard Worker 257*0e209d39SAndroid Build Coastguard Worker src_path.write_text(header_content) 258*0e209d39SAndroid Build Coastguard Worker 259*0e209d39SAndroid Build Coastguard Worker if os.path.basename(src_path) in IGNORED_HEADER_FOR_DOXYGEN_GROUPING: 260*0e209d39SAndroid Build Coastguard Worker continue 261*0e209d39SAndroid Build Coastguard Worker 262*0e209d39SAndroid Build Coastguard Worker cmd_add_addtogroup_annotation = ['sed', 263*0e209d39SAndroid Build Coastguard Worker '-i', 264*0e209d39SAndroid Build Coastguard Worker '0,/^\( *\)\(\* *\\\\file\)/s//\\1* @addtogroup icu4c ICU4C\\n\\1* @{\\n\\1\\2/', 265*0e209d39SAndroid Build Coastguard Worker src_path 266*0e209d39SAndroid Build Coastguard Worker ] 267*0e209d39SAndroid Build Coastguard Worker 268*0e209d39SAndroid Build Coastguard Worker subprocess.check_call(cmd_add_addtogroup_annotation) 269*0e209d39SAndroid Build Coastguard Worker 270*0e209d39SAndroid Build Coastguard Worker # Next iteration if the above sed regex doesn't add the text 271*0e209d39SAndroid Build Coastguard Worker if not has_string_in_file(src_path, 'addtogroup'): 272*0e209d39SAndroid Build Coastguard Worker basename = os.path.basename(src_path) 273*0e209d39SAndroid Build Coastguard Worker print(f'Warning: unicode/{basename} has no "\\file" annotation') 274*0e209d39SAndroid Build Coastguard Worker continue 275*0e209d39SAndroid Build Coastguard Worker 276*0e209d39SAndroid Build Coastguard Worker # Add the closing bracket for @addtogroup 277*0e209d39SAndroid Build Coastguard Worker with open(src_path, 'a') as header_file: 278*0e209d39SAndroid Build Coastguard Worker header_file.write('\n/** @} */ // addtogroup\n') 279*0e209d39SAndroid Build Coastguard Worker 280*0e209d39SAndroid Build Coastguard Workerdef has_string_in_file(path, s): 281*0e209d39SAndroid Build Coastguard Worker """Return True if the a string exists in the file""" 282*0e209d39SAndroid Build Coastguard Worker with open(path, 'r') as file: 283*0e209d39SAndroid Build Coastguard Worker return s in file.read() 284*0e209d39SAndroid Build Coastguard Worker 285*0e209d39SAndroid Build Coastguard Workerdef get_exported_symbol_map(export_file : str) -> Dict[str, str]: 286*0e209d39SAndroid Build Coastguard Worker """Return a dictionary mapping from the symbol name to API level in the 287*0e209d39SAndroid Build Coastguard Worker export_file""" 288*0e209d39SAndroid Build Coastguard Worker result_map = {} 289*0e209d39SAndroid Build Coastguard Worker with open(os.path.join(THIS_DIR, export_file), 'r') as file: 290*0e209d39SAndroid Build Coastguard Worker for line in file: 291*0e209d39SAndroid Build Coastguard Worker line = line.strip() 292*0e209d39SAndroid Build Coastguard Worker if line and not line.startswith("#"): 293*0e209d39SAndroid Build Coastguard Worker splits = line.split(',') 294*0e209d39SAndroid Build Coastguard Worker if len(splits) < 2: 295*0e209d39SAndroid Build Coastguard Worker raise ValueError(f'line "{line}" has no , separator') 296*0e209d39SAndroid Build Coastguard Worker result_map[splits[0]] = splits[1] 297*0e209d39SAndroid Build Coastguard Worker 298*0e209d39SAndroid Build Coastguard Worker return result_map 299*0e209d39SAndroid Build Coastguard Worker 300*0e209d39SAndroid Build Coastguard Worker 301*0e209d39SAndroid Build Coastguard Workerdef main(): 302*0e209d39SAndroid Build Coastguard Worker """Parse the ICU4C headers and generate the shim libicu.""" 303*0e209d39SAndroid Build Coastguard Worker logging.basicConfig(level=logging.DEBUG) 304*0e209d39SAndroid Build Coastguard Worker 305*0e209d39SAndroid Build Coastguard Worker exported_symbol_map = get_exported_symbol_map('libicu_export.txt') 306*0e209d39SAndroid Build Coastguard Worker allowlisted_apis = set(exported_symbol_map.keys()) 307*0e209d39SAndroid Build Coastguard Worker decl_filters = [StableDeclarationFilter()] 308*0e209d39SAndroid Build Coastguard Worker decl_filters.append(AllowlistedDeclarationFilter(allowlisted_apis)) 309*0e209d39SAndroid Build Coastguard Worker parser = DeclaredFunctionsParser(decl_filters, []) 310*0e209d39SAndroid Build Coastguard Worker parser.set_ignored_include_dependency(IGNORED_INCLUDE_DEPENDENCY) 311*0e209d39SAndroid Build Coastguard Worker 312*0e209d39SAndroid Build Coastguard Worker parser.parse() 313*0e209d39SAndroid Build Coastguard Worker 314*0e209d39SAndroid Build Coastguard Worker includes = parser.header_includes 315*0e209d39SAndroid Build Coastguard Worker functions = parser.declared_functions 316*0e209d39SAndroid Build Coastguard Worker header_to_function_names = parser.header_to_function_names 317*0e209d39SAndroid Build Coastguard Worker 318*0e209d39SAndroid Build Coastguard Worker # The shim has the allowlisted functions only 319*0e209d39SAndroid Build Coastguard Worker functions = [f for f in functions if f.name in allowlisted_apis] 320*0e209d39SAndroid Build Coastguard Worker 321*0e209d39SAndroid Build Coastguard Worker headers_folder = android_path('external/icu/libicu/ndk_headers/unicode') 322*0e209d39SAndroid Build Coastguard Worker if os.path.exists(headers_folder): 323*0e209d39SAndroid Build Coastguard Worker shutil.rmtree(headers_folder) 324*0e209d39SAndroid Build Coastguard Worker os.mkdir(headers_folder) 325*0e209d39SAndroid Build Coastguard Worker 326*0e209d39SAndroid Build Coastguard Worker with open(android_path('external/icu/libicu/src/shim.cpp'), 327*0e209d39SAndroid Build Coastguard Worker 'w') as out_file: 328*0e209d39SAndroid Build Coastguard Worker out_file.write(generate_shim(functions, includes, SYMBOL_SUFFIX, 'libicu_shim.cpp.j2')) 329*0e209d39SAndroid Build Coastguard Worker 330*0e209d39SAndroid Build Coastguard Worker with open(android_path('external/icu/libicu/libicu.map.txt'), 'w') as out_file: 331*0e209d39SAndroid Build Coastguard Worker data = { 332*0e209d39SAndroid Build Coastguard Worker 'exported_symbol_map' : exported_symbol_map, 333*0e209d39SAndroid Build Coastguard Worker } 334*0e209d39SAndroid Build Coastguard Worker out_file.write(get_jinja_env().get_template('libicu.map.txt.j2').render(data)) 335*0e209d39SAndroid Build Coastguard Worker 336*0e209d39SAndroid Build Coastguard Worker # Process the C headers and put them into the ndk folder. 337*0e209d39SAndroid Build Coastguard Worker for src_path in parser.header_paths_to_copy: 338*0e209d39SAndroid Build Coastguard Worker basename = os.path.basename(src_path) 339*0e209d39SAndroid Build Coastguard Worker dst_path = os.path.join(headers_folder, basename) 340*0e209d39SAndroid Build Coastguard Worker exported_symbol_map_this_header = { 341*0e209d39SAndroid Build Coastguard Worker key: value for key, value in exported_symbol_map.items() 342*0e209d39SAndroid Build Coastguard Worker if key in header_to_function_names[basename]} 343*0e209d39SAndroid Build Coastguard Worker modify_func_declarations(src_path, dst_path, exported_symbol_map_this_header) 344*0e209d39SAndroid Build Coastguard Worker # Remove #include lines from the header files. 345*0e209d39SAndroid Build Coastguard Worker if basename in IGNORED_INCLUDE_DEPENDENCY: 346*0e209d39SAndroid Build Coastguard Worker remove_ignored_includes(dst_path, IGNORED_INCLUDE_DEPENDENCY[basename]) 347*0e209d39SAndroid Build Coastguard Worker 348*0e209d39SAndroid Build Coastguard Worker copy_header_only_files() 349*0e209d39SAndroid Build Coastguard Worker 350*0e209d39SAndroid Build Coastguard Worker generate_cts_headers(allowlisted_apis) 351*0e209d39SAndroid Build Coastguard Worker 352*0e209d39SAndroid Build Coastguard Worker add_ndk_required_doxygen_grouping() 353*0e209d39SAndroid Build Coastguard Worker 354*0e209d39SAndroid Build Coastguard Worker # Apply documentation patches by the following shell script 355*0e209d39SAndroid Build Coastguard Worker subprocess.check_call( 356*0e209d39SAndroid Build Coastguard Worker [android_path('external/icu/tools/icu4c_srcgen/doc_patches/apply_patches.sh')]) 357*0e209d39SAndroid Build Coastguard Worker 358*0e209d39SAndroid Build Coastguard Worker print("Done. See the generated headers at libicu/ndk_headers/.") 359*0e209d39SAndroid Build Coastguard Worker 360*0e209d39SAndroid Build Coastguard Workerif __name__ == '__main__': 361*0e209d39SAndroid Build Coastguard Worker main() 362