• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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