0

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

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

正如所建议的那样:我如何从创建swig包装器的 ruby​​ 中调用 C++ 函数,但是当尝试使用生成的库时,我遇到了错误:

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 会话输出:

$ 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 中生成包装器:

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

#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

知道如何解决吗?谢谢。

更新:

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

$ 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 输出(不确定是否有帮助):

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 输出:

$ 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>'
4

1 回答 1

1

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

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

更新

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

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

结论:

我不知道一种方法来确定哪个版本的 SWIG 包装了现有的 lib,如果你找到一个,你可能会得到一个包装 Qt lib 的版本并使用该版本来包装你的 Qxt lib。

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

于 2013-03-04T09:19:24.303 回答