SWIG 杂记

| 分类 Development  | 标签 swig  jni  typemap 

用了两天 SWIG 来将 C++ 接口转成 Java 接口,在此简单记录一下用到 typemap 解决的几个问题,以备查询。关于 typemap ,可参考 官方文档

1 Example1 Return byte[] instead of std::string

1.1 C++ Header:

 1: #ifndef _EXAMPLE1_H_
 2: #define _EXAMPLE1_H_
 3: #include <string>
 4: class Example1
 5: {
 6: public:
 7:     Example1();
 8:     virtual ~Example1();
 9:     std::string GetString();
10: };
11: #endif /* _EXAMPLE1_H_ */

1.2 修改的 SWIG 接口文件:

 1: %module exampl1
 2: %{
 3: #include "example1.h"
 4: %}
 5: 
 6: %include <std_string.i>
 7: 
 8: %typemap(jstype) std::string GetString "byte[]";
 9: %typemap(jtype) std::string GetString "byte[]";
10: %typemap(jni) std::string GetString "jbyteArray";
11: %typemap(out) std::string GetString
12: {
13:     if ($1.empty())
14:     {
15:         return NULL;
16:     }
17: 
18:     $result = JCALL1(NewByteArray, jenv, $1.size());
19:     JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.size(), (const jbyte*)$1.c_str());
20: }
21: 
22: %include "example1.h"

1.3 生成的文件

1.3.1 Java:

1: public class Example1 {
2:   public Example1() {
3:     this(exampl1JNI.new_Example1(), true);
4:   }
5: 
6:   public byte[] GetString() {
7:     return exampl1JNI.Example1_GetString(swigCPtr, this);
8:   }
9: }

1.3.2 Java JNI:

1: public class exampl1JNI {
2:   public final static native long new_Example1();
3:   public final static native void delete_Example1(long jarg1);
4:   public final static native byte[] Example1_GetString(long jarg1, Example1 jarg1_);
5: }

1.3.3 JNI Code CPP:

 1: SWIGEXPORT jbyteArray JNICALL Java_exampl1JNI_Example1_1GetString(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_) {
 2:     jbyteArray jresult = 0 ;
 3:     Example1 *arg1 = (Example1 *) 0 ;
 4:     std::string result;
 5: 
 6:     (void)jenv;
 7:     (void)jcls;
 8:     (void)jarg1_;
 9:     arg1 = *(Example1 **)&jarg1;
10:     result = (arg1)->GetString();
11:     {
12:         if ((&result)->empty())
13:         {
14:             return NULL;
15:         }
16: 
17:         jresult = jenv->NewByteArray((&result)->size());
18:         jenv->SetByteArrayRegion(jresult, 0, (&result)->size(), (const jbyte*)(&result)->c_str());
19:     }
20:     return jresult;
21: }

2 Example2: 转引用为bytearrary:

2.1 C++

1: #ifndef _EXAMPLE1_H_
2: #define _EXAMPLE1_H_
3: #include <string>
4: class Example1
5: {
6: public:
7:     void GetString(std::string &out);
8: };
9: #endif /* _EXAMPLE1_H_ */

2.2 SWIG Interface

 1: %module exampl1
 2: %{
 3: #include "example2.h"
 4: %}
 5: 
 6: %include <std_string.i>
 7: 
 8: %typemap(jstype) std::string& out "byte[]";
 9: %typemap(jtype) std::string& out "byte[]";
10: %typemap(jni) std::string& out "jbyteArray";
11: %typemap(argout) std::string& out
12: {
13:     if ($1.empty())
14:     {
15:         return NULL;
16:     }
17: 
18:     $result = JCALL1(NewByteArray, jenv, $1.size());
19:     JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.size(), (const jbyte*)$1.c_str());
20: }
21: 
22: %include "example2.h"

2.3 Generated Codes:

2.3.1 Java Layer

 1: public class Example2 {
 2:   private long swigCPtr;
 3:   protected boolean swigCMemOwn;
 4: 
 5:   protected Example2(long cPtr, boolean cMemoryOwn) {
 6:     swigCMemOwn = cMemoryOwn;
 7:     swigCPtr = cPtr;
 8:   }
 9: 
10:   protected static long getCPtr(Example2 obj) {
11:     return (obj == null) ? 0 : obj.swigCPtr;
12:   }
13: 
14:   protected void finalize() {
15:     delete();
16:   }
17: 
18:   public synchronized void delete() {
19:     if (swigCPtr != 0) {
20:       if (swigCMemOwn) {
21:         swigCMemOwn = false;
22:         exampl1JNI.delete_Example2(swigCPtr);
23:       }
24:       swigCPtr = 0;
25:     }
26:   }
27: 
28:   public void GetString(byte[] out) {
29:     exampl1JNI.Example2_GetString(swigCPtr, this, SWIGTYPE_p_std__string.getCPtr(out));
30:   }
31: 
32:   public Example2() {
33:     this(exampl1JNI.new_Example2(), true);
34:   }
35: 
36: }

2.3.2 Java JNI

1: public class exampl2JNI {
2:   public final static native void Example2_GetString(long jarg1, Example2 jarg1_, byte[] jarg2);
3:   public final static native long new_Example2();
4:   public final static native void delete_Example2(long jarg1);
5: }

2.3.3 C++ JNI:

 1: SWIGEXPORT void JNICALL Java_exampl2JNI_Example2_1GetString(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jbyteArray jarg2) {
 2:     Example2 *arg1 = (Example2 *) 0 ;
 3:     std::string *arg2 = 0 ;
 4: 
 5:     (void)jenv;
 6:     (void)jcls;
 7:     (void)jarg1_;
 8:     arg1 = *(Example2 **)&jarg1;
 9:     arg2 = *(std::string **)&jarg2;
10:     if (!arg2) {
11:         SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "std::string & reference is null");
12:         return ;
13:     }
14:     (arg1)->GetString(*arg2);
15:     {
16:         if ((&arg2)->empty())
17:         {
18:             return NULL;
19:         }
20: 
21:         jresult = jenv->NewByteArray((&arg2)->size());
22:         jenv->SetByteArrayRegion(jresult, 0, (&arg2)->size(), (const jbyte*)(&arg2)->c_str());
23:     }
24: }

3 Example3: Director

3.1 C++

1: #include <string>
2: class Example3
3: {
4: public:
5:     virtual ~Example3() {}
6:     virtual void Updated(const std::string& o, const std::string& n) = 0;
7: };

3.2 SWIG Interface

 1: %module (directors="1") exampl3
 2: %{
 3: #include "example3.h"
 4: %}
 5: 
 6: %include <std_string.i>
 7: 
 8: %feature("director") Example3;
 9: 
10: %typemap(jtype) const std::string& o "byte[]"
11: %typemap(jtype) const std::string& n "byte[]"
12: %typemap(jstype) const std::string& o "byte[]"
13: %typemap(jstype) const std::string& n "byte[]"
14: %typemap(jni) const std::string& o "jbyteArray"
15: %typemap(jni) const std::string& n "jbyteArray"
16: 
17: %typemap(directorin,descriptor="[b") const std::string&
18: {
19:     if ($1.empty())
20:     {
21:         return NULL;
22:     }
23: 
24:     $input = JCALL1(NewByteArray, jenv, $1.size());
25:     JCALL4(SetByteArrayRegion, jenv, $result, 0, $1.size(), (const jbyte*)$1.c_str());
26: }
27: 
28: %typemap(in) const std::string& // we can add variable names to narrow down pattern matching.
29: {
30:     jbyte* dataPtr = (jbyte*)JCALL(env->GetByteArrayElements($input, 0));
31:     jsize  dataSize = JCALL11(env->GetArrayLength($input));
32:     if (olddata && dataSize)
33:     {
34:         $1 = std::string(dataPtr, dataSize);
35:     }
36: }
37: 
38: %include "example3.h"

3.3 Generated Codes:

3.3.1 Java

 1: public class Example3 {
 2:   private long swigCPtr;
 3:   protected boolean swigCMemOwn;
 4: 
 5:   protected Example3(long cPtr, boolean cMemoryOwn) {
 6:     swigCMemOwn = cMemoryOwn;
 7:     swigCPtr = cPtr;
 8:   }
 9: 
10:   protected static long getCPtr(Example3 obj) {
11:     return (obj == null) ? 0 : obj.swigCPtr;
12:   }
13: 
14:   public synchronized void delete() {
15:     if (swigCPtr != 0) {
16:       if (swigCMemOwn) {
17:         swigCMemOwn = false;
18:         throw new UnsupportedOperationException("C++ destructor does not have public access");
19:       }
20:       swigCPtr = 0;
21:     }
22:   }
23: 
24:   protected void swigDirectorDisconnect() {
25:     swigCMemOwn = false;
26:     delete();
27:   }
28: 
29:   public void swigReleaseOwnership() {
30:     swigCMemOwn = false;
31:     exampl3JNI.Example3_change_ownership(this, swigCPtr, false);
32:   }
33: 
34:   public void swigTakeOwnership() {
35:     swigCMemOwn = true;
36:     exampl3JNI.Example3_change_ownership(this, swigCPtr, true);
37:   }
38: 
39:   public void Updated(byte[] o, byte[] n) {
40:     exampl3JNI.Example3_Updated(swigCPtr, this, o, n);
41:   }
42: 
43:   public Example3() {
44:     this(exampl3JNI.new_Example3(), true);
45:     exampl3JNI.Example3_director_connect(this, swigCPtr, swigCMemOwn, true);
46:   }
47: 
48: }

3.3.2 Java JNI

 1: public class exampl3JNI {
 2:   public final static native void Example3_Updated(long jarg1, Example3 jarg1_, byte[] jarg2, byte[] jarg3);
 3:   public final static native long new_Example3();
 4:   public final static native void Example3_director_connect(Example3 obj, long cptr, boolean mem_own, boolean weak_global);
 5:   public final static native void Example3_change_ownership(Example3 obj, long cptr, boolean take_or_release);
 6: 
 7:   public static void SwigDirector_Example3_Updated(Example3 self, byte[] o, byte[] n) {
 8:     self.Updated(o, n);
 9:   }
10: 
11:   private final static native void swig_module_init();
12:   static {
13:     swig_module_init();
14:   }
15: }

3.3.3 C++ Wrapper

 1: void SwigDirector_Example3::Updated(std::string const &o, std::string const &n) {
 2:     JNIEnvWrapper swigjnienv(this) ;
 3:     JNIEnv * jenv = swigjnienv.getJNIEnv() ;
 4:     jobject swigjobj = (jobject) NULL ;
 5:     jbyteArray jo = 0 ;
 6:     jbyteArray jn = 0 ;
 7: 
 8:     if (!swig_override[0]) {
 9:         SWIG_JavaThrowException(JNIEnvWrapper(this).getJNIEnv(), SWIG_JavaDirectorPureVirtual, "Attempted to invoke pure virtual method Example3::Updated.");
10:         return;
11:     }
12:     swigjobj = swig_get_self(jenv);
13:     if (swigjobj && jenv->IsSameObject(swigjobj, NULL) == JNI_FALSE) {
14:         {
15:             if ((&o)->empty())
16:             {
17:                 return NULL;
18:             }
19: 
20:             jo = jenv->NewByteArray((&o)->size());
21:             jenv->SetByteArrayRegion($result, 0, (&o)->size(), (const jbyte*)(&o)->c_str());
22:         }
23:         {
24:             if ((&n)->empty())
25:             {
26:                 return NULL;
27:             }
28: 
29:             jn = jenv->NewByteArray((&n)->size());
30:             jenv->SetByteArrayRegion($result, 0, (&n)->size(), (const jbyte*)(&n)->c_str());
31:         }
32:         jenv->CallStaticVoidMethod(Swig::jclass_exampl3JNI, Swig::director_methids[0], swigjobj, jo, jn);
33:         if (jenv->ExceptionCheck() == JNI_TRUE) return ;
34:     } else {
35:         SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "null upcall object");
36:     }
37:     if (swigjobj) jenv->DeleteLocalRef(swigjobj);
38: }
39: 
40: 
41: #ifdef __cplusplus
42: extern "C" {
43: #endif
44: 
45: SWIGEXPORT void JNICALL Java_exampl3JNI_Example3_1Updated(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jbyteArray jarg2, jbyteArray jarg3) {
46:     Example3 *arg1 = (Example3 *) 0 ;
47:     std::string *arg2 = 0 ;
48:     std::string *arg3 = 0 ;
49: 
50:     (void)jenv;
51:     (void)jcls;
52:     (void)jarg1_;
53:     arg1 = *(Example3 **)&jarg1;
54:     {
55:         jbyte* dataPtr = (jbyte*)JCALL(env->GetByteArrayElements(jarg2, 0));
56:         jsize  dataSize = JCALL11(env->GetArrayLength(jarg2));
57:         if (olddata && dataSize)
58:         {
59:             arg2 = std::string(dataPtr, dataSize);
60:         }
61:     }
62:     {
63:         jbyte* dataPtr = (jbyte*)JCALL(env->GetByteArrayElements(jarg3, 0));
64:         jsize  dataSize = JCALL11(env->GetArrayLength(jarg3));
65:         if (olddata && dataSize)
66:         {
67:             arg3 = std::string(dataPtr, dataSize);
68:         }
69:     }
70:     (arg1)->Updated((std::string const &)*arg2,(std::string const &)*arg3);
71: }
72: 
73: SWIGEXPORT void JNICALL Java_exampl3JNI_swig_1module_1init(JNIEnv *jenv, jclass jcls) {
74:     int i;
75: 
76:     static struct {
77:         const char *method;
78:         const char *signature;
79:     } methods[1] = {
80:         {
81:             "SwigDirector_Example3_Updated", "(LExample3;[B[B)V"
82:         }
83:     };
84:     Swig::jclass_exampl3JNI = (jclass) jenv->NewGlobalRef(jcls);
85:     if (!Swig::jclass_exampl3JNI) return;
86:     for (i = 0; i < (int) (sizeof(methods)/sizeof(methods[0])); ++i) {
87:         Swig::director_methids[i] = jenv->GetStaticMethodID(jcls, methods[i].method, methods[i].signature);
88:         if (!Swig::director_methids[i]) return;
89:     }
90: }
91: 
92: 
93: #ifdef __cplusplus
94: }
95: #endif

上一篇     下一篇