forked from zeromq/zproject
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzproject_python_cffi.gsl
157 lines (149 loc) · 5.23 KB
/
zproject_python_cffi.gsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Generate minimal Python language bindings that use CFFI.
#
# These are not meant to be idiomatic, but to provide a minimal platform
# of FFI function bindings on which to base idiomatic Python classes.
#
# This is a code generator built using the iMatix GSL code generation
# language. See https://github.com/imatix/gsl for details.
#
# Copyright (c) the Contributors as noted in the AUTHORS file.
# This file is part of zproject.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
register_target ("python_cffi", "Python CFFI binding")
# Target provides name space isolation for its functions
function target_python_cffi
function register_type (struct, pointer)
if count(project->python_types.type, type.name = my.struct) = 0
new project->python_types.type
type.name = my.struct
type.pointer = my.pointer
endnew
endif
endfunction
function resolve_container (container)
if my.container.variadic
elsif my.container.type = "nothing"
elsif my.container.type = "anything" | my.container.type = "sockish"
elsif my.container.type = "boolean"
elsif my.container.type = "byte"
elsif my.container.type = "integer" | my.container.type = "file_size" | my.container.type = "time"
elsif my.container.type = "number"
elsif my.container.type = "size"
elsif my.container.type = "real"
elsif my.container.type = "buffer"
elsif my.container.type = "FILE"
elsif my.container.type = "string" | my.container.type = "format"
elsif my.container.callback
else
register_type ("$(my.container.type:c,no)_t", "$(my.container.type:c,no)_p")
endif
endfunction
function resolve_method (method)
my.method.python_name = "$(my.method.name:c)"
if regexp.match ("^(is|from)$", my.method.python_name) # matches keyword
my.method.python_name += "_"
endif
for my.method.argument where !argument.variadic
resolve_container (argument)
endfor
for my.method.return as ret
resolve_container (ret)
endfor
endfunction
function resolve_class (class)
register_type("$(class.c_name)_t", "$(class.c_name)_p")
for my.class.callback_type as method
resolve_method (method)
endfor
for my.class.constructor as method
resolve_method (method)
endfor
for my.class.destructor as method
resolve_method (method)
endfor
for my.class.method
resolve_method (method)
endfor
endfunction
function generate_binding
directory.create ("bindings/python_cffi")
output "bindings/python_cffi/$(project.name:c)_cffi.py"
>$(project.GENERATED_WARNING_HEADER:)
>
>from __future__ import print_function
>import os
>import re
>import sys
>
>from pyczmq._cffi import ffi
>
>try:
> # If LD_LIBRARY_PATH or your OSs equivalent is set, this is the only way to
> # load the library. If we use find_library below, we get the wrong result.
> if os.name == 'posix':
> if sys.platform == 'darwin':
> libpath = '$(project.libname).$(project->version.major).dylib'
> else:
> libpath = '$(project.libname).so.$(project->version.major)'
> elif os.name == 'nt':
> libpath = '$(project.libname).dll'
> lib = ffi.dlopen(libpath)
>except OSError:
> libpath = find_library("$(project.name)")
> if not libpath:
> raise ImportError("Unable to find $(project.libname)")
> lib = ffi.dlopen(libpath)
>
># Custom setup for $(project.name)
>$(file.slurp('src/python_cffi.inc')?'')
>
>cdefs = '''
for project->python_types.type as t
>typedef struct _$(t.name:c) $(t.name:c);
endfor
for class where defined (class.api) & class.private = "0"
for class.callback_type
>// $(callback_type.description:no,block)
>$(c_callback_typedef (callback_type):)
>
endfor
endfor
for class where defined (class.api) & class.private = "0"
>// CLASS: $(class.name)
for class. as f
if class(f) = "XML item" & (name(f) = 'constructor' | name(f) = 'destructor')
>// $(f.description:no,block)
>$(c_method_signature (f):);
>
endif
endfor
for class.actor
>// $(actor.description:no,block)
>$(PROJECT.PREFIX)_EXPORT void
> $(actor.name:c) (zsock_t *pipe, void *args);
>
endfor
for class.method
>// $(method.description:no,block)
>$(c_method_signature (method):);
>
endfor
endfor
>'''
>cdefs = re.sub(r';[^;]*\\bva_list\\b[^;]*;', ';', cdefs, flags=re.S) # we don't support anything with a va_list arg
>
>ffi.cdef(cdefs)
endfunction
if count (class, defined (class.api) & class.private = "0")
# Container for UDTs used by this module
new python_types
endnew
for class where defined (class.api) & class.private = "0"
resolve_class (class)
endfor
generate_binding ()
endif
endfunction