blob: 9c8ba515f8cabd1a3bf72e936c8a4be6f9c8ccdb [file] [log] [blame]
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "modules/skunicode/src/SkUnicode_icu.h"
#include <dlfcn.h>
#define SK_RUNTIME_ICU_PATHS "libicuuc.so"
std::unique_ptr<SkICULib> SkLoadICULib() {
static constexpr char const* gLibPaths[] = { SK_RUNTIME_ICU_PATHS };
void* dlhnd = nullptr;
for (const auto path : gLibPaths) {
dlhnd = dlopen(path, RTLD_LAZY);
if (dlhnd) {
break;
}
}
if (!dlhnd) {
SkDEBUGF("ICU loader: failed to open libicuuc.\n");
return nullptr;
}
int icu_ver = -1;
bool resolved_required_syms = true;
auto resolve_sym = [&](void* hnd, const char name[], bool required = false) -> void* {
static constexpr int kMinVer = 44,
kMaxVer = 100;
// First call performs a search to determine the actual lib version.
// Subsequent calls are pinned to the version found.
const auto search_to = icu_ver > 0 ? icu_ver : kMaxVer;
icu_ver = icu_ver > 0 ? icu_ver : kMinVer;
for (;;) {
const auto sym = SkStringPrintf("%s_%d", name, icu_ver);
if (auto* addr = dlsym(dlhnd, sym.c_str())) {
return addr;
}
if (icu_ver == search_to) {
break;
}
icu_ver++;
}
if (required) {
resolved_required_syms = false;
}
return nullptr;
};
SkICULib lib {};
// When using dlsym
// *(void**)(&procPtr) = dlsym(self, "proc");
// is non-standard, but safe for POSIX. Cannot write
// *reinterpret_cast<void**>(&procPtr) = dlsym(self, "proc");
// because clang has not implemented DR573. See http://clang.llvm.org/cxx_dr_status.html .
#define SKICU_FUNC(fname) *(void**)(&lib.f_##fname) = resolve_sym(dlhnd, #fname, true);
SKICU_EMIT_FUNCS
*(void**)(&lib.f_ubrk_clone_) = resolve_sym(dlhnd, "ubrk_clone");
*(void**)(&lib.f_ubrk_safeClone_) = resolve_sym(dlhnd, "ubrk_safeClone");
if (!resolved_required_syms || (!lib.f_ubrk_clone_ && !lib.f_ubrk_safeClone_)) {
SkDEBUGF("ICU loader: failed to resolve required symbols.");
dlclose(dlhnd);
return nullptr;
}
return std::make_unique<SkICULib>(lib);
}