使用 -DSWIGWORDSIZE64 时,SWIG Java 将 int64_t 转换为 jlong

SWIG Java convert int64_t to jlong when using -DSWIGWORDSIZE64

上下文

我有一个带有重载 intint64_t 的 C++ 代码,我需要将其包装到 Java

#include <cstdint>

int foo(int param);
int foo(int64_t param);
};

还有这一口

%{
#include <cstdint>
%}

%include "stdint.i"
%include "typemaps.i"

%ignore "";
%rename ("foo") foo(int);
%rename ("foo") foo(int64_t);

%include "foo.hpp";

海湾合作委员会

使用 GCC 时 int64_t 将被定义为 long int

grepc -rn "typedef.*INT64_TYPE" /lib/gcc
/lib/gcc/x86_64-linux-gnu/9/include/stdint-gcc.h:43:typedef __INT64_TYPE__ int64_t;

然后

gcc -dM -E -x c++ /dev/null | grep __INT64
#define __INT64_TYPE__ long int

所以我使用 -DSWIGWORDSIZE64 来避免 wrapper 类型错误的问题

grep "int64" -C 1 /usr/local/share/swig/4.0.1/stdint.i 
#if defined(SWIGWORDSIZE64)
typedef long int        int64_t;
#else
typedef long long int       int64_t;
#endif

到目前为止还不错(至少在 python 和 csharp 中),但是在 Java...

痛饮Java

in Java SWIG swig 似乎将 C++ long int 包装到 C Wrapper int(也将 2^64 截断为 2^32...) 参考:http://www.swig.org/Doc4.0/SWIGDocumentation.html#Java_default_primitive_type_mappings 来源:https://github.com/swig/swig/blob/master/Lib/java/typemaps.i

所以这两种方法将具有相同的原型 -> 我当前的问题

AFAIK java/typemaps.i nor java.swg 支持 SWIGWORDSIZE64 开关...

测试协议

重现问题(我使用的是 swig 4.0.1)

mkdir -p gen
swig -DSWIGWORDSIZE64 -I. -c++ -java -o gen/foo_java_wrap.cc -package com.google.Foo -module main -outdir gen foo.i

观察到

foo.hpp:9: Warning 516: Overloaded method baz(int64_t) ignored,
foo.hpp:8: Warning 516: using baz(int) instead.

cat gen/main.java
...
package com.google.Foo;

public class main {
  public static int baz(int param) {
    return mainJNI.baz__SWIG_0(param);
  }

}

预计

cat gen/main.java
...
package com.google.Foo;

public class main {
  public static int baz(int param) {
    return mainJNI.baz__SWIG_0(param);
  }
  public static int baz(long param) {
    return mainJNI.baz__SWIG_1(param);
  }
}

那么我该如何处理这个问题呢?

谢谢

编辑:你可以在这里找到这个例子:https://github.com/Mizux/swig_java (ed可以点徽章看logs/files)

一个丑陋的解决方法是使用SWIGWORDSIZE64,因此int64_t将被定义为long long 将被映射为 jlong。 参见:http://www.swig.org/Doc4.0/SWIGDocumentation.html#Java_default_primitive_type_mappings

BUT,在 C++ 扭曲文件中,您将有一些 long long 需要修补(例如使用 post 进程 sed -i -e 's/long long/int64_t/g') 否则编译失败,因为 long longint64_t (又名 long int

不是同一类型

您可以尝试提供自己的类型映射。


%include "stdint.i;"

#ifdef SWIGWORDSIZE64

%define PRIMITIVE_TYPEMAP(TYPE, JNITYPE, JTYPE)
%clear TYPE;
%typemap(jstype) TYPE "JTYPE";
%typemap(javain) TYPE "$javainput";
%typemap(jtype) TYPE "JTYPE";
%typemap(jni) TYPE "JNITYPE";
%typemap(in) TYPE %{  = (_ltype)&$input; %}
%typemap(freearg) TYPE "";
%typemap(out) TYPE %{ $result = ; %}
%typemap(javaout) TYPE %{ return $jnicall; %}

%enddef // PRIMITIVE_TYPEMAP

PRIMITIVE_TYPEMAP(long int, jlong, long);
PRIMITIVE_TYPEMAP(unsigned long int, jlong, long);
#undef PRIMITIVE_TYPEMAP

#endif // SWIGWORDSIZE64

因为您想重用 long long 类型映射:

#ifdef SWIGWORDSIZE64

%define PRIMITIVE_TYPEMAP(NEW_TYPE, TYPE)
%clear NEW_TYPE;
%apply TYPE { NEW_TYPE };
%enddef // PRIMITIVE_TYPEMAP

PRIMITIVE_TYPEMAP(long int, long long);
PRIMITIVE_TYPEMAP(unsigned long int, long long);
#undef PRIMITIVE_TYPEMAP

#endif // SWIGWORDSIZE64