File tree Expand file tree Collapse file tree 4 files changed +95
-1
lines changed Expand file tree Collapse file tree 4 files changed +95
-1
lines changed Original file line number Diff line number Diff line change 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
125126static PyObject *
126127pycairo_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
130133static PyObject *
Original file line number Diff line number Diff line change 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+ }
Original file line number Diff line number Diff line change 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+ #define PYCAIRO_GET_CAIRO_FUNC (field ) \
22+ (_Pycairo_cairo_funcs.field.checked ? _Pycairo_cairo_funcs.field.ptr : \
23+ (_Pycairo_cairo_funcs.field.checked = 1, \
24+ _Pycairo_cairo_funcs.field.ptr = _Pycairo_get_cairo_symbol(_Pycairo_cairo_funcs.field.symbol_name)))
25+
26+ #define PYCAIRO_HAS_CAIRO_FUNC (field ) \
27+ (PYCAIRO_GET_CAIRO_FUNC(field) != NULL)
28+
29+ #define PYCAIRO_CAIRO_FUNC_NAME (field ) \
30+ (_Pycairo_cairo_funcs.field.symbol_name)
31+
32+ #define RETURN_NULL_IF_NOT_HAS_CAIRO_FUNC (field ) \
33+ do { \
34+ if (!PYCAIRO_GET_CAIRO_FUNC(field)) { \
35+ PyErr_Format(PyExc_RuntimeError, "%s not available in this cairo build", \
36+ PYCAIRO_CAIRO_FUNC_NAME(field)); \
37+ return NULL; \
38+ } \
39+ } while(0)
40+
41+ #endif // _PYCAIRO_DYNAMIC_H_
Original file line number Diff line number Diff line change @@ -22,6 +22,7 @@ sources = [
2222 ' surface.c' ,
2323 ' textcluster.c' ,
2424 ' textextents.c' ,
25+ ' dynamic.c' ,
2526]
2627
2728foreach python_file : python_sources
You can’t perform that action at this time.
0 commit comments