1/* 2 * Copyright 2021 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkString.h" 9#include "include/core/SkTypes.h" 10#include "modules/skunicode/src/SkUnicode_icu.h" 11 12#include <dlfcn.h> 13 14#define SK_RUNTIME_ICU_PATHS "libicuuc.so" 15 16std::unique_ptr<SkICULib> SkLoadICULib() { 17 static constexpr char const* gLibPaths[] = { SK_RUNTIME_ICU_PATHS }; 18 19 void* dlhnd = nullptr; 20 for (const auto path : gLibPaths) { 21 dlhnd = dlopen(path, RTLD_LAZY); 22 if (dlhnd) { 23 break; 24 } 25 } 26 27 if (!dlhnd) { 28 SkDEBUGF("ICU loader: failed to open libicuuc.\n"); 29 return nullptr; 30 } 31 32 int icu_ver = -1; 33 34 bool resolved_required_syms = true; 35 36 auto resolve_sym = [&](void* hnd, const char name[], bool required = false) -> void* { 37 static constexpr int kMinVer = 44, 38 kMaxVer = 100; 39 40 // First call performs a search to determine the actual lib version. 41 // Subsequent calls are pinned to the version found. 42 const auto search_to = icu_ver > 0 ? icu_ver : kMaxVer; 43 icu_ver = icu_ver > 0 ? icu_ver : kMinVer; 44 45 for (;;) { 46 const auto sym = SkStringPrintf("%s_%d", name, icu_ver); 47 if (auto* addr = dlsym(dlhnd, sym.c_str())) { 48 return addr; 49 } 50 51 if (icu_ver == search_to) { 52 break; 53 } 54 55 icu_ver++; 56 } 57 58 if (required) { 59 resolved_required_syms = false; 60 } 61 return nullptr; 62 }; 63 64 SkICULib lib {}; 65 66 // When using dlsym 67 // *(void**)(&procPtr) = dlsym(self, "proc"); 68 // is non-standard, but safe for POSIX. Cannot write 69 // *reinterpret_cast<void**>(&procPtr) = dlsym(self, "proc"); 70 // because clang has not implemented DR573. See http://clang.llvm.org/cxx_dr_status.html . 71 #define SKICU_FUNC(fname) *(void**)(&lib.f_##fname) = resolve_sym(dlhnd, #fname, true); 72 SKICU_EMIT_FUNCS 73 74 *(void**)(&lib.f_ubrk_clone_) = resolve_sym(dlhnd, "ubrk_clone"); 75 *(void**)(&lib.f_ubrk_safeClone_) = resolve_sym(dlhnd, "ubrk_safeClone"); 76 77 if (!resolved_required_syms || (!lib.f_ubrk_clone_ && !lib.f_ubrk_safeClone_)) { 78 SkDEBUGF("ICU loader: failed to resolve required symbols."); 79 dlclose(dlhnd); 80 return nullptr; 81 } 82 83 return std::make_unique<SkICULib>(lib); 84} 85