Ruby 和 Swig:TypeError:无法将 nil 转换为 String [英] Ruby and Swig: TypeError: can't convert nil into String

查看:47
本文介绍了Ruby 和 Swig:TypeError:无法将 nil 转换为 String的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为问题的后续:Ruby with Swig: NameError: uninitialized constant

我正在尝试使用 Qxt 库(即 QxtGlobalShortcut) 在 ruby​​ 中.

I'm trying to use Qxt library (namely QxtGlobalShortcut) in the ruby.

如上所示:如何从在 ruby​​ 中,我创建了 swig 包装器,但是在尝试使用生成的库时,我被困住了错误:

As suggested on: How can I call C++ functions from within ruby I created swig wrapper, however when trying to use generated library I'm stuck with error:

irb(main):005:0> shortcut = QxtGlobalShortcut::QxtGlobalShortcut.new ui
TypeError: can't convert nil into String
    from (irb):5:in `initialize'
    from (irb):5:in `new'
    from (irb):5
    from /usr/bin/irb:12:in `<main>'

我的完整 irb 会话输出:

My full irb session output:

$ irb
irb(main):001:0> require 'Qt4'
=> true
irb(main):002:0> require 'QxtGlobalShortcut'
=> true
irb(main):003:0> app = Qt::Application.new ARGV
=> #<Qt::Application:0x00000002e02598 objectName="irb">
irb(main):004:0> ui = Qt::Widget.new
=> #<Qt::Widget:0x00000002f9e2a8 objectName="", x=0, y=0, width=640, height=480>
irb(main):005:0> shortcut = QxtGlobalShortcut::QxtGlobalShortcut.new ui
TypeError: can't convert nil into String
    from (irb):5:in `initialize'
    from (irb):5:in `new'
    from (irb):5
    from /usr/bin/irb:12:in `<main>'

我使用以下内容在 swig 中生成包装器:

I used following to generate the wrapper in swig:

由于 Swig 无法解析 qxtglobalshortcut.h 内容,我创建了简化版本(包含我需要使用的所有 API)和内容:

As qxtglobalshortcut.h contents were not parsable by Swig, I created the simplified version (containg all the API that I need to use) with the contents:

#ifndef QXTGLOBALSHORTCUT_H
#define QXTGLOBALSHORTCUT_H

#include "qxtglobal.h"
#include <QObject>
#include <QKeySequence>

class QxtGlobalShortcut : public QObject
{

public:
    explicit QxtGlobalShortcut(QObject* parent);
    explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0);
    virtual ~QxtGlobalShortcut();

    QKeySequence shortcut() const;
    bool setShortcut(const QKeySequence& shortcut);

    bool isEnabled() const;

};

#endif // QXTGLOBALSHORTCUT_H

其余的都非常标准:

$ cat QxtGlobalShortcut.i
%module QxtGlobalShortcut
%{
/* Includes the header in the wrapper code */
#include "/usr/include/QxtGui/QxtGlobalShortcut"
%}

/* Parse the header file to generate wrappers */
%include "qxtglobalshortcut.h"

$ cat extconf.sh
require 'mkmf'
dir_config('QxtCore')
dir_config('QxtGui')
dir_config('QtCore')
dir_config('QtGui')
create_makefile('QxtGlobalShortcut')

$ cat wrapper.sh
swig -c++ -ruby QxtGlobalShortcut.i
ruby extconf.rb --with-QxtCore-include=/usr/include/QxtCore/ --with-QxtGui-include=/usr/include/QxtGui/ --with-QtCore-include=/usr/include/QtCore/ --with-QtGui-include=/usr/include/QtGui/
make 
sudo make install

有关 swig 生成的输出,请参阅:QxtGlobalShortcut_wrap.cxx.

For the swig generated output, see: QxtGlobalShortcut_wrap.cxx.

知道如何修复它吗?谢谢.

Any idea how to fix it? Thanks.

更新:

基于@PascalHurni扩展日志差异提供irb输出:

Providing the irb output based on @PascalHurni extended logging diff:

$ irb
irb(main):001:0> require 'Qt4'
=> true
irb(main):002:0> require 'QxtGlobalShortcut'
=> true
irb(main):003:0> app = Qt::Application.new ARGV                                                                                                                   
=> #<Qt::Application:0x00000001d79d98 objectName="irb">                                                                                                           
irb(main):004:0> ui = Qt::Widget.new                                                                                                                              
=> #<Qt::Widget:0x00000001f16818 objectName="", x=0, y=0, width=640, height=480>                                                                                  
irb(main):005:0> shortcut = QxtGlobalShortcut::QxtGlobalShortcut.new ui                                                                                           
_wrap_new_QxtGlobalShortcut ENTERING with 0 arguments                                                                                                             
TypeError: can't convert nil into String
    from (irb):5:in `initialize'
    from (irb):5:in `new'
    from (irb):5
    from /usr/bin/irb:12:in `<main>'

此外,我看到 argc 似乎有问题,因此发布 make 输出(不确定是否有帮助):

Moreover, I see there seems to be problem with argc, therefor posting make output (not sure if that helps):

creating Makefile
g++ -I. -I/usr/include/x86_64-linux -I/usr/include/ruby/backward -I/usr/include -I. -I/usr/include/QtGui/ -I/usr/include/QtCore/ -I/usr/include/QxtGui/ -I/usr/include/QxtCore/    -fPIC -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -mtune=generic -fPIC -m64 -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -mtune=generic -o QxtGlobalShortcut_wrap.o -c QxtGlobalShortcut_wrap.cxx
QxtGlobalShortcut_wrap.cxx: In function ‘void SWIG_Ruby_define_class(swig_type_info*)’:
QxtGlobalShortcut_wrap.cxx:1517:9: warning: variable ‘klass’ set but not used [-Wunused-but-set-variable]
QxtGlobalShortcut_wrap.cxx: In function ‘void SWIG_InitializeModule(void*)’:
QxtGlobalShortcut_wrap.cxx:2206:21: warning: statement has no effect [-Wunused-value]
QxtGlobalShortcut_wrap.cxx: In function ‘VALUE _wrap_new_QxtGlobalShortcut(int, VALUE*, VALUE)’:
QxtGlobalShortcut_wrap.cxx:1973:75: warning: ‘argc’ is used uninitialized in this function [-Wuninitialized]
rm -f QxtGlobalShortcut.so
g++ -shared -o QxtGlobalShortcut.so QxtGlobalShortcut_wrap.o -L. -L/usr/lib64 -L. -Wl,-z,relro -rdynamic -Wl,-export-dynamic  -m64  -lruby  -lpthread -lrt -ldl -lcrypt -lm   -lc
/usr/bin/mkdir -p /usr/local/lib64/ruby/site_ruby
/usr/bin/install -c -m 0755 QxtGlobalShortcut.so /usr/local/lib64/ruby/site_ruby

有什么想法吗?

更新 2:

基于@PascalHurni 扩展日志差异(版本 2)提供 irb 输出:

Providing the irb output based on @PascalHurni extended logging diff (version 2):

$ irb
irb(main):001:0> require 'Qt4'
=> true
irb(main):002:0> require 'QxtGlobalShortcut'
=> true
irb(main):003:0> app = Qt::Application.new ARGV 
=> #<Qt::Application:0x000000017b4e30 objectName="irb">
irb(main):004:0> ui = Qt::Widget.new
=> #<Qt::Widget:0x00000001952940 objectName="", x=0, y=0, width=640, height=480>
irb(main):005:0> shortcut = QxtGlobalShortcut::QxtGlobalShortcut.new ui
_wrap_new_QxtGlobalShortcut ENTERING with 1 arguments
_wrap_new_QxtGlobalShortcut before ptr convert for _wrap_new_QxtGlobalShortcut__SWIG_0 TYPE=12
TypeError: can't convert nil into String
    from (irb):5:in `initialize'
    from (irb):5:in `new'
    from (irb):5
    from /usr/bin/irb:12:in `<main>'

推荐答案

这个比较棘手.我没有看到任何对字符串的引用,所以 TypeError 真的很奇怪.

This one is more tricky. I don't see any reference to a string, so the TypeError is really weird.

尽管如此,您可以使用此要点修补生成的 .cxx 文件 https://gist.github.com/phurni/5081001 .如您所见,它只是添加了一堆 printf() 来跟踪对 #initialize 的调用.您可以按照此模式进行跟踪,也可以使用更多信息或更新的 irb 会话(显示跟踪)来编辑您的问题.

Nonetheless, you may patch the generated .cxx file with this gist https://gist.github.com/phurni/5081001 . As you see it simply adds a bunch of printf() to trace the call to #initialize. You may follow this pattern to track it down, maybe editing your question with some more info, or the updated irb session (showing the trace).

更新

简而言之,您生成的 Qxt 库和您使用的 Qt ruby​​ 库似乎不是由同一版本的 SWIG 生成的.这对于分离的库来说不是问题,但是因为您的 Qxt 库将与 Qt 库互操作(您将作为 Qt 包装对象的 ui 参数传递给您自己的 Qxt 包装对象),两者必须由相同版本包装(至少是未成年人?)的 SWIG.

To make it short, it seems that the Qxt lib you generate and the Qt ruby lib you use are not generated by the same version of SWIG. This wouldn't be a problem for separated libs, but because your Qxt lib will interop with the Qt lib (you pass the ui argument which is a Qt wrapped object to your own Qxt wrapped object), both MUST be wrapped by the same version (at least the minor?) of SWIG.

回到技术细节:引发的异常来自第 1984 行对 SWIG_ConvertPtr 的调用,该调用又调用 SWIG_Ruby_MangleStr.此函数尝试在代码中的 ui 传递的参数上获取实例变量 @__swigtype__.这是为了能够对传递的参数进行类型检查(在 C++ 端).看起来这个变量是nil(因为它来自Qt,没有使用这样的变量进行了不同的包装),并且SWIG_Ruby_MangleStr 中的代码想要将其转换为字符串.

Back to technical detail: The exception raised comes from the call of SWIG_ConvertPtron line 1984 which in turn calls SWIG_Ruby_MangleStr. This function tries to get an instance variable @__swigtype__ on the passed argument which is ui in your code. This is to be able to type check (on the C++ side) the passed argument. It seems that this variable is nil (because it comes from Qt wrapped differently without using such a variable), and the code in SWIG_Ruby_MangleStr WANTS to convert it to a String.

我不知道如何确定哪个版本的 SWIG 包装了现有的库,如果您找到了,您可能会得到包装 Qt 库的那个版本,并使用该版本来包装您的 Qxt 库.

I don't know a way to determine which version of SWIG wrapped an existing lib, if you find one, you may get the one that wrapped the Qt lib and use that version to wrap your Qxt lib.

另一种方法是使用已知版本的 SWIG 生成 Qt 库,并为您的 Qxt 库执行相同操作.

The other way is to generate the Qt libs with a known version of SWIG and do the same for your Qxt lib.

这篇关于Ruby 和 Swig:TypeError:无法将 nil 转换为 String的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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