|
| 1 | +import sh |
| 2 | +import os |
| 3 | +from os.path import join, isdir |
| 4 | +from pythonforandroid.recipe import NDKRecipe |
| 5 | +from pythonforandroid.toolchain import shprint, info |
| 6 | +from pythonforandroid.util import current_directory, ensure_dir |
| 7 | + |
| 8 | + |
| 9 | +class ICURecipe(NDKRecipe): |
| 10 | + name = 'icu4c' |
| 11 | + version = '57.1' |
| 12 | + url = 'http://download.icu-project.org/files/icu4c/57.1/icu4c-57_1-src.tgz' |
| 13 | + |
| 14 | + depends = [('python2', 'python3crystax')] # installs in python |
| 15 | + generated_libraries = [ |
| 16 | + 'libicui18n.so', 'libicuuc.so', 'libicudata.so', 'libicule.so'] |
| 17 | + |
| 18 | + def get_lib_dir(self, arch): |
| 19 | + lib_dir = join(self.ctx.get_python_install_dir(), "lib") |
| 20 | + ensure_dir(lib_dir) |
| 21 | + return lib_dir |
| 22 | + |
| 23 | + def prepare_build_dir(self, arch): |
| 24 | + if self.ctx.android_api > 19: |
| 25 | + # greater versions do not have /usr/include/sys/exec_elf.h |
| 26 | + raise RuntimeError("icu needs an android api <= 19") |
| 27 | + |
| 28 | + super(ICURecipe, self).prepare_build_dir(arch) |
| 29 | + |
| 30 | + def build_arch(self, arch, *extra_args): |
| 31 | + env = self.get_recipe_env(arch).copy() |
| 32 | + build_root = self.get_build_dir(arch.arch) |
| 33 | + |
| 34 | + def make_build_dest(dest): |
| 35 | + build_dest = join(build_root, dest) |
| 36 | + if not isdir(build_dest): |
| 37 | + ensure_dir(build_dest) |
| 38 | + return build_dest, False |
| 39 | + |
| 40 | + return build_dest, True |
| 41 | + |
| 42 | + icu_build = join(build_root, "icu_build") |
| 43 | + build_linux, exists = make_build_dest("build_icu_linux") |
| 44 | + |
| 45 | + host_env = os.environ.copy() |
| 46 | + # reduce the function set |
| 47 | + host_env["CPPFLAGS"] = ( |
| 48 | + "-O3 -fno-short-wchar -DU_USING_ICU_NAMESPACE=1 -fno-short-enums " |
| 49 | + "-DU_HAVE_NL_LANGINFO_CODESET=0 -D__STDC_INT64__ -DU_TIMEZONE=0 " |
| 50 | + "-DUCONFIG_NO_LEGACY_CONVERSION=1 " |
| 51 | + "-DUCONFIG_NO_TRANSLITERATION=0 ") |
| 52 | + |
| 53 | + if not exists: |
| 54 | + configure = sh.Command( |
| 55 | + join(build_root, "source", "runConfigureICU")) |
| 56 | + with current_directory(build_linux): |
| 57 | + shprint( |
| 58 | + configure, |
| 59 | + "Linux", |
| 60 | + "--prefix="+icu_build, |
| 61 | + "--enable-extras=no", |
| 62 | + "--enable-strict=no", |
| 63 | + "--enable-static", |
| 64 | + "--enable-tests=no", |
| 65 | + "--enable-samples=no", |
| 66 | + _env=host_env) |
| 67 | + shprint(sh.make, "-j5", _env=host_env) |
| 68 | + shprint(sh.make, "install", _env=host_env) |
| 69 | + |
| 70 | + build_android, exists = make_build_dest("build_icu_android") |
| 71 | + if exists: |
| 72 | + return |
| 73 | + |
| 74 | + configure = sh.Command(join(build_root, "source", "configure")) |
| 75 | + |
| 76 | + include = ( |
| 77 | + " -I{ndk}/sources/cxx-stl/gnu-libstdc++/{version}/include/" |
| 78 | + " -I{ndk}/sources/cxx-stl/gnu-libstdc++/{version}/libs/" |
| 79 | + "{arch}/include") |
| 80 | + include = include.format(ndk=self.ctx.ndk_dir, |
| 81 | + version=env["TOOLCHAIN_VERSION"], |
| 82 | + arch=arch.arch) |
| 83 | + env["CPPFLAGS"] = env["CXXFLAGS"] + " " |
| 84 | + env["CPPFLAGS"] += host_env["CPPFLAGS"] |
| 85 | + env["CPPFLAGS"] += include |
| 86 | + |
| 87 | + lib = "{ndk}/sources/cxx-stl/gnu-libstdc++/{version}/libs/{arch}" |
| 88 | + lib = lib.format(ndk=self.ctx.ndk_dir, |
| 89 | + version=env["TOOLCHAIN_VERSION"], |
| 90 | + arch=arch.arch) |
| 91 | + env["LDFLAGS"] += " -lgnustl_shared -L"+lib |
| 92 | + |
| 93 | + env.pop("CFLAGS", None) |
| 94 | + env.pop("CXXFLAGS", None) |
| 95 | + |
| 96 | + with current_directory(build_android): |
| 97 | + shprint( |
| 98 | + configure, |
| 99 | + "--with-cross-build="+build_linux, |
| 100 | + "--enable-extras=no", |
| 101 | + "--enable-strict=no", |
| 102 | + "--enable-static", |
| 103 | + "--enable-tests=no", |
| 104 | + "--enable-samples=no", |
| 105 | + "--host="+env["TOOLCHAIN_PREFIX"], |
| 106 | + "--prefix="+icu_build, |
| 107 | + _env=env) |
| 108 | + shprint(sh.make, "-j5", _env=env) |
| 109 | + shprint(sh.make, "install", _env=env) |
| 110 | + |
| 111 | + self.copy_files(arch) |
| 112 | + |
| 113 | + def copy_files(self, arch): |
| 114 | + ndk = self.ctx.ndk_dir |
| 115 | + env = self.get_recipe_env(arch) |
| 116 | + |
| 117 | + lib = "{ndk}/sources/cxx-stl/gnu-libstdc++/{version}/libs/{arch}" |
| 118 | + lib = lib.format(ndk=self.ctx.ndk_dir, |
| 119 | + version=env["TOOLCHAIN_VERSION"], |
| 120 | + arch=arch.arch) |
| 121 | + stl_lib = join(lib, "libgnustl_shared.so") |
| 122 | + dst_dir = join(self.ctx.get_site_packages_dir(), "..", "lib-dynload") |
| 123 | + shprint(sh.cp, stl_lib, dst_dir) |
| 124 | + |
| 125 | + src_lib = join(self.get_build_dir(arch.arch), "icu_build", "lib") |
| 126 | + dst_lib = self.get_lib_dir(arch) |
| 127 | + |
| 128 | + src_suffix = "." + self.version |
| 129 | + dst_suffix = "." + self.version.split(".")[0] # main version |
| 130 | + for lib in self.generated_libraries: |
| 131 | + shprint(sh.cp, join(src_lib, lib+src_suffix), |
| 132 | + join(dst_lib, lib+dst_suffix)) |
| 133 | + |
| 134 | + src_include = join( |
| 135 | + self.get_build_dir(arch.arch), "icu_build", "include") |
| 136 | + dst_include = join( |
| 137 | + self.ctx.get_python_install_dir(), "include", "icu") |
| 138 | + ensure_dir(dst_include) |
| 139 | + shprint(sh.cp, "-r", join(src_include, "layout"), dst_include) |
| 140 | + shprint(sh.cp, "-r", join(src_include, "unicode"), dst_include) |
| 141 | + |
| 142 | + # copy stl library |
| 143 | + lib = "{ndk}/sources/cxx-stl/gnu-libstdc++/{version}/libs/{arch}" |
| 144 | + lib = lib.format(ndk=self.ctx.ndk_dir, |
| 145 | + version=env["TOOLCHAIN_VERSION"], |
| 146 | + arch=arch.arch) |
| 147 | + stl_lib = join(lib, "libgnustl_shared.so") |
| 148 | + |
| 149 | + dst_dir = join(self.ctx.get_python_install_dir(), "lib") |
| 150 | + ensure_dir(dst_dir) |
| 151 | + shprint(sh.cp, stl_lib, dst_dir) |
| 152 | + |
| 153 | + |
| 154 | +recipe = ICURecipe() |
0 commit comments