@@ -13,7 +13,7 @@ transparently execute code from Python to any programming language, for
1313example, calling JavaScript, NodeJS, Ruby or C# code from Python.
1414
1515Install
16- ========
16+ =======
1717
1818Install MetaCall binaries first:
1919
@@ -28,7 +28,10 @@ Then install MetaCall Python package through MetaCall:
2828 metacall pip3 install metacall
2929
3030 Example
31- ========
31+ =======
32+
33+ Calling Ruby from Python
34+ ------------------------
3235
3336``multiply.rb ``
3437
@@ -44,7 +47,7 @@ Example
4447
4548 from metacall import metacall_load_from_file, metacall
4649
47- metacall_load_from_file(' rb' , [ ' multiply.rb' ]);
50+ metacall_load_from_file(' rb' , [ ' multiply.rb' ])
4851
4952 metacall(' multiply' , 3 , 4 ); # 12
5053
@@ -53,3 +56,152 @@ Running the example:
5356.. code :: console
5457
5558 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