@@ -13,7 +13,7 @@ transparently execute code from Python to any programming language, for
13
13
example, calling JavaScript, NodeJS, Ruby or C# code from Python.
14
14
15
15
Install
16
- ========
16
+ =======
17
17
18
18
Install MetaCall binaries first:
19
19
@@ -28,7 +28,10 @@ Then install MetaCall Python package through MetaCall:
28
28
metacall pip3 install metacall
29
29
30
30
Example
31
- ========
31
+ =======
32
+
33
+ Calling Ruby from Python
34
+ ------------------------
32
35
33
36
``multiply.rb ``
34
37
@@ -44,7 +47,7 @@ Example
44
47
45
48
from metacall import metacall_load_from_file, metacall
46
49
47
- metacall_load_from_file(' rb' , [ ' multiply.rb' ]);
50
+ metacall_load_from_file(' rb' , [ ' multiply.rb' ])
48
51
49
52
metacall(' multiply' , 3 , 4 ); # 12
50
53
@@ -53,3 +56,152 @@ Running the example:
53
56
.. code :: console
54
57
55
58
metacall main.py
59
+
60
+ Using pointers (calling to a C library)
61
+ ---------------------------------------
62
+
63
+ For a simple case, let's imagine that we have a simple C function that
64
+ has an 'in' parameter and we want to pass a pointer to a long, from
65
+ Python side, and then store some value there for reading it later on.
66
+ Let's assume we have a ``loadtest.h `` and ``libloadtest.so `` and a C
67
+ function from this library could be this one:
68
+
69
+ .. code :: c
70
+
71
+ void modify_int_ptr(long *l)
72
+ {
73
+ *l = 111;
74
+ }
75
+
76
+ Now if we want to call it from Python side, we should do the following:
77
+
78
+ .. code :: py
79
+
80
+ from metacall import metacall_load_from_package, metacall, metacall_value_reference, metacall_value_dereference
81
+
82
+ # Load the library (we can configure the search paths for the .so and .lib with metacall_execution_path)
83
+ # metacall_execution_path('c', '/usr/local/include')
84
+ # metacall_execution_path('c', '/usr/local/lib')
85
+ metacall_load_from_package(' c' , ' loadtest' )
86
+
87
+ # Create value pointer (int *)
88
+ int_val = 324444
89
+ int_val_ref = metacall_value_reference(int_val)
90
+
91
+ # Pass the pointer to the function
92
+ metacall(' modify_int_ptr' , int_val_ref)
93
+
94
+ # Get the value from pointer
95
+ int_val_deref = metacall_value_dereference(int_val_ref)
96
+ print (int_val_deref, ' ==' , 111 )
97
+
98
+ For a more complex case, where we have an in/out parameter, for example
99
+ an opaque struct that we want to alloc from C side. First of all, with
100
+ the following header ``loadtest.h ``:
101
+
102
+ .. code :: c
103
+
104
+ #ifndef LIB_LOAD_TEST_H
105
+ #define LIB_LOAD_TEST_H 1
106
+
107
+ #if defined(WIN32) || defined(_WIN32)
108
+ #define EXPORT __declspec(dllexport)
109
+ #else
110
+ #define EXPORT __attribute__((visibility("default")))
111
+ #endif
112
+
113
+ #ifdef __cplusplus
114
+ extern "C" {
115
+ #endif
116
+
117
+ #include <cstdint>
118
+
119
+ typedef struct
120
+ {
121
+ uint32_t i;
122
+ double d;
123
+ } pair;
124
+
125
+ typedef struct
126
+ {
127
+ uint32_t size;
128
+ pair *pairs;
129
+ } pair_list;
130
+
131
+ EXPORT int pair_list_init(pair_list **t);
132
+
133
+ EXPORT double pair_list_value(pair_list *t, uint32_t id);
134
+
135
+ EXPORT void pair_list_destroy(pair_list *t);
136
+
137
+ #ifdef __cplusplus
138
+ }
139
+ #endif
140
+
141
+ #endif /* LIB_LOAD_TEST_H */
142
+
143
+ With the following implementation ``loadtest.cpp ``:
144
+
145
+ .. code :: c
146
+
147
+ #include "loadtest.h"
148
+
149
+ int pair_list_init(pair_list **t)
150
+ {
151
+ static const uint32_t size = 3;
152
+
153
+ *t = new pair_list();
154
+
155
+ (*t)->size = size;
156
+ (*t)->pairs = new pair[(*t)->size];
157
+
158
+ for (uint32_t i = 0; i < size; ++i)
159
+ {
160
+ (*t)->pairs[i].i = i;
161
+ (*t)->pairs[i].d = (double)(((double)i) * 1.0);
162
+ }
163
+
164
+ return 0;
165
+ }
166
+
167
+ double pair_list_value(pair_list *t, uint32_t id)
168
+ {
169
+ return t->pairs[id].d;
170
+ }
171
+
172
+ void pair_list_destroy(pair_list *t)
173
+ {
174
+ delete[] t->pairs;
175
+ delete t;
176
+ }
177
+
178
+ In this case the structs are not opaque, but they can be opaque and it
179
+ will work in the same way. Now, we can call those functions in the
180
+ following manner:
181
+
182
+ .. code :: py
183
+
184
+ from metacall import metacall_load_from_package, metacall, metacall_value_create_ptr, metacall_value_reference, metacall_value_dereference
185
+
186
+ metacall_load_from_package(' c' , ' loadtest' )
187
+
188
+ # Create a pointer to void* set to NULL
189
+ list_pair = metacall_value_create_ptr(None )
190
+
191
+ # Create a reference to it (void**)
192
+ list_pair_ref = metacall_value_reference(list_pair)
193
+
194
+ # Call the function
195
+ result = metacall(' pair_list_init' , list_pair_ref)
196
+
197
+ # Get the result updated (struct allocated)
198
+ list_pair = metacall_value_dereference(list_pair_ref)
199
+
200
+ # Pass it to a function
201
+ result = metacall(' pair_list_value' , list_pair, 2 )
202
+
203
+ # Destroy it
204
+ metacall(' pair_list_destroy' , list_pair)
205
+
206
+ # Here result will be 2.0 because is the third element in the array of pairs inside the struct
207
+ print (result, ' ==' , 2.0 )
0 commit comments