Swig将C++转为Perl:无法执行基类继承的公共方法

3
我尝试为一些C++类(可能使用模板)生成Perl包,但遇到了一个奇怪的问题,派生类对象无法调用基类方法,在C++类中公开继承的方法。
阅读swig 4.0手册后,我成功设置了我的类(包括模板类)并正确地编译它们,没有错误。我知道如何对它们进行排序以及如何分离模块,以便正确地编译它们。
不知何故,当在perl中使用派生类对象时,它无法访问基类方法 - 这就是我需要帮助的地方。如果我查看对象转储(使用objdump -t命令),我会发现base_hello()方法仍然未定义,但似乎无法弄清楚原因?
我尝试将其显式链接到DerivedClass.so文件,但没有成功。
请注意,我能够使相同的程序工作,但没有使用模板。在我的Perl脚本中,我能够从派生类对象执行基类方法。
有人可以指导我进一步调查的方向吗?目前,我无法在互联网上找到与我的用例相关的任何相关信息,即无法在Perl中执行基类方法。
如果您对此问题感兴趣,请在下面找到用于执行此小测试的文件:
Perl程序引发未定义的符号错误:
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__

更新: 添加编译命令

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

你是如何编译你的扩展的? - Håkon Hægland
1
@HåkonHægland - 我现在已经添加了用于编译此代码的编译命令。请查看。 - User9102d82
我使用的是Ubuntu 19.04,swig版本为3.0.12。使用您提供的编译命令,我可以编译扩展程序,然后运行脚本testDerivedClass.pl,只需将当前目录添加到包含路径中:perl -I. testDerivedClass.pl。它不会产生错误undefined symbol: _ZN9BaseClassIiE10base_helloEi。但是,如果您使用gcc而不是g++来编译扩展程序,则可能会出现此类错误。 - Håkon Hægland
1
这是因为第二个方法(base_hello)需要一个整数值,所以我使用了 base_hello(int(5)) 或只是 base_hello(5)。 - User9102d82
是的,这就是问题所在。请注意,如果我们删除模板,它可以正常工作。我已经成功地实现了相同的继承案例。但是我需要模板来完成我正在尝试做的事情。 :( - User9102d82
显示剩余3条评论
1个回答

2
您需要强制实例化模板类 BaseClass<int>,以便在BaseClass.so中定义符号BaseClass<int>::base_hello(int)。因此,请在BaseClass.cpp的底部添加以下行:
template class BaseClass<int>;  // <-- explicitly instantiate the template specialization for int

然后重新编译所有内容,它应该就可以工作了。另请参见此篇文章

1
嗨Hakon - 是的,这个方法很有效。现在我能够按照预期使它工作了。非常感谢您抽出时间来帮助我和社区。我真的很感激。干杯! - User9102d82

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接