修改SWIG接口文件以支持C void *和结构返回类型 [英] Modifying SWIG Interface file to Support C void* and structure return types

查看:66
本文介绍了修改SWIG接口文件以支持C void *和结构返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用SWIG为大量C API生成我的JNI层,我想知道以下情况的最佳实践是什么.以下内容不仅适用于SWIG,而且还适用于一般JNI.

I'm using SWIG to generate my JNI layer for a large set of C APIs and I was wondering what is the best practices for the below situations. The below not only pertain to SWIG but JNI in general.

当C函数返回指向Structures的指针时,应该大量使用SWIG接口文件(JNI逻辑)还是应该创建C包装函数来分片返回数据(即,包含各种数据元素的char数组)? 当C函数返回void *时,是否应该修改C API以返回实际的数据类型,无论是原始类型还是结构类型? 我不确定是否要添加大量逻辑并创建中间层(SWIG接口文件/JNI逻辑).有想法吗?

When C functions return pointers to Structures, should the SWIG interface file (JNI logic) be heavily used or should C wrapper functions be created to return the data in pieces (i.e. a char array that contains the various data elements)? When C Functions return void* should the C APIs be modified to return the actual data type, whether it be primitive or structure types? I'm unsure if I want to add a mass amount of logic and create a middle layer (SWIG interface file/JNI logic). Thoughts?

推荐答案

我过去的处理方法是编写尽可能少的代码以使其工作.当我必须编写代码以使其工作时,请按以下优先顺序进行编写:

My approach to this in the past has been to write as little code as possible to make it work. When I have to write code to make it work I write it in this order of preference:

  1. 在原始库中写为C或C ++ -每个人都可以使用此代码,而不必编写任何特定于Java或SWIG的内容(例如,在C ++中添加更多重载,添加C中有更多版本的函数,请使用SWIG知道的返回类型)

  1. Write as C or C++ in the original library - everyone can use this code, you don't have to write anything Java or SWIG specific (e.g. add more overloads in C++, add more versions of functions in C, use return types that SWIG knows about in them)

编写更多目标语言-提供胶水"将库的某些部分组合在一起.在这种情况下,它将是Java.

Write more of the target language - supply "glue" to bring some bits of the library together. In this case that would be Java.

这是否纯"并不重要.从我的角度来看,Java完全位于SWIG之外,或者作为SWIG接口文件的一部分. Java界面的用户应该无法区分两者.不过,在许多情况下,您都可以使用SWIG来避免重复.

It doesn't really matter if this is "pure" Java, outside of SWIG altogether, or as part of the SWIG interface file from my perspective. Users of the Java interface shouldn't be able to distinguish the two. You can use SWIG to help avoid repetition in a number of cases though.

通过SWIG类型图编写一些JNI .这很丑陋,如果您不熟悉它,容易出错,难以维护(可以说),并且仅对SWIG + Java有用.使用SWIG类型映射至少确实意味着您为每种包装类型只编写了一次.

Write some JNI through SWIG typemaps. This is ugly, error prone if you're not familiar with writing it, harder to maintain (arguably) and only useful to SWIG+Java. Using SWIG typemaps does at least mean you only write it once for every type you wrap.

相对于2,我更愿意这样做的时间是以下一项或多项:

The times I'd favour this over 2. is one or more of:

  1. 出现很多情况(节省重复编码)
  2. 我根本不了解目标语言,在这种情况下,使用该语言的C API可能比用该语言编写东西要容易
  3. 用户会期望的
  4. 否则就无法使用以前的样式.

基本上,我建议的这些准则是尝试为尽可能多的库用户提供功能,同时最大程度地减少您必须编写的额外的,目标语言特定的代码,并在必须编写时降低其复杂性

Basically these guidelines I suggested are trying to deliver functionality to as many users of the library as possible whilst minimising the amount of extra, target language specific code you have to write and reducing the complexity of it when you do have to write it.

对于sockaddr_in*的特定情况:

方法1

我要尝试做的第一件事是避免包装除了指向它的指针以外的任何东西.这是swig在默认情况下对SWIGTYPE_p_sockaddr_in所做的事情.您可以使用此未知"如果您要做的就是将它从一件事传递到另一件事,以容器的形式/作为成员等存储,例如,

The first thing I'd try and do is avoid wrapping anything more than a pointer to it. This is what swig does by default with the SWIGTYPE_p_sockaddr_in thing. You can use this "unknown" type in Java quite happily if all you do is pass it from one thing to another, store in containers/as a member etc., e.g.

public static void main(String[] argv) {
  Module.takes_a_sockaddr(Module.returns_a_sockaddr());
}

如果这样做不起作用,您可以在C中执行类似编写另一个函数的操作:

If that doesn't do the job you could do something like write another function, in C:

const char * sockaddr2host(struct sockaddr_in *in); // Some code to get the host as a string
unsigned short sockaddr2port(struct sockaddr_in *in); // Some code to get the port

在这种情况下,这并不好-使用地址族,我想避免使用它,因此您要处理一些复杂性(这就是为什么首先使用sockaddr_in的原因) ,但它不是Java特有的,语法也不是晦涩的,除此之外,这一切都会自动为您完成.

This isn't great in this case though - you've got some complexity to handle there with address families that I'd guess you'd rather avoid (that's why you're using sockaddr_in in the first place), but it's not Java specific, it's not obscure syntax and it all happens automatically for you besides that.

方法2

如果这还不够好,那么我会开始考虑编写Java的一些方法-您可以通过将SWIGTYPE_p_sockaddr_in类型隐藏为您自己的Java类型的私有成员来公开一个更好的接口,并且将对调用的返回包装在一些Java中,该函数可以为您构造类型,例如

If that still isn't good enough then I'd start to think about writing a little bit of Java - you could expose a nicer interface by hiding the SWIGTYPE_p_sockaddr_in type as a private member of your own Java type, and wrapping the call to the function that returns it in some Java that constructs your type for you, e.g.

public class MyExtension {
  private MyExtension() { }
  private SWIGTYPE_p_sockaddr_in detail;
  public static MyExtension native_call() {
    MyExtension e = new MyExtension();
    e.detail = Module.real_native_call();
    return e;
  }

  public void some_call_that_takes_a_sockaddr() {
    Module.real_call(detail);
  }
}

无需编写额外的SWIG,无需编写JNI.您可以使用%pragma(modulecode)通过SWIG进行此操作,以使其在SWIG实际生成的模块上全部重载-这对于Java用户来说可能更自然(看起来不算特例),并且实际上并没有任何复杂性. SWIG仍在努力,这只是为了避免在Java端重复编码而提供了一些改进.

No extra SWIG to write, no JNI to write. You could do this through SWIG using %pragma(modulecode) to make it all overloads on the actual Module SWIG generates - this feels more natural to the Java users probably (it doesn't look like a special case) and isn't really any more complex. The hardwork is being done by SWIG still, this just provides some polish that avoids repetitious coding on the Java side.

方法3

这基本上是

This would basically be the second part of my previous answer. It's nice because it looks and feels native to the Java users and the C library doesn't have to be modified either. In essence the typemap provides a clean-ish syntax for encapsulating the JNI calls for converting from what Java users expect to what C works with and neither side knows about the other side's outlook.

缺点是难以维护且很难调试.我的经验是,SWIG在类似这样的事情上有一个陡峭的学习曲线,但是一旦达到一个点,编写类型图就不需要花费太多精力,像这样,它们通过重用和封装C而为您提供了强大的功能. type-> Java类型映射非常有用且功能强大.

The downside though is that it is harder to maintain and really hard to debug. My experience has been that SWIG has a steep learning curve for things like this, but once you reach a point where it doesn't take too much effort to write typemaps like that the power they give you through re-use and encapsulation of the C type->Java type mapping is very useful and powerful.

如果您是团队中的一员,但只有一个真正了解SWIG界面的人,这句话就很重要:如果您被公交车撞到了怎么办?"影响整个项目. (不过,这可能会使您不愉快!)

If you're part of a team, but the only person who really understands the SWIG interface then that puts a big "what if you get hit by a bus?" factor on the project as a whole. (Probably quite good for making you unfirable though!)

这篇关于修改SWIG接口文件以支持C void *和结构返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆