Skip to content

Commit 7e384e1

Browse files
committed
Report library paths.
1 parent eb27fbf commit 7e384e1

File tree

6 files changed

+76
-36
lines changed

6 files changed

+76
-36
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ jobs:
6464
run: |
6565
set -x &&
6666
python -mpip list &&
67+
python -c 'import mplcairo as m, pprint as p; p.pprint(m.get_versions())' &&
6768
# Skip tests triggering to-be-investigated fatal error on Windows :(
6869
(
6970
if [[ "$(python -c 'import sys; print(sys.platform)')" != win32 ]]; then

src/_mplcairo.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
#include "_macros.h"
1515

16+
using namespace pybind11::literals;
17+
using namespace std::string_literals;
18+
1619
P11X_DECLARE_ENUM(
1720
"antialias_t", "enum.Enum",
1821
{"DEFAULT", CAIRO_ANTIALIAS_DEFAULT},
@@ -104,8 +107,6 @@ P11X_DECLARE_ENUM(
104107

105108
namespace mplcairo {
106109

107-
using namespace pybind11::literals;
108-
109110
Region::Region(
110111
cairo_rectangle_int_t bbox, std::unique_ptr<uint8_t const[]> buffer) :
111112
bbox{bbox}, buffer{std::move(buffer)}
@@ -1952,7 +1953,7 @@ PYBIND11_MODULE(_mplcairo, m)
19521953
auto const& ctypes = py::module::import("ctypes"),
19531954
& _cairo = py::module::import("cairo._cairo");
19541955
auto const& dll = ctypes.attr("CDLL")(_cairo.attr("__file__"));
1955-
auto const& load_ptr = [&](char const* name) -> uintptr_t {
1956+
auto const& load_ptr = [&](char const* name) -> os::symbol_t {
19561957
return
19571958
ctypes.attr("cast")(
19581959
py::getattr(dll, name, py::int_(0)), ctypes.attr("c_void_p"))
@@ -1963,8 +1964,7 @@ PYBIND11_MODULE(_mplcairo, m)
19631964
return os::dlsym(name);
19641965
};
19651966
#endif
1966-
#define LOAD_API(name) \
1967-
detail::name = reinterpret_cast<decltype(detail::name)>(load_ptr(#name));
1967+
#define LOAD_API(name) detail::name = load_ptr(#name);
19681968
ITER_CAIRO_OPTIONAL_API(LOAD_API)
19691969
#undef LOAD_API
19701970

@@ -2107,29 +2107,36 @@ straight RGBA8888.
21072107
)__doc__");
21082108
m.def(
21092109
"get_versions", [] {
2110-
auto const& cairo_version = cairo_version_string();
2110+
auto const& cairo_version =
2111+
cairo_version_string() + " @ "s
2112+
+ os::dladdr_fname(cairo_version_string);
21112113
auto ft_major = 0, ft_minor = 0, ft_patch = 0;
21122114
FT_Library_Version(detail::ft_library, &ft_major, &ft_minor, &ft_patch);
21132115
auto const& freetype_version =
21142116
std::to_string(ft_major) + "."
21152117
+ std::to_string(ft_minor) + "."
2116-
+ std::to_string(ft_patch);
2118+
+ std::to_string(ft_patch) + " @ "
2119+
+ os::dladdr_fname(FT_Library_Version);
21172120
auto const& pybind11_version =
21182121
Py_STRINGIFY(PYBIND11_VERSION_MAJOR) "."
21192122
Py_STRINGIFY(PYBIND11_VERSION_MINOR) "."
21202123
Py_STRINGIFY(PYBIND11_VERSION_PATCH);
21212124
auto const& raqm_version =
21222125
has_raqm()
2123-
? std::optional<std::string>{raqm::version_string()} : std::nullopt;
2126+
? std::optional{raqm::version_string() + " @ "s
2127+
+ os::dladdr_fname(raqm::version_string)}
2128+
: std::nullopt;
21242129
auto const& hb_version =
21252130
has_raqm() && hb::version_string
2126-
? std::optional<std::string>{hb::version_string()} : std::nullopt;
2131+
? std::optional{hb::version_string() + " @ "s
2132+
+ os::dladdr_fname(hb::version_string)}
2133+
: std::nullopt;
21272134
return py::dict(
21282135
"cairo"_a=cairo_version,
21292136
"freetype"_a=freetype_version,
21302137
"pybind11"_a=pybind11_version,
21312138
"raqm"_a=raqm_version,
2132-
"hb"_a=hb_version);
2139+
"harfbuzz"_a=hb_version);
21332140
}, R"__doc__(
21342141
Get library versions.
21352142

src/_os.cpp

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ namespace mplcairo::os {
1818
namespace py = pybind11;
1919

2020
#if defined __linux__ || defined __APPLE__
21-
using library_t = void*;
22-
using symbol_t = void*;
23-
2421
library_t dlopen(char const* filename)
2522
{
2623
return ::dlopen(filename, RTLD_LAZY);
@@ -42,6 +39,16 @@ void throw_dlerror()
4239
throw py::error_already_set{};
4340
}
4441

42+
std::string dladdr_fname(symbol_t handle)
43+
{
44+
auto dlinfo = Dl_info{};
45+
return
46+
::dladdr(handle, &dlinfo)
47+
? py::module::import("os").attr("fsdecode")(
48+
py::bytes(dlinfo.dli_fname)).cast<std::string>()
49+
: "";
50+
}
51+
4552
void install_abrt_handler()
4653
{
4754
signal(SIGABRT, [](int signal) {
@@ -54,9 +61,6 @@ void install_abrt_handler()
5461
}
5562

5663
#elif defined _WIN32
57-
using library_t = HMODULE;
58-
using symbol_t = FARPROC;
59-
6064
library_t dlopen(char const* filename)
6165
{
6266
// Respect os.add_dll_directory.
@@ -75,15 +79,15 @@ symbol_t dlsym(library_t handle, char const* symbol)
7579

7680
symbol_t dlsym(char const* symbol)
7781
{
78-
auto hProcess = GetCurrentProcess();
79-
auto cbNeeded = DWORD{};
80-
EnumProcessModules(hProcess, nullptr, 0, &cbNeeded);
81-
auto n_modules = cbNeeded / sizeof(HMODULE);
82-
auto lphModule = std::unique_ptr<HMODULE[]>{new HMODULE[n_modules]};
83-
if (EnumProcessModules(hProcess, lphModule.get(), cbNeeded, &cbNeeded)) {
82+
auto proc = GetCurrentProcess();
83+
auto size = DWORD{};
84+
EnumProcessModules(proc, nullptr, 0, &size);
85+
auto n_modules = size / sizeof(HMODULE);
86+
auto modules = std::unique_ptr<HMODULE[]>{new HMODULE[n_modules]};
87+
if (EnumProcessModules(proc, modules.get(), size, &size)) {
8488
for (auto i = 0; i < n_modules; ++i) {
85-
if (auto proc = GetProcAddress(lphModule[i], symbol)) {
86-
return proc;
89+
if (auto ptr = GetProcAddress(modules[i], symbol)) {
90+
return ptr;
8791
}
8892
}
8993
}
@@ -96,6 +100,20 @@ void throw_dlerror()
96100
throw py::error_already_set{};
97101
}
98102

103+
std::string dladdr_fname(symbol_t handle)
104+
{
105+
auto proc = GetCurrentProcess();
106+
HMODULE mod;
107+
wchar_t wpath[MAX_PATH];
108+
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
109+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
110+
handle, &mod)
111+
&& GetModuleFileNameEx(proc, mod, wpath, MAX_PATH)) {
112+
return py::cast(wpath).cast<std::string>();
113+
}
114+
return "";
115+
}
116+
99117
void install_abrt_handler()
100118
{
101119
}

src/_os.h

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,44 @@
1+
#pragma once
2+
13
#include <iostream>
24

35
#ifdef _WIN32
46
#define NOMINMAX
7+
#define UNICODE
8+
#define _UNICODE
59
#include <Windows.h>
610
#endif
711

812
namespace mplcairo::os {
913

1014
#if defined __linux__ || defined __APPLE__
1115
using library_t = void*;
12-
using symbol_t = void*;
16+
using symbol_ptr_t = void*;
1317
#elif defined _WIN32
1418
using library_t = HMODULE;
15-
using symbol_t = FARPROC;
16-
17-
// Like dlsym, but looks through everything listed by EnumProcessModules.
18-
symbol_t dlsym(char const* symbol);
19+
using symbol_ptr_t = FARPROC;
1920
#endif
21+
22+
class symbol_t {
23+
symbol_ptr_t ptr;
24+
25+
public:
26+
// Allow implicit cast from int (address) but not to int (only to pointers).
27+
template<typename T> symbol_t(T ptr) : ptr{reinterpret_cast<symbol_ptr_t>(ptr)} {}
28+
template<typename T> operator T*() const { return reinterpret_cast<T*>(ptr); }
29+
};
30+
2031
library_t dlopen(char const* filename);
2132
bool dlclose(library_t handle);
2233
symbol_t dlsym(library_t handle, char const* symbol);
2334
void throw_dlerror();
35+
std::string dladdr_fname(symbol_t handle);
2436

2537
void install_abrt_handler();
2638

39+
#if defined _WIN32
40+
// Like dlsym, but looks through everything listed by EnumProcessModules.
41+
symbol_t dlsym(char const* symbol);
42+
#endif
43+
2744
}

src/_raqm.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ void load_raqm() {
3535
os::throw_dlerror();
3636
}
3737
#define LOAD_API(name) \
38-
if (!(raqm::name = \
39-
reinterpret_cast<decltype(raqm::name)>( \
40-
os::dlsym(raqm::_handle, "raqm_" #name)))) { \
38+
if (!(raqm::name = os::dlsym(raqm::_handle, "raqm_" #name))) { \
4139
os::dlclose(raqm::_handle); \
4240
raqm::_handle = nullptr; \
4341
os::throw_dlerror(); \
@@ -56,8 +54,7 @@ void load_raqm() {
5654
// Trying to retrieve hb_version_string from the raqm shared object
5755
// normally only works on POSIX, so we just allow this to be nullptr and
5856
// check that at the call site.
59-
hb::version_string = reinterpret_cast<decltype(hb::version_string)>(
60-
os::dlsym(raqm::_handle, "hb_version_string"));
57+
hb::version_string = os::dlsym(raqm::_handle, "hb_version_string");
6158
}
6259
}
6360

src/_util.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
#include <pybind11/stl.h>
99

1010
// Helper for std::visit.
11-
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
12-
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
11+
template<typename... Ts> struct overloaded : Ts... { using Ts::operator()...; };
12+
template<typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;
1313

1414
namespace mplcairo {
1515

0 commit comments

Comments
 (0)