作为问题的后续跟进:Ruby with Swig: NameError: uninitialized constant
我正在尝试在红宝石中使用Qxt library(即QxtGlobalShortcut)。
正如建议:How can I call C++ functions from within ruby我创建了swig包装器,但是当我尝试使用生成的库时,我遇到了错误:
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中生成包装器:
由于qxtglobalshortcut.h内容无法被Swig解析,我创建了简化版本(包含我需要使用的所有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>'
答案 0 :(得分:1)
这个更棘手。我没有看到任何对字符串的引用,因此TypeError非常奇怪。
尽管如此,您可以使用此要点https://gist.github.com/phurni/5081001修补生成的.cxx文件。如您所见,它只是添加了一堆printf()
来跟踪对#initialize
的调用。您可以按照此模式跟踪它,也可以使用更多信息编辑您的问题,或更新的irb会话(显示跟踪)。
<强>更新强>
简而言之,您生成的Qxt lib和您使用的Qt ruby lib似乎不是由相同版本的SWIG生成的。这对于分离的lib来说不是问题,但是因为你的Qxt lib将与Qt lib互操作(你将ut参数传递给你自己的Qxt包装对象的Qt包装对象),两者必须被相同的版本包装(至少是次要的?)SWIG。
返回技术细节:
提出的例外来自1984年SWIG_ConvertPtr
的号召,后者又调用SWIG_Ruby_MangleStr
。此函数尝试在传递的参数中获取实例变量@__swigtype__
,该参数在代码中为ui
。这是为了能够键入check(在C ++端)传递的参数。看来这个变量是nil
(因为它来自Qt,不使用这样的变量而换行),而SWIG_Ruby_MangleStr
WANTS中的代码将它转换为String。
我不知道如何确定哪个版本的SWIG包装了现有的lib,如果你找到了一个,你可能会得到一个包装Qt lib的版本并使用该版本来包装你的Qxt lib。
另一种方法是使用已知版本的SWIG生成Qt库,并为您的Qxt lib执行相同的操作。