Mercurial > pub > dyncall > bindings
annotate go/godc/godc.go @ 44:0f86a5ecfe61
- python: allow None to be passed for 'p'ointers, always passing NULL
author | Tassilo Philipp |
---|---|
date | Tue, 27 Oct 2020 18:44:18 +0100 |
parents | 1e3d929e43be |
children |
rev | line source |
---|---|
0 | 1 /* |
2 | |
3 godc.go | |
4 Copyright (c) 2014 Tassilo Philipp <tphilipp@potion-studios.com> | |
5 | |
6 Permission to use, copy, modify, and distribute this software for any | |
7 purpose with or without fee is hereby granted, provided that the above | |
8 copyright notice and this permission notice appear in all copies. | |
9 | |
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 | |
18 */ | |
19 | |
20 | |
21 // Go/dyncall extension implementation. | |
22 package godc | |
23 | |
9
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
24 // #cgo LDFLAGS: -ldyncall_s |
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
25 // #cgo LDFLAGS: -ldynload_s |
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
26 // #cgo LDFLAGS: -ldyncallback_s |
0 | 27 // #include <stdlib.h> |
9
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
28 // #include "dyncall.h" |
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
29 // #include "dynload.h" |
8a45a05ff64e
- go binding cleanup, not enforcing relative paths anymore, readme update
cslag
parents:
0
diff
changeset
|
30 // #include "dyncall_signature.h" |
0 | 31 import "C" |
32 import ( | |
33 "unsafe" | |
34 "fmt" | |
35 "reflect" | |
36 ) | |
37 | |
38 type ExtLib struct { | |
39 lib *C.DLLib | |
40 syms *C.DLSyms | |
41 } | |
42 | |
43 type CallVM struct { | |
44 cvm *C.DCCallVM | |
45 } | |
46 | |
47 | |
48 // dynload | |
49 func (p *ExtLib) Load(path string) error { | |
50 s := C.CString(path) | |
51 defer C.free(unsafe.Pointer(s)) | |
52 p.lib = C.dlLoadLibrary(s) | |
53 if p.lib != nil { return nil } | |
54 return fmt.Errorf("Can't load %s", path) | |
55 } | |
56 | |
57 func (p *ExtLib) Free() { | |
58 C.dlFreeLibrary(p.lib) | |
59 } | |
60 | |
61 func (p *ExtLib) FindSymbol(name string) unsafe.Pointer { | |
62 s := C.CString(name) | |
63 defer C.free(unsafe.Pointer(s)) | |
64 return unsafe.Pointer(C.dlFindSymbol(p.lib, s)) | |
65 } | |
66 | |
67 | |
68 // dynload Syms | |
69 func (p *ExtLib) SymsInit(path string) error { | |
70 s := C.CString(path) | |
71 defer C.free(unsafe.Pointer(s)) | |
72 p.syms = C.dlSymsInit(s) | |
73 if p.syms != nil { return nil } | |
74 return fmt.Errorf("Can't load %s", path) | |
75 } | |
76 | |
77 func (p *ExtLib) SymsCleanup() { | |
78 C.dlSymsCleanup(p.syms) | |
79 } | |
80 | |
81 func (p *ExtLib) SymsCount() int { | |
82 return int(C.dlSymsCount(p.syms)) | |
83 } | |
84 | |
85 func (p *ExtLib) SymsName(i int) string { | |
86 return C.GoString(C.dlSymsName(p.syms, C.int(i))) | |
87 } | |
88 | |
89 func (p *ExtLib) SymsNameFromValue(v unsafe.Pointer) string { | |
90 return C.GoString(C.dlSymsNameFromValue(p.syms, v)) | |
91 } | |
92 | |
93 | |
94 // dyncall | |
95 func (p *CallVM) InitCallVM() error { | |
96 return p.InitCallVMWithStackSize(4096) | |
97 } | |
98 | |
99 func (p *CallVM) InitCallVMWithStackSize(stackSize int) error { | |
100 p.cvm = C.dcNewCallVM(C.DCsize(stackSize)) | |
101 if p.cvm != nil { return nil } | |
102 return fmt.Errorf("Can't create CallVM") | |
103 } | |
104 | |
105 func (p *CallVM) Free() { | |
106 C.dcFree(p.cvm) | |
107 } | |
108 | |
109 func (p *CallVM) Reset() { | |
110 C.dcReset(p.cvm) | |
111 } | |
112 | |
113 | |
114 | |
115 // Modes | |
116 const ( | |
117 DC_CALL_C_DEFAULT = C.DC_CALL_C_DEFAULT | |
118 DC_CALL_C_ELLIPSIS = C.DC_CALL_C_ELLIPSIS | |
119 DC_CALL_C_ELLIPSIS_VARARGS = C.DC_CALL_C_ELLIPSIS_VARARGS | |
120 DC_CALL_C_X86_CDECL = C.DC_CALL_C_X86_CDECL | |
121 DC_CALL_C_X86_WIN32_STD = C.DC_CALL_C_X86_WIN32_STD | |
122 DC_CALL_C_X86_WIN32_FAST_MS = C.DC_CALL_C_X86_WIN32_FAST_MS | |
123 DC_CALL_C_X86_WIN32_FAST_GNU = C.DC_CALL_C_X86_WIN32_FAST_GNU | |
124 DC_CALL_C_X86_WIN32_THIS_MS = C.DC_CALL_C_X86_WIN32_THIS_MS | |
125 DC_CALL_C_X86_WIN32_THIS_GNU = C.DC_CALL_C_X86_WIN32_THIS_GNU | |
126 DC_CALL_C_X64_WIN64 = C.DC_CALL_C_X64_WIN64 | |
127 DC_CALL_C_X64_SYSV = C.DC_CALL_C_X64_SYSV | |
128 DC_CALL_C_PPC32_DARWIN = C.DC_CALL_C_PPC32_DARWIN | |
129 DC_CALL_C_PPC32_OSX = C.DC_CALL_C_PPC32_OSX | |
130 DC_CALL_C_ARM_ARM_EABI = C.DC_CALL_C_ARM_ARM_EABI | |
131 DC_CALL_C_ARM_THUMB_EABI = C.DC_CALL_C_ARM_THUMB_EABI | |
132 DC_CALL_C_ARM_ARMHF = C.DC_CALL_C_ARM_ARMHF | |
133 DC_CALL_C_MIPS32_EABI = C.DC_CALL_C_MIPS32_EABI | |
134 DC_CALL_C_MIPS32_PSPSDK = C.DC_CALL_C_MIPS32_PSPSDK | |
135 DC_CALL_C_PPC32_SYSV = C.DC_CALL_C_PPC32_SYSV | |
136 DC_CALL_C_PPC32_LINUX = C.DC_CALL_C_PPC32_LINUX | |
137 DC_CALL_C_ARM_ARM = C.DC_CALL_C_ARM_ARM | |
138 DC_CALL_C_ARM_THUMB = C.DC_CALL_C_ARM_THUMB | |
139 DC_CALL_C_MIPS32_O32 = C.DC_CALL_C_MIPS32_O32 | |
140 DC_CALL_C_MIPS64_N32 = C.DC_CALL_C_MIPS64_N32 | |
141 DC_CALL_C_MIPS64_N64 = C.DC_CALL_C_MIPS64_N64 | |
142 DC_CALL_C_X86_PLAN9 = C.DC_CALL_C_X86_PLAN9 | |
143 DC_CALL_C_SPARC32 = C.DC_CALL_C_SPARC32 | |
144 DC_CALL_C_SPARC64 = C.DC_CALL_C_SPARC64 | |
42
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
145 DC_CALL_C_ARM64 = C.DC_CALL_C_ARM64 |
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
146 DC_CALL_C_PPC64 = C.DC_CALL_C_PPC64 |
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
147 DC_CALL_C_PPC64_LINUX = C.DC_CALL_C_PPC64_LINUX |
0 | 148 DC_CALL_SYS_DEFAULT = C.DC_CALL_SYS_DEFAULT |
149 DC_CALL_SYS_X86_INT80H_LINUX = C.DC_CALL_SYS_X86_INT80H_LINUX | |
150 DC_CALL_SYS_X86_INT80H_BSD = C.DC_CALL_SYS_X86_INT80H_BSD | |
42
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
151 DC_CALL_SYS_X64_SYSCALL_SYSV = C.DC_CALL_SYS_X64_SYSCALL_SYSV |
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
152 DC_CALL_SYS_PPC32 = C.DC_CALL_SYS_PPC32 |
1e3d929e43be
- godc updated to dc 1.1 and added note about missing feature
Tassilo Philipp
parents:
9
diff
changeset
|
153 DC_CALL_SYS_PPC64 = C.DC_CALL_SYS_PPC64 |
0 | 154 ) |
155 | |
156 | |
157 func (p *CallVM) Mode(mode int) { | |
158 C.dcMode(p.cvm, C.DCint(mode)) | |
159 } | |
160 | |
161 // Error codes | |
162 const ( | |
163 DC_ERROR_NONE = C.DC_ERROR_NONE | |
164 DC_ERROR_UNSUPPORTED_MODE = C.DC_ERROR_UNSUPPORTED_MODE | |
165 ) | |
166 | |
167 | |
168 func (p *CallVM) GetError() int { | |
169 return int(C.dcGetError(p.cvm)) | |
170 } | |
171 | |
172 | |
173 // Helper for string/pointer conversion, needed as low-level string alloc needs to be freed in different scope | |
174 func (p *CallVM) AllocCString(value string) unsafe.Pointer { s := C.CString(value); return unsafe.Pointer(s) } | |
175 func (p *CallVM) FreeCString (value unsafe.Pointer) { C.free(value) } | |
176 | |
177 // Args | |
178 func (p *CallVM) ArgBool (value bool) { if value==true { C.dcArgBool(p.cvm, C.DC_TRUE) } else { C.dcArgBool(p.cvm, C.DC_FALSE) } } | |
179 func (p *CallVM) ArgChar (value int8) { C.dcArgChar (p.cvm, C.DCchar (value)) } | |
180 func (p *CallVM) ArgShort (value int16) { C.dcArgShort (p.cvm, C.DCshort (value)) } | |
181 func (p *CallVM) ArgInt (value int) { C.dcArgInt (p.cvm, C.DCint (value)) } | |
182 func (p *CallVM) ArgLong (value int32) { C.dcArgLong (p.cvm, C.DClong (value)) } | |
183 func (p *CallVM) ArgLongLong (value int64) { C.dcArgLongLong(p.cvm, C.DClonglong(value)) } | |
184 func (p *CallVM) ArgFloat (value float32) { C.dcArgFloat (p.cvm, C.DCfloat (value)) } | |
185 func (p *CallVM) ArgDouble (value float64) { C.dcArgDouble (p.cvm, C.DCdouble (value)) } | |
186 func (p *CallVM) ArgPointer (value unsafe.Pointer) { C.dcArgPointer (p.cvm, C.DCpointer (value)) } | |
187 //@@@func (p *CallVM) ArgStruct (s C.DCstruct*, value unsafe.Pointer) | |
188 | |
189 // "Formatted" args | |
190 // - first takes Go's types (as they cover all C types dyncall supports) and pushes values accordingly | |
191 // - second uses a dyncall signature for implicit type conversion/casting, however it uses reflect package and is slower | |
192 // Note that first version doesn't feature calling convention mode switching. | |
193 func (p *CallVM) ArgF_Go(args ...interface{}) error { | |
194 | |
195 for i, n := 0, len(args); i<n; i++ { | |
196 switch args[i].(type) { | |
197 case bool: p.ArgBool ( (args[i].(bool ))) | |
198 case int8: p.ArgChar ( (args[i].(int8 ))) | |
199 case uint8/*byte*/: p.ArgChar (int8 (args[i].(uint8 ))) | |
200 case int16: p.ArgShort ( (args[i].(int16 ))) | |
201 case uint16: p.ArgShort (int16 (args[i].(uint16 ))) | |
202 case int: p.ArgInt ( (args[i].(int ))) | |
203 case uint: p.ArgInt (int (args[i].(uint ))) | |
204 case int32/*rune*/: p.ArgLong ( (args[i].(int32 ))) | |
205 case uint32: p.ArgLong (int32 (args[i].(uint32 ))) | |
206 case int64: p.ArgLongLong( (args[i].(int64 ))) | |
207 case uint64: p.ArgLongLong(int64 (args[i].(uint64 ))) | |
208 case float32: p.ArgFloat ( (args[i].(float32 ))) | |
209 case float64: p.ArgDouble ( (args[i].(float64 ))) | |
210 case uintptr: p.ArgPointer (unsafe.Pointer(args[i].(unsafe.Pointer))) | |
211 case unsafe.Pointer: p.ArgPointer ( (args[i].(unsafe.Pointer))) | |
212 default: return fmt.Errorf("Unknown type passed to ArgF_Go") | |
213 } | |
214 } | |
215 return nil | |
216 } | |
217 | |
218 func (p *CallVM) ArgF(signature string, args ...interface{}) { | |
219 | |
220 tb := reflect.TypeOf((*bool )(nil)).Elem() | |
221 ti := reflect.TypeOf((*int64 )(nil)).Elem() | |
222 tf := reflect.TypeOf((*float64)(nil)).Elem() | |
223 tp := reflect.TypeOf((*uintptr)(nil)).Elem() | |
224 | |
225 for i, n := 0, len(signature); i<n; i++ { | |
226 //@@@ add support for calling convention mode(s) | |
227 switch s := signature[i]; s { | |
228 case C.DC_SIGCHAR_BOOL: p.ArgBool (bool (reflect.ValueOf(args[i]).Convert(tb).Bool ())) | |
229 case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (int8 (reflect.ValueOf(args[i]).Convert(ti).Int ())) | |
230 case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (int (reflect.ValueOf(args[i]).Convert(ti).Int ())) | |
231 case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (int32 (reflect.ValueOf(args[i]).Convert(ti).Int ())) | |
232 case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(int64 (reflect.ValueOf(args[i]).Convert(ti).Int ())) | |
233 case C.DC_SIGCHAR_FLOAT: p.ArgFloat (float32 (reflect.ValueOf(args[i]).Convert(tf).Float ())) | |
234 case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (float64 (reflect.ValueOf(args[i]).Convert(tf).Float ())) | |
235 case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (unsafe.Pointer(reflect.ValueOf(args[i]).Convert(tp).Pointer())) | |
236 case C.DC_SIGCHAR_ENDARG: return | |
237 } | |
238 // Faster, but doesn't do cross-type conversions. | |
239 //switch s := signature[i]; s { | |
240 // case C.DC_SIGCHAR_BOOL: p.ArgBool (args[i].(bool )) | |
241 // case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (args[i].(int8 )) | |
242 // case C.DC_SIGCHAR_SHORT, C.DC_SIGCHAR_USHORT: p.ArgShort (args[i].(int16 )) | |
243 // case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (args[i].(int )) | |
244 // case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (args[i].(int32 )) | |
245 // case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(args[i].(int64 )) | |
246 // case C.DC_SIGCHAR_FLOAT: p.ArgFloat (args[i].(float32 )) | |
247 // case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (args[i].(float64 )) | |
248 // case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (args[i].(unsafe.Pointer)) | |
249 // case C.DC_SIGCHAR_ENDARG: return | |
250 //} | |
251 } | |
252 } | |
253 | |
254 | |
255 // Calls | |
256 func (p *CallVM) CallVoid (funcptr unsafe.Pointer) { C.dcCallVoid (p.cvm, C.DCpointer(funcptr)) } | |
257 func (p *CallVM) CallBool (funcptr unsafe.Pointer) bool { b := (C.dcCallBool(p.cvm, C.DCpointer(funcptr))); if b==C.DC_TRUE { return true } else { return false } } | |
258 func (p *CallVM) CallChar (funcptr unsafe.Pointer) int8 { return int8 (C.dcCallChar (p.cvm, C.DCpointer(funcptr))) } | |
259 func (p *CallVM) CallShort (funcptr unsafe.Pointer) int16 { return int16 (C.dcCallShort (p.cvm, C.DCpointer(funcptr))) } | |
260 func (p *CallVM) CallInt (funcptr unsafe.Pointer) int { return int (C.dcCallInt (p.cvm, C.DCpointer(funcptr))) } | |
261 func (p *CallVM) CallLong (funcptr unsafe.Pointer) int32 { return int32 (C.dcCallLong (p.cvm, C.DCpointer(funcptr))) } | |
262 func (p *CallVM) CallLongLong (funcptr unsafe.Pointer) int64 { return int64 (C.dcCallLongLong(p.cvm, C.DCpointer(funcptr))) } | |
263 func (p *CallVM) CallFloat (funcptr unsafe.Pointer) float32 { return float32 (C.dcCallFloat (p.cvm, C.DCpointer(funcptr))) } | |
264 func (p *CallVM) CallDouble (funcptr unsafe.Pointer) float64 { return float64 (C.dcCallDouble (p.cvm, C.DCpointer(funcptr))) } | |
265 func (p *CallVM) CallPointer (funcptr unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(C.dcCallPointer (p.cvm, C.DCpointer(funcptr))) } | |
266 func (p *CallVM) CallPointerToStr(funcptr unsafe.Pointer) string { return C.GoString((*C.char)(C.dcCallPointer (p.cvm, C.DCpointer(funcptr)))) } // For convenience | |
267 //@@@func (p *CallVM) CallStruct (funcptr unsafe.Pointer, s C.DCstruct* s, returnValue unsafe.Pointer) | |
268 | |
269 // "Formatted" calls | |
270 //@@@func (p *CallVM) Call(result, funcptr unsafe.Pointer, signature string, args ...interface{}) { | |
271 //@@@... | |
272 //@@@} | |
273 | |
274 | |
275 //void dcCallF (DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, ...); | |
276 | |
277 /* | |
278 DC_API DCstruct* dcNewStruct (DCsize fieldCount, DCint alignment); | |
279 DC_API void dcStructField (DCstruct* s, DCint type, DCint alignment, DCsize arrayLength); | |
280 DC_API void dcSubStruct (DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength); | |
281 DC_API void dcCloseStruct (DCstruct* s); | |
282 DC_API DCsize dcStructSize (DCstruct* s); | |
283 DC_API DCsize dcStructAlignment(DCstruct* s); | |
284 DC_API void dcFreeStruct (DCstruct* s); | |
285 | |
286 DC_API DCstruct* dcDefineStruct (const char* signature); | |
287 */ | |
288 |