我正在尝试使用Swig为一些内部C代码生成包装器,以便我可以将它重用于新的Android java项目并且遇到问题。我是Java和Swig的新手,所以请在任何回复的技术内容方面与我保持温和。
我正在尝试包装一个名为S_MESSAGE_STRUCT的C结构,其中包含的指针使得它的元素可以从java以及传统的C代码访问(设置,编写,读取等)。定义结构的我的C头文件如下所示,代码是我的实际代码(具有相同的问题)的示例和简化:
#ifndef MESSAGE_H_
#define MESSAGE_H_
#include <stdbool.h>
typedef struct
{
int* i1;
char* c1;
int len;
} *P_S_MESSAGE_STRUCT, S_MESSAGE_STRUCT;
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct);
#endif /* ndef MESSAGE_H_ */
我的C文件包含一个函数,它测试S_MESSAGE_STRUCT的int * i1元素,然后按如下方式写入c1和i1元素:
#include "message.h"
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct)
{
if (*p_s_mystruct->i1 == 1)
{
strcpy(p_s_mystruct->c1, "Hello from swig");
p_s_mystruct->c1[p_s_mystruct->len-1] = '\0';
*p_s_mystruct->i1 = strlen(p_s_mystruct->c1);
}
return true;
}
我使用的是.i文件,如下所示:
/* File : Message.i */
%module Message
%{
/* Includes the header in the wrapper code */
#include "../../../common/message/message.h"
%}
// Enable the JNI class to load the required native library.
%pragma(java) jniclasscode=%{
static {
try {
java.lang.System.loadLibrary("Message");
} catch (UnsatisfiedLinkError e) {
java.lang.System.err.println("native code library failed to load.\n" + e);
java.lang.System.exit(1);
}
}
%}
%include <typemaps.i>
%apply signed char * INOUT {char*};
typedef struct
{
int* i1;
char* c1;
int len;
} *P_S_MESSAGE_STRUCT, S_MESSAGE_STRUCT;
%include cpointer.i
bool t_func(P_S_MESSAGE_STRUCT p_s_mystruct);
%pointer_functions(int, intp);
我的java源函数如下(从默认的Android Activity编辑):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* typedef struct
{
int* i1;
char* c1;
int len;
}*P_MYSTRUCT, MYSTRUCT;
*/
S_MESSAGE_STRUCT p_my_struct = new S_MESSAGE_STRUCT();
int i1 = 1;
SWIGTYPE_p_int i1p = Message.new_intp();
Message.intp_assign(i1p, i1);
int len = 128;
byte[] c1 = new byte[len];
p_my_struct.setI1(i1p);
p_my_struct.setC1(c1);
p_my_struct.setLen(len);
Message.t_func(p_my_struct);
Integer i1_ret = Message.intp_value(i1p);
byte[] ret_c1 = p_my_struct.getC1();
String display = new String();
// !! display = Arrays.toString(ret_c1); // <<<< Gives Exception !!
display += i1_ret;
final EditText eText = (EditText) findViewById(R.id.editText1);
eText.setText(display);
}
所有内容都编译并构建正常,并且swig调用没有错误:
swig -java -package com.mobbu.Message -outdir ../../src/com/mobbu/Message/ -verbose Message.i
但是我知道我做错了什么,因为我在从java调用t_func()函数后不断出现问题。问题是多种多样的,包括在调用t_func()之后程序挂起但有时程序运行并显示输出OK。当显示输出时,由c1引起的贡献为空(它只给出输出“15”,没有“Hello from swig”的迹象。
我已经确定程序碎片源于对P_MYSTRUCT结构中指针元素i1和c1的写入,因为没有这些元素或没有写入没有问题(但是在结构中保留c1,i1元素) )。
我非常感谢有关如何实现我能够使用C结构的指针元素以及我在Message.i文件中出错的任何想法的帮助?我使用的是SWIG 3.0.2版。 谢谢,
麦克
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!编辑:
我发现如果我在message.i
中更改以下行%apply signed char * INOUT {char*};
到
%apply byte * INOUT {char*};
我的Swig调用会出现以下错误:
Warning 453: Can't apply (byte *INOUT). No typemaps are defined.
然而,生成的代码编译并运行正常,条件是我需要更改我的java应用程序代码,使用字符串而不是字节[]作为其c1版本。
我的新java代码是:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* typedef struct
{
int* i1;
char* c1;
int len;
}*P_MYSTRUCT, MYSTRUCT;*/
S_MESSAGE_STRUCT p_my_struct = new S_MESSAGE_STRUCT();
int i1 = 1;
SWIGTYPE_p_int i1p = Message.new_intp();
Message.intp_assign(i1p, i1);
int len = 128;
byte[] c1 = new byte[len];
String s1 = new String(c1);
p_my_struct.setI1(i1p);
p_my_struct.setC1(s1);
p_my_struct.setLen(len);
Message.t_func(p_my_struct);
SWIGTYPE_p_int pi1_ret = p_my_struct.getI1();
Integer i1_ret = Message.intp_value(pi1_ret);
String display = p_my_struct.getC1();
display += i1_ret;
final EditText eText = (EditText) findViewById(R.id.editText1);
eText.setText(display);
}
这是否说明我可能做错了什么?
感激地收到任何想法,
麦克
答案 0 :(得分:0)
我们也可以使用JavaCPP,它比作为作者的SWIG,IMO更容易使用。
使用此配置类:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
import org.bytedeco.javacpp.tools.*;
@Properties(value=@Platform(include="message.h", link="theMessageLibFile"), target="Message")
public class MessageConfig implements InfoMapper {
public void map(InfoMap infoMap) {
infoMap.put(new Info("P_S_MESSAGE_STRUCT").valueTypes("S_MESSAGE_STRUCT"));
}
}
并执行
$ javac -cp javacpp.jar MessageConfig.java
$ java -jar javacpp.jar MessageConfig
解析器生成此包装类:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
public class Message extends MessageConfig {
static { Loader.load(); }
public static class S_MESSAGE_STRUCT extends Pointer {
static { Loader.load(); }
public S_MESSAGE_STRUCT() { allocate(); }
public S_MESSAGE_STRUCT(int size) { allocateArray(size); }
public S_MESSAGE_STRUCT(Pointer p) { super(p); }
private native void allocate();
private native void allocateArray(int size);
@Override public S_MESSAGE_STRUCT position(int position) {
return (S_MESSAGE_STRUCT)super.position(position);
}
public native IntPointer i1(); public native S_MESSAGE_STRUCT i1(IntPointer i1);
public native @Cast("char*") BytePointer c1(); public native S_MESSAGE_STRUCT c1(BytePointer c1);
public native int len(); public native S_MESSAGE_STRUCT len(int len);
}
public static native @Cast("bool") boolean t_func(S_MESSAGE_STRUCT p_s_mystruct);
}
然后我们可以通过调用:
来构建本机库$ javac -cp javacpp.jar Message.java
$ java -jar javacpp.jar Message
按预期工作,例如:
import org.bytedeco.javacpp.*;
public class Main {
public static void main(String[] args) {
Message.S_MESSAGE_STRUCT my_struct = new Message.S_MESSAGE_STRUCT();
IntPointer i1 = new IntPointer(1).put(1);
BytePointer c1 = new BytePointer(128);
my_struct.i1(i1);
my_struct.c1(c1);
my_struct.len(c1.capacity());
Message.t_func(my_struct);
System.out.println(c1.getString());
}
}
输出以下内容:
Hello from JavaCPP