Reputation: 39
I am using SWIG to generate a PHP extension that calls into a 'c' shared lib. I am able to get most things to work except the following situation...
In my 'c' code I declare a function as (Please note that structure and function names have been changed to protect the innocent):
int getAllThePortInfo(EthernetPort *ports);
In this case, the parameter ports is actually an array of EthernetPort structures. In another 'c' program, I could have called it like this...
EthernetPort ports[4];
int rval = getAllThePortInfo(ports);
<etc>
<etc>
This works fine. Then I run SWIG, generate my shared lib, and all builds well. I get php code that I can call...
$ports = new_ethernetport();
$rval = getAllThePortInfo($ports);
This causes PHP to throw the following error : php: free(): invalid pointer: 0x099cb610
So, I tried to do something like...
$ports = array(new_ethernetport(), new_ethernetport(), new_ethernetport(), new_ethernetport());
$rval = getAllThePortInfo($ports);
But then PHP complained... PHP Fatal error: Type error in argument 1 of getAllThePortInfo. Expected SWIGTYPE_p_EthernetPort
What I think is happening is that PHP (and SWIG) do not differentiate between pointers and arrays, and in the wrapper, it is thinking 'pointer to a single structure', when, in reality, it is an array of structures.
Is there something in PHP I can do? Allocate a chunk of memory that I can use as a space to store more than one structure?
Is there something with SWIG I can do to make my wrapper understand my intentions better?
I truly would appreciate any suggestions. Thanks.
Upvotes: 0
Views: 1053
Reputation: 11
@DoranKatt, your solution worked for me too with one minor tweak. I had to change the order in the swig file:
%include <carrays.i>
%include "my_lib.h"
%array_functions(EthernetPort, ethernetPortArray);
with the original order I found it generated code that did not compile because the array functions referred to a type that was included later in "my_lib.h". Of course my code used different names and types but I've kept the original authors names for clarity.
Thanks for posting the original question and answer. This has dug me out of a hole. I couldn't find anything about this in the swig documentation.
Upvotes: 0
Reputation: 39
carrays.i indeed hold the answer to my question...
In the SWIG interface file, I have the following lines...
%include <carrays.i>
%array_functions(EthernetPort, ethernetPortArray);
%include "my_lib.h"
"my_lib.h" contains the typedef for the EthernetPort structure, as well as the function declaration...
#define NUM_ETHERNET_PORTS 4
typedef struct {
int number;
mode_t mode;
} EthernetPort;
int getAllThePortInfo(EthernetPort *ports);
After running SWIG and building the shared lib my_lib.so, I can use the following PHP code...
$ports = new_ethernetPortArray(NUM_ETHERNET_PORTS);
$rval = getAllThePortInfo($ports);
$port0 = ethernetPortArray_getitem($ports, 0);
$pnum = ethernetport_number_get($port1);
$pmode = ethernetport_mode_get($port1);
// port1 port2 port3 etc etc
delete_ethernetPortArray($ports);
The php functions new_ethernetPortArray, ethernetPortArray_getitem, ethernetport_number_get, ethernetport_mode_get, delete_ethernetPortArray were all created by SWIG based on the .i file.
The other benefit SWIG enables is the use of #define's in my php code (e.g. NUM_ETHERNET_PORTS), allowing me a single place for some of my common data. I like that. :-)
Cheers.
Upvotes: 1