Skip to content

Commit a96be45

Browse files
committed
Dynamic cairo symbol lookup
wip
1 parent 737bc6c commit a96be45

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

cairo/cairomodule.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <Python.h>
3434

3535
#include "private.h"
36+
#include "dynamic.h"
3637

3738
#ifdef CAIRO_HAS_PDF_SURFACE
3839
#include <cairo-pdf.h>
@@ -124,7 +125,9 @@ static Pycairo_CAPI_t CAPI = {
124125

125126
static PyObject *
126127
pycairo_cairo_version (PyObject *self, PyObject *ignored) {
127-
return PyLong_FromLong (cairo_version());
128+
RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(cairo_version);
129+
130+
return PyLong_FromLong (PYCAIRO_GET_CAIRO_FUNC(cairo_version)());
128131
}
129132

130133
static PyObject *

cairo/dynamic.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <stddef.h>
2+
#ifdef _WIN32
3+
#include <windows.h>
4+
#else
5+
#define _GNU_SOURCE
6+
#include <dlfcn.h>
7+
#endif
8+
9+
#include "dynamic.h"
10+
11+
#define INIT_CAIRO_FUNC(field, symbol_name) \
12+
.field = {symbol_name, NULL, 0}
13+
14+
_Pycairo_cairo_funcs_t _Pycairo_cairo_funcs = {
15+
INIT_CAIRO_FUNC(cairo_version, "cairo_version"),
16+
};
17+
18+
void* _Pycairo_get_cairo_symbol(const char* symbol_name) {
19+
static void* cairo_handle = NULL;
20+
static int handle_initialized = 0;
21+
22+
if (!handle_initialized) {
23+
handle_initialized = 1;
24+
#ifdef _WIN32
25+
HMODULE handle;
26+
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
27+
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
28+
(LPCSTR)cairo_create, &handle)) {
29+
cairo_handle = handle;
30+
}
31+
#else
32+
Dl_info info;
33+
if (dladdr((void*)cairo_create, &info) != 0) {
34+
cairo_handle = dlopen(info.dli_fname, RTLD_LAZY | RTLD_NOLOAD);
35+
}
36+
#endif
37+
}
38+
39+
if (!cairo_handle)
40+
return NULL;
41+
42+
#ifdef _WIN32
43+
return (void*)GetProcAddress((HMODULE)cairo_handle, symbol_name);
44+
#else
45+
dlerror();
46+
void* symbol = dlsym(cairo_handle, symbol_name);
47+
return (dlerror() == NULL) ? symbol : NULL;
48+
#endif
49+
}

cairo/dynamic.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#ifndef _PYCAIRO_DYNAMIC_H_
2+
#define _PYCAIRO_DYNAMIC_H_
3+
4+
#include <cairo.h>
5+
6+
void* _Pycairo_get_cairo_symbol(const char* symbol_name);
7+
8+
#define _PYCAIRO_DECLARE_CAIRO_FUNC(name, ret_type, params) \
9+
struct { \
10+
const char* symbol_name; \
11+
ret_type (*ptr)params; \
12+
int checked; \
13+
} name
14+
15+
typedef struct {
16+
_PYCAIRO_DECLARE_CAIRO_FUNC(cairo_version, int, (void));
17+
} _Pycairo_cairo_funcs_t;
18+
19+
extern _Pycairo_cairo_funcs_t _Pycairo_cairo_funcs;
20+
21+
#ifdef CAIRO_WIN32_STATIC_BUILD
22+
23+
#define PYCAIRO_GET_CAIRO_FUNC(field) (field)
24+
25+
#define RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(field)
26+
27+
#define PYCAIRO_HAS_CAIRO_FUNC(field) (1)
28+
29+
#else
30+
31+
#define PYCAIRO_GET_CAIRO_FUNC(field) \
32+
(_Pycairo_cairo_funcs.field.checked ? _Pycairo_cairo_funcs.field.ptr : \
33+
(_Pycairo_cairo_funcs.field.checked = 1, \
34+
_Pycairo_cairo_funcs.field.ptr = _Pycairo_get_cairo_symbol(_Pycairo_cairo_funcs.field.symbol_name)))
35+
36+
#define PYCAIRO_HAS_CAIRO_FUNC(field) \
37+
(PYCAIRO_GET_CAIRO_FUNC(field) != NULL)
38+
39+
#define RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC(field) \
40+
do { \
41+
if (!PYCAIRO_GET_CAIRO_FUNC(field)) { \
42+
PyErr_Format(PyExc_RuntimeError, "%s not available in this cairo build", \
43+
_Pycairo_cairo_funcs.field.symbol_name); \
44+
return NULL; \
45+
} \
46+
} while(0)
47+
48+
#endif
49+
50+
#endif // _PYCAIRO_DYNAMIC_H_

cairo/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ sources = [
2222
'surface.c',
2323
'textcluster.c',
2424
'textextents.c',
25+
'dynamic.c',
2526
]
2627

2728
foreach python_file : python_sources

0 commit comments

Comments
 (0)