Typedef、Ruby 和 SWIG
Typedefs, Ruby and SWIG
我正在尝试为某些 C++ 类 生成一个 Ruby 包装器。生成成功,所有的方法都创建了,但是问题是很多C++的方法都是这样用的:
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
当我 运行 irb 中的一个方法 returns 一个计数时,我得到这样的结果:
irb(main):006:0> ngram.numNgrams(0)
=> #<SWIG::TYPE_p_Count:0x00000001c52280>
我期待一个数字...我尝试使用反射来查看我是否能以某种方式获得该值,但没有雪茄。有什么建议吗?
typedef 阻止 SWIG 确定 Counter
是它可以直接转换的未装箱类型。在没有附加信息的情况下,它将 Counter
视为抽象对象类型,只能由库中的函数生成和使用。
您需要告诉 SWIG Counter
等同于固有 long
或 long long
.
typemap
是 SWIG 的做法。此外,SWIG 语言本身提供 typedef
s 来声明 Counter
及其基础内在类型的等价性。
这是它的工作原理。您应该能够轻松地将其转化为您的问题的解决方案:
// hacking.i
%module hacking
%{
// "Simulation" of the header included verbatim in the glue code.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count foo(Count count) { return count; }
%}
// The typemaps...
%typemap(in) Count n {
#ifdef USE_LONGLONG_COUNTS
= ULL2INT($input);
#else
= ULONG2INT($input);
#endif
}
%typemap(out) Count {
#ifdef USE_LONGLONG_COUNTS
$result = ULL2NUM();
#else
$result = ULONG2NUM();
#endif
}
// Now tell SWIG about the type equivalences and function prototype.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count foo(Count count);
注意,如果定义了USE_LONGLONG_COUNTS
,你使用的Ruby必须支持long long
类型。并非所有人都这样做。
字体映射功能强大,有很多选项。您没有提供足够的信息来为您的问题提供更具体的解决方案。在您提供更多之前,引用 Ruby SWIG docs 几乎是所有可能的。
现在构建,制作一个文件:
# extconf.rb
require 'mkmf'
create_makefile('hacking')
并且(如果您需要 unsigned long
,请省略 -DUSE_LONGLONGCOUNTS
):
$ swig -c++ -DUSE_LONGLONG_COUNTS -ruby -o wrap.cpp hacking.i
$ ruby extconf.rb
$ make
compiling wrap.cpp
linking shared-object hacking.bundle
$ make install
/usr/bin/install -c -m 0755 hacking.bundle ...
$ irb
2.2.1 :001 > require 'hacking'
=> true
2.2.1 :002 > Hacking.foo(1234567890123454567)
=> 1234567890123454567
这很奇怪。
您确定 swig 是 "seeing" 您的 typedef
还是 Count
?因为否则 Count
只是 swig 不知道的某种类型,它将把它包装为指向 C 对象的指针,在这种情况下 swig 应该生成警告。
无论如何,我刚刚根据您的问题创建了一个示例,并像使用 swig 3.0.7 一样对其进行了测试,对我来说它按预期工作(没有类型映射):
dummy.i(另一种情况评论#define USE_LONGLONG_COUNTS
)
%module dummy
%inline %{
#define USE_LONGLONG_COUNTS
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count returnCount(Count count) { return count; }
%}
extconf.rb
require 'mkmf'
create_makefile('dummy')
为了编译和运行ruby,我这样做:
swig -c++ -ruby dummy.i
ruby extconf.rb
make
irb
那么在irb
,我可以做:
irb(main):001:0> require_relative 'dummy'
=> true
irb(main):002:0> Dummy.returnCount(2**64-1)
=> 18446744073709551615
irb(main):003:0> Dummy.returnCount(-1)
=> 18446744073709551615
irb(main):004:0> Dummy.returnCount(2**64)
TypeError: Expected argument 0 of type Count, but got Bignum 18446744073709551616
in SWIG method 'returnCount'
from (irb):4:in `returnCount'
from (irb):4
from /usr/bin/irb:12:in `<main>'
请注意,unsigned long long
和 unsigned long
在我的系统/编译器上都是 64 位的,我的 ruby 版本支持这些。如果这不是真的,也许转换可能无法工作,我不知道。
在任何情况下,问题都不是 typedef
造成的,正如另一个答案中所声称的那样。
我正在尝试为某些 C++ 类 生成一个 Ruby 包装器。生成成功,所有的方法都创建了,但是问题是很多C++的方法都是这样用的:
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
当我 运行 irb 中的一个方法 returns 一个计数时,我得到这样的结果:
irb(main):006:0> ngram.numNgrams(0)
=> #<SWIG::TYPE_p_Count:0x00000001c52280>
我期待一个数字...我尝试使用反射来查看我是否能以某种方式获得该值,但没有雪茄。有什么建议吗?
typedef 阻止 SWIG 确定 Counter
是它可以直接转换的未装箱类型。在没有附加信息的情况下,它将 Counter
视为抽象对象类型,只能由库中的函数生成和使用。
您需要告诉 SWIG Counter
等同于固有 long
或 long long
.
typemap
是 SWIG 的做法。此外,SWIG 语言本身提供 typedef
s 来声明 Counter
及其基础内在类型的等价性。
这是它的工作原理。您应该能够轻松地将其转化为您的问题的解决方案:
// hacking.i
%module hacking
%{
// "Simulation" of the header included verbatim in the glue code.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count foo(Count count) { return count; }
%}
// The typemaps...
%typemap(in) Count n {
#ifdef USE_LONGLONG_COUNTS
= ULL2INT($input);
#else
= ULONG2INT($input);
#endif
}
%typemap(out) Count {
#ifdef USE_LONGLONG_COUNTS
$result = ULL2NUM();
#else
$result = ULONG2NUM();
#endif
}
// Now tell SWIG about the type equivalences and function prototype.
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count foo(Count count);
注意,如果定义了USE_LONGLONG_COUNTS
,你使用的Ruby必须支持long long
类型。并非所有人都这样做。
字体映射功能强大,有很多选项。您没有提供足够的信息来为您的问题提供更具体的解决方案。在您提供更多之前,引用 Ruby SWIG docs 几乎是所有可能的。
现在构建,制作一个文件:
# extconf.rb
require 'mkmf'
create_makefile('hacking')
并且(如果您需要 unsigned long
,请省略 -DUSE_LONGLONGCOUNTS
):
$ swig -c++ -DUSE_LONGLONG_COUNTS -ruby -o wrap.cpp hacking.i
$ ruby extconf.rb
$ make
compiling wrap.cpp
linking shared-object hacking.bundle
$ make install
/usr/bin/install -c -m 0755 hacking.bundle ...
$ irb
2.2.1 :001 > require 'hacking'
=> true
2.2.1 :002 > Hacking.foo(1234567890123454567)
=> 1234567890123454567
这很奇怪。
您确定 swig 是 "seeing" 您的 typedef
还是 Count
?因为否则 Count
只是 swig 不知道的某种类型,它将把它包装为指向 C 对象的指针,在这种情况下 swig 应该生成警告。
无论如何,我刚刚根据您的问题创建了一个示例,并像使用 swig 3.0.7 一样对其进行了测试,对我来说它按预期工作(没有类型映射):
dummy.i(另一种情况评论#define USE_LONGLONG_COUNTS
)
%module dummy
%inline %{
#define USE_LONGLONG_COUNTS
#ifdef USE_LONGLONG_COUNTS
typedef unsigned long long Count; /* a count of something */
#else
typedef unsigned long Count; /* a count of something */
#endif
Count returnCount(Count count) { return count; }
%}
extconf.rb
require 'mkmf'
create_makefile('dummy')
为了编译和运行ruby,我这样做:
swig -c++ -ruby dummy.i
ruby extconf.rb
make
irb
那么在irb
,我可以做:
irb(main):001:0> require_relative 'dummy'
=> true
irb(main):002:0> Dummy.returnCount(2**64-1)
=> 18446744073709551615
irb(main):003:0> Dummy.returnCount(-1)
=> 18446744073709551615
irb(main):004:0> Dummy.returnCount(2**64)
TypeError: Expected argument 0 of type Count, but got Bignum 18446744073709551616
in SWIG method 'returnCount'
from (irb):4:in `returnCount'
from (irb):4
from /usr/bin/irb:12:in `<main>'
请注意,unsigned long long
和 unsigned long
在我的系统/编译器上都是 64 位的,我的 ruby 版本支持这些。如果这不是真的,也许转换可能无法工作,我不知道。
在任何情况下,问题都不是 typedef
造成的,正如另一个答案中所声称的那样。