0

As a follow up of the question: Ruby with Swig: NameError: uninitialized constant

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

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

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

I used following to generate the wrapper in swig:

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

The rest is pretty much standard:

$ 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

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

Any idea how to fix it? Thanks.

UPDATE:

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

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

Any ideas?

UPDATE 2:

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>'
Community
  • 1
  • 1
Peter Butkovic
  • 11,143
  • 10
  • 57
  • 81

1 Answers1

1

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

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).

UPDATE

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.

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.

Conclusion:

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.

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

Pascal Hurni
  • 376
  • 1
  • 7
  • thank you for your help. I just tried with extended logging. See the updated question. – Peter Butkovic Mar 04 '13 at 19:19
  • I updated the gist with some more trace and fixed the argc issue (my fault). Could you re-compile and run with this patch (against the original file) and replace your updated output in the question. Note that your issue is early as we are only in the SWIG dispatch function. From here it seems that the argument passed may have the wrong type (your ui ruby argument) but that seems strange. – Pascal Hurni Mar 05 '13 at 13:48