(This is a question I asked yesterday, but I simplified it)
I've created a class, of which I want two objects as output arguments of a function (called Test below). But when I run the swig command swig -c++ -python swigtest.i I'm getting the error "Warning 453: Can't apply (MyClass &OUTPUT). No typemaps are defined." I tried adding typemaps, but that doesn't help. I also tried using pointers, pointers to pointers and references to pointers, that doesn't help either.
I feel like I've overlooked something simple, because this should be quite a common thing to do. Or do I need to write a complex typemap, like I've seen around but don't understand (yet)?
Below is my code:
MyClass.h (simplified to make it understandable, so switching to just int doesn't help):
class MyClass
{
int x;
public:
int get() const
{
return x;
}
};
void Test(MyClass &obj1, MyClass &obj2);
swigtest.i:
%module swigtest
%include typemaps.i
%{
#define SWIG_FILE_WITH_INIT
%}
%{
#include "MyClass.h"
%}
%include "MyClass.h"
%apply (MyClass& OUTPUT) { MyClass &obj1 }
%apply (MyClass& OUTPUT) { MyClass &obj2 }
As noted in my previous comment, the %apply OUTPUT trick only works for a limited set of POD types.
For future Swiggers, this solution worked for me (in C# bindings):
%typemap(cstype) CustomType* "out CustomType"
%typemap(csin,
pre=" $csclassname temp$csinput = new $csclassname();",
post=" $csinput = temp$csinput;"
) CustomType* "$csclassname.getCPtr(temp$csinput)"
This generates a public interface with an "out" param for CustomType passed by pointer. The internal P/Invoke interface (csim) is left as raw pointers. The "csin" typemap creates a temp variable and assigns to the output parameter.
Also worth noting that in C#, if MyCustomType is already a reference type, you may not need this, however it's strange to have an API that modifies the parameter value without declaring it as "out" (this actually works for my type, but I prefer the explicit out param).
Try:
%module swigtest
%{
#define SWIG_FILE_WITH_INIT
#include "MyClass.h"
%}
%include "typemaps.i"
%apply MyClass *OUTPUT { MyClass &obj1, MyClass &obj2 };
%include "MyClass.h"
You could also create a wrapper that returns a std::list:
%include "std_list.i"
%ignore Test;
%rename(Test) TestWrap;
%inline %{
std::list<MyClass> TestWrap() {
MyClass obj1, obj2;
Test(obj1, obj2);
std::list<MyClass> tempList;
tempList.push_back(obj1);
tempList.push_back(obj2);
return tempList;
}
%}
I settled for adding extra Python code in swigtest.i that wraps the test function, so that I can write obj1, obj2 = Test2(). I still think there must be an easier solution,
// swigtest.i:
%module swigtest
%{
#define SWIG_FILE_WITH_INIT
#include "MyClass.h"
%}
%include "MyClass.h"
%insert("python") %{
def Test2():
obj1 = swigtest.MyClass()
obj2 = swigtest.MyClass()
swigtest.Test(obj1, obj2)
return obj1, obj2
%}
Related
I have following c++ functions for which i am making Java wrapper
void label(const std::string &label) { // wrapper correctly built
...
}
void label(const boost::none_t t) { // generating SWIGTYPE_p_boost__none_t
...
}
How can i correctly wrap boost::none_t in Java. I m new to SWIG. Any help is appreciated
Depending on quite what this function actually does you probably want something like:
%{
#include <boost/none.hpp>
%}
%typemap(in,numinputs=0) boost::none_t %{
$1 = boost::none;
%}
void label(const boost::none_t t);
Which then generates the following Java:
public static void label()
The argument is omitted in Java and automatically filled out with boost::none via an assignment before the function gets called.
I read here how to wrap this macro FOOBAR in SWIG:
class foobar {
public:
static void method() {}
};
#define FOOBAR() foobar().method()
The solution is to include this in SWIG interface:
void FOOBAR();
However, suppose I drop () so that my macro is
#define FOOBAR foobar().method()
This is still perfectly legitimate macro I can use in C++. How do I wrap this, so I can say on Python command line:
>>>FOOBAR
To clarify, since this seems to be confusing. I purposely chose the method to return nothing. I did that, so that the irrelevant question of "what is it supposed to return" is not considered. However, people still seem to want to consider it.
OK then, in C++, FOOBAR has meaning - it is a certain object, I can call FOOBAR.someMethod(). I want that on Python command line, it also be an object (the equivalent one), which will behave the same, I also want to call FOOBAR.someMethod() and have it behave the same as in C++.
I am sorry, but I assumed, that in the context of SWIG, the above explanation is obvious and unnecessary, and is contained in the abbreviation "wrap".
%pythoncode may be what you want. Example:
%module x
%inline %{
class foobar {
public:
static void method() {}
};
#define FOOBAR foobar().method()
%}
%pythoncode %{
FOOBAR = foobar().method
%}
Result:
>>> from x import *
>>> FOOBAR
<built-in function foobar_method>
I'm making a wrapper of a C++ library so it can be used from Java, I'm doing this with Swig.
What I'm facing is that i have a Class SomeClass, which has some overloaded methods (someMethod). Of this overloaded methods some receive complex data that i don't want to export to the wrapper, and some simple ones which i do want then exported.
I'm trying to use the %rename("$ignore") directive but either i get all methods exported or none. I have another two types of Classes SimpleData and ComplexData, one of them in namespace ns1 and the other in ns2, SomeClass is in namespace ''ns3`.
The class SimpleData:
#ifndef SIMPLEDATA_H_
#define SIMPLEDATA_H_
namespace ns1 {
class SimpleData {
public:
SimpleData(){}
virtual ~SimpleData(){}
};
} /* namespace ns1 */
#endif /* SIMPLEDATA_H_ */
The class ComplexData:
#ifndef COMPLEXDATA_H_
#define COMPLEXDATA_H_
namespace ns2 {
class ComplexData {
public:
ComplexData(){}
virtual ~ComplexData(){}
};
} /* namespace ns2 */
#endif /* COMPLEXDATA_H_ */
The class SomeClass:
#ifndef SOMECLASS_H_
#define SOMECLASS_H_
#include "SimpleData.h"
#include "ComplexData.h"
namespace ns3 {
class SomeClass {
public:
SomeClass(){}
bool someMethod(const ns1::SimpleData & data){return true;}
bool someMethod(const ns2::ComplexData & data){return true;}
bool someMethod(const int & data){return true;}
bool anotherMethod();
virtual ~SomeClass(){}
};
} /* namespace ns3 */
#endif /* SOMECLASS_H_ */
The i file snippet looks like this:
%rename ("$ignore", fullname=1) "ns3::SomeClass::someMethod(const ns2::ComplexData&)";
But that isn't working. Which one is the correct way of ignoring some specific overload of a method?
The full .i file:
%module libSomeClass
%{
#include "../src/SomeClass.h"
%}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("SWIG_C++");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
// SimpleData
%include "../src/SimpleData.h"
//removes too much
//%rename ("$ignore", fullname=1) "ns3::SomeClass::someMethod";
//does not work
%rename ("$ignore", fullname=1) "ns3::SomeClass::someMethod(const ns2::ComplexData &)";
%rename ("renamedMethod", fullname=1) "ns3::SomeClass::anotherMethod";
%include "../src/SomeClass.h"
Note: I don't think it actually has nothing to do but just in case, those methods actually throw a exception.
Note2: I also don't think is relevant, but the target language is Java and the source language is C++.
Have you tried using just the %ignore directive, http://www.swig.org/Doc1.3/SWIG.html#SWIG_rename_ignore? Check out http://www.swig.org/Doc1.3/SWIGPlus.html#ambiguity_resolution_renaming to see how to best match the function you want to ignore.
Also note that "The placement of the %rename directive is arbitrary as long as it appears before the declarations to be renamed", is your %rename before the function?
(In your example you are missing the class name, I assume that is just a typo right?)
The solution is to not use quotes with the method signature.
%rename ("$ignore", fullname=1) ns3::SomeClass::someMethod(const ns2::ComplexData &);
I did put quotes in the first place because I always have and always worked for me, for example:
%rename ("renamedMethod", fullname=1) "ns3::SomeClass::anotherMethod";
The full .i file for reference:
%module libSomeClass
%{
#include "../src/SomeClass.h"
%}
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("SWIG_C++");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}
// SimpleData
%include "../src/SimpleData.h"
%rename ("$ignore", fullname=1) ns3::SomeClass::someMethod(const ns2::ComplexData &);
%ignore ns3::SomeClass::someMethod(const int &);
%rename ("renamedMethod", fullname=1) "ns3::SomeClass::anotherMethod";
%include "../src/SomeClass.h"
I have two C functions that I'm exposing through SWIG to my Java layer and both have an input param with a const void * data type ("val) that needs to be a uint8_t for the addCategory function but a char for the addAttribute function. I'm currently, in the SWIG Interface file, using the %apply to map the const void * C type to a short on the Java side. Is there a way to modify the SWIG interface file to support both a char (String) and a uint8_t (short) for the const void * input parameter?
C Functions from header file:
int
addCategory(query_t *query, type_t type, const void *val);
int
addAttribute(query_t *query, type_t type, const void *val);
SWIG Interface File:
%module Example
%include "stdint.i"
void setPhy_idx(uint32_t value);
%include "arrays_java.i"
void setId(unsigned char *value);
%{
#include "Example.h"
%}
%apply char * { unsigned char * };
%apply char * { void * };
%apply uint8_t { const void * }
%apply int32_t { int32_t * }
%include "Example.h"
You can't directly do this - what type would be used in this place in Java? You need to help SWIG decide that in some way.
You have (at least) three possible solutions:
Use a type hierarchy - The base type will be what the function takes, the subclasses will get wrapped also. You could do this on the C++ side, or on the Java side using SWIG's typemap facilities. I think this is needlessly complicated though, so I've not made an example here.
Use overloads (or even different functions, with different names altogether - you could use %rename to make them back into overloads in Java even if they have different names in C)
Use a union. This will get wrapped with set and get functions by SWIG:
%module test
union values {
unsigned char *string;
void *generic;
uint8_t someOtherThing;
uint32_t number;
};
void func(values v);
This results in a Java class called values, which func() takes and can pass one of the members of the union through. Clearly you'd want to %apply appropriate typemaps for the members of the union.
I'm trying to write a typemap that converts multiple/variable arguments into one input parameter.
For example, say I have a function that takes a vector.
void foo(vector<int> x);
And I want to call it like this (happens to be in Perl)
foo(1,2,3,4);
The typemap should take arguments ($argnum, ...), gather them into one vector and then pass that to foo.
I have this so far:
typedef vector<int> vectori;
%typemap(in) (vectori) {
for (int i=$argnum-1; i<items; i++) {
$1->push_back( <argv i> ); // This is language dependent, of course.
}
}
This would work, except that SWIG checks the number of arguments
if ((items < 1) || (items > 1)) {
SWIG_croak("Usage: foo(vectori);");
}
If I do:
void foo(vectori, ...);
SWIG will expect to call foo with two arguments.
foo(arg1, arg2);
Perhaps there's a way to tell SWIG to suppress arg2 from the call to foo?
I can't use this in my .i:
void foo(...)
because I want to have different typemaps, depending on the types that foo is expecting (an array of int, strings, whatever). Maybe there's a way to give a type to "..."
Is there a way to do this?
SWIG has built-in support for some STL classes. Try this for your SWIG .i file:
%module mymod
%{
#include <vector>
#include <string>
void foo_int(std::vector<int> i);
void foo_str(std::vector<std::string> i);
%}
%include <std_vector.i>
%include <std_string.i>
// Declare each template used so SWIG exports an interface.
%template(vector_int) std::vector<int>;
%template(vector_str) std::vector<std::string>;
void foo_int(std::vector<int> i);
void foo_str(std::vector<std::string> i);
Then call it with array syntax in the language of choice:
#Python
import mymod
mymod.foo_int([1,2,3,4])
mymod.foo_str(['abc','def','ghi'])
SWIG determines the argument count at the time SWIG generates the bindings. SWIG does provide some limited support for variable argument lists but I'm not sure this is the right approach to take. If you're interested, you can read more about it in the SWIG vararg documentation section.
I think a better approach would be to pass these values in as an array reference. Your typemap would then look something like this (not tested):
%typemap(in) vectori (vector<int> tmp)
{
if (!SvROK($input))
croak("Argument $argnum is not a reference.");
if (SvTYPE(SvRV($input)) != SVt_PVAV)
croak("Argument $argnum is not an array.");
$1 = &$tmp;
AV *arrayValue = (AV*)SvRV($input);
int arrayLen = av_len(arrayLen);
for (int i=0; i<=arrayLen; ++i)
{
SV* scalarValue = av_fetch(arrayValue , i, 0);
$1->push_back( SvPV(*scalarValue, PL_na) );
}
};
Then from Perl you'd use array notation:
#myarray = (1, 2, 3, 4);
foo(\#myarray);