我开始了解SWIG,SWIG的最新版本(v3.0)似乎可以处理我开箱即用的所有内容,包括C ++ 11的功能,但我已经打了一个关于将shared_ptr与我的导演课程一起使用时会遇到麻烦。
我能够让shared_ptr
能够很好地使用普通代理类,但是现在我的导演似乎不支持开箱即用。它给了我自动生成的类型SWIGTYPE_p_std__shared_ptrT_MyDataType_t
,并且正在生成一个损坏的接口,因为它没有使用代理类使用的相同类型。
我有一个简单的例子,说明我正在尝试做什么(在swig 3.0上使用swig -c++ -java Test.i
运行):
Test.i
%module(directors="1") test
%{
%}
%include <std_shared_ptr.i>
%shared_ptr(MyDataType)
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod();
};
%feature("director") CallbackBaseClass;
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() {};
};
基本上我要做的是在Java中扩展CallbackBaseClass
,我希望能够传递我的shared_ptr包装类型。非director类生成shared_ptr类型就好了。导向器类代理文件生成正确,但包装器中的SwigDirector_
方法引用了错误的类型。
似乎我可以通过在任何地方将SWIGTYPE_p_std__shared_ptrT_MyDataType_t
的类型更改为MyDataType
来手动修复文件,但我希望有更多swig知识的人可以回答这个问题,这样就可以正确生成
我得到的最好线索是here,但我仍在努力弄清楚如何正确使用这些类型的地图,尤其是shared_ptr
而不是基本原语。
更新:
文档says:
注意:目前不支持%shared_ptr和导演功能。
虽然没有说明原因。如果有充分理由不在董事中使用shared_ptr,我想知道这对于swig director是不可能的。看起来使用你在其他地方使用的相同类型是有意义的。我希望答案是有可能的。
答案 0 :(得分:6)
最新版本的SWIG文档现为:
“对
%shared_ptr
的支持有限,导演功能和成功程度因不同的目标语言而异。请通过提供改进补丁来帮助改善这种支持。”
为了使您的示例正常工作,我们似乎需要添加四个缺少的类型映射,directorin,directorout,javadirectorin和javadirectorout:
%module(directors="1") test
%include <std_shared_ptr.i>
%{
#include <memory>
#include <iostream>
%}
%shared_ptr(MyDataType)
%feature("director") CallbackBaseClass;
%typemap(javadirectorin) std::shared_ptr<MyDataType> "new $typemap(jstype, MyDataType)($1,true)";
%typemap(directorin,descriptor="L$typemap(jstype, MyDataType);") std::shared_ptr<MyDataType> %{
*($&1_type*)&j$1 = new $1_type($1);
%}
%typemap(javadirectorout) std::shared_ptr<MyDataType> "$typemap(jstype, MyDataType).getCPtr($javacall)";
%typemap(directorout) std::shared_ptr<MyDataType> %{
$&1_type tmp = NULL;
*($&1_type*)&tmp = *($&1_type*)&$input;
if (!tmp) {
SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "Attempt to dereference null $1_type");
return NULL;
}
$result = *tmp;
%}
%inline %{
class MyDataType {
public:
int value;
};
class NonDirectorClass {
public:
std::shared_ptr<MyDataType> TestMethod() { return std::make_shared<MyDataType>(); }
};
class CallbackBaseClass {
public:
virtual ~CallbackBaseClass() {};
virtual std::shared_ptr<MyDataType> GetDataFromJava() = 0;
};
void frobinate(CallbackBaseClass& cb) {
std::cout << "In C++: " << cb.GetDataFromJava()->value << "\n";
}
%}
即使您只在示例中使用了directorout case,仍然需要directorin typemap才能使director_connect中的查找成功,因为它取决于具有正确的描述符。
这四个类型图与功能中的in,javain和javaout类型图等效,但由于它们在导演中的作用而被逆转。
它们不够完整,无法处理所有情况,但它们适用于您的示例。描述符内的$typemap
调用需要比Ubuntu 14.04中包含的版本更新的SWIG 3版本 - 在我写的形式中,我测试的唯一版本是从主干中检出的。您可以手动编写描述符(这只是descriptor="LMyDataType;"
),但显然不那么通用。如上所述编写它的优点是它也能正确处理%rename
指令。这不会正确处理包,因此你也必须在这种情况下再次手动编写它。
我能够测试并运行该示例,我添加了以下run.java:
public class run extends CallbackBaseClass {
public MyDataType GetDataFromJava() {
MyDataType val = new MyDataType();
val.setValue(123);
return val;
}
public static void main(String[] argv) {
System.loadLibrary("test");
run r = new run();
System.out.println("In Java: " + r.GetDataFromJava().getValue());
test.frobinate(r);
}
}
编译并运行:
~/swig-trunk/preinst-swig -Wall -c++ -java test.i
clang++-3.6 -stdlib=libc++ -Wall -Wextra -std=c++1y test_wrap.cxx -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux -shared -fPIC
javac run.java
LD_LIBRARY_PATH=. java run
当跑的时候给了:
In Java: 123
In C++: 123
我猜想在带有shared_ptr
+导演的Java的情况下,使描述符正确的微妙之处可能是让这个“正常工作”的主要障碍。