3

I am trying to generate Perl packages for some C++ classes (which may use templates), and facing this weird issue that the derived class object is unable to call the base class method, which it inherited in C++ class publicly.

After reading the swig 4.0 manual, I was able to setup my classes (including template ones) and compile them properly sans errors. I got to know how to order them and how to separate the modules in order to get them compiled properly.

Somehow the derived class object, when used in perl, is unable to access base class method - and here is where I need some help. If I look at the object dump (using objdump -t command), I see that the base_hello() method is still undefined but can't seem to figure out why?

I tried to link it explicitly with the DerivedClass.so file but to no avail.

Note that I was able to make the same thing work but sans the templates. I was able to execute the base class method from the derived class object, in my Perl script.

Can anyone point me in a direction where I could investigate further? Currently I am not able to find any related information on internet for my use case i.e. unable to execute base class method in Perl.

If this problem interests you, please find the files used below to do this small test:

Perl Program throws undefined symbol error:

20190901 03:25 [compuser@lenovoe470:template-base-class]$  perl testDerivedClass.pl

Hello from derived class
perl: symbol lookup error: /home/compuser/mystuff/study/ace/swig-with-ace/template-base-class/BaseClass.so: undefined symbol: _ZN9BaseClassIiE10base_helloEi

20190901 03:25 [compuser@lenovoe470:template-base-class]$  

Baseclass.i

%module BaseClass
%{
#include "BaseClass.h"
%}

%include "BaseClass.h"
%template(intBaseClass) BaseClass< int > ;

Derivedclass.i

%module DerivedClass

%import "BaseClass.i"

%{
#include "DerivedClass.h"
%}

%include "DerivedClass.h"

Baseclass.h

#ifndef BC__
#define BC__

#include <iostream>

template <class T>
class BaseClass {
  public:
    void base_hello(T value);
};

#endif /* BC__ */

Baseclass.cpp

#include "BaseClass.h"
template <class T>
void BaseClass<T>::base_hello(T value) {
  std::cerr << "Hello from base class: " << value << "\n";
}

Derivedclass.h

#ifndef __DC_
#define __DC_

#include "BaseClass.h"
class DerivedClass : public BaseClass <int> {
  public:
    void derived_hello();
};

#endif /* __DC_ */

Derivedclass.cpp

#include "DerivedClass.h"

void DerivedClass::derived_hello() {
  std::cerr << "Hello from derived class\n";
}

testDerivedClass.pl

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;
use DerivedClass;

my $obj = new DerivedClass::DerivedClass();

$obj->derived_hello();
$obj->base_hello();

__END__

UPDATE: Adding compilation commands

#### For Base Class
/usr/local/bin/swig -c++ -perl5 BaseClass.i
g++ -std=c++11 -c -fPIC `perl -MConfig -e 'print join(" ", @Config{qw(ccflags optimize cccdlflags)}, "-I$Config{archlib}/CORE")'` -D_GNU_SOURCE  -L.  BaseClass.cpp BaseClass_wrap.cxx
g++ -std=c++11 -lstdc++ `perl -MConfig -e 'print $Config{lddlflags}'` -L.  BaseClass.o BaseClass_wrap.o -o BaseClass.so

#### For Derived Class
/usr/local/bin/swig -c++ -perl5 DerivedClass.i
g++ -std=c++11 -c -fPIC `perl -MConfig -e 'print join(" ", @Config{qw(ccflags optimize cccdlflags)}, "-I$Config{archlib}/CORE")'` -D_GNU_SOURCE  -L.  DerivedClass.cpp DerivedClass_wrap.cxx
g++ -std=c++11 -lstdc++ `perl -MConfig -e 'print $Config{lddlflags}'` -L.  DerivedClass.o DerivedClass_wrap.o -o DerivedClass.so
User9102d82
  • 1,172
  • 9
  • 19
  • How did you compile your extension? – Håkon Hægland Sep 01 '19 at 10:16
  • 1
    @HåkonHægland - I have now added the compilation commands used to compile this. Please have a look. – User9102d82 Sep 01 '19 at 11:04
  • I am on Ubuntu 19.04, swig version 3.0.12. Using your provided compilation commands, I can compile the extension and then run the script `testDerivedClass.pl` provided I add the current directory to the include path: `perl -I. testDerivedClass.pl`. It *does not* produce the error `undefined symbol: _ZN9BaseClassIiE10base_helloEi`. However this type of error can occur if you use `gcc` instead of `g++` to compile the extension – Håkon Hægland Sep 01 '19 at 11:22
  • @HåkonHægland: I just tried what you explained but I still seem to get the same error. Can you share your exact logs of what you tried out? that would be really helpful. Moreover, did you see the output of the second method call in Perl script? – User9102d82 Sep 01 '19 at 11:27
  • Sure! But note that even if I do not get `undefined symbol: _ZN9BaseClassIiE10base_helloEi` I still get an error: `RuntimeError Usage: intBaseClass_base_hello(self,value);`, I will check out that error first.. – Håkon Hægland Sep 01 '19 at 11:31
  • 1
    That is because the second method (base_hello) needs an int value, so I used it like base_hello(int(5)) or just base_hello(5). – User9102d82 Sep 01 '19 at 11:32
  • Ok, then I see the problem. Now after doing: `$obj->base_hello(1)` in `testDerivedClass.pl` I also get the error: `undefined symbol: _ZN9BaseClassIiE10base_helloEi`. I will check further to see if I can find the problem! – Håkon Hægland Sep 01 '19 at 11:35
  • Yes. That is the issue here. Note that this works if we remove the templates. I was able to make the same inheritance case work. But I need to have the template for something which I am trying to do. :( – User9102d82 Sep 01 '19 at 11:38

1 Answers1

2

You need to force instantiation of the template class BaseClass<int> in order for the symbol BaseClass<int>::base_hello(int) to be defined in BaseClass.so. So add the following line to the bottom of BaseClass.cpp:

template class BaseClass<int>;  // <-- explicitly instantiate the template specialization for int

and then recompile everything and it should work. See also this post

Håkon Hægland
  • 39,012
  • 21
  • 81
  • 174
  • 1
    Hi Hakon - Yes this does the trick. Now I am able to make it work as expected. Thank you so much for taking out your time to help me and the community. I really appreciate it. Cheers! – User9102d82 Sep 01 '19 at 15:31