SWIG与C++模板:未定义符号

4

我使用C++模板和SWIG遇到了问题。

当我尝试导入我的模块时,出现错误:

ImportError: ./_simple.so: undefined symbol: _Z9double_itIiET_S0_

我将使用SWIG 1.3来进行翻译。
下面是一个简单的例子,展示了问题:
//file: simple.h
template <typename T>
T double_it (T a);

//file: simple.cc
template <typename T>
T double_it (T a) {
  return (2 * a);
}

//file: simple.i
%module "simple"

%{
  #include "simple.h"
%}

%include "simple.h"

%template(int_double_it) double_it <int>;
%template(float_double_it) double_it <float>;

#file: setup.py
from distutils.core import setup, Extension
simple_module = Extension('_simple',
                          sources=['simple.i', 'simple.cc'],
                          swig_opts=['-c++'],
                          )
setup (name = 'simple',
       ext_modules = [simple_module],
       py_modules = ["simple"],
       )

然后使用以下命令进行构建:
python setup.py build

如果我将simple.cc的内容包含在simple.i中,并从setup.py中删除对simple.cc的引用,则一切都正常,但是当事情变得更加复杂时,这并不是一个真正的解决方案。
接下来,我会举一个相似但不使用模板且运行正常的反例。
//file: simple.h
int double_it (int a);

//file: simple.cc
int double_it (int a) {
  return (2 * a);
}

//file: simple.i
//Same as before but with %template statements removed.
%module "simple"

%{
  #include "simple.h"
%}

%include "simple.h"

#file: setup.py
#Identical to previous example.
1个回答

3
通常,模板是在头文件中定义而不是在cc文件中定义。根据您的设置,编译器无法找到/编译模板的实现代码。您需要更改代码组织结构,以便模板实现代码可用:
//file: simple.hh
template <typename T>
T double_it (T a) {
  return (2 * a);
}

//file: simple.i
%module "simple"

%{
  #include "simple.hh"
%}

%include "simple.hh" // include it directly into here

%template(int_double_it) double_it <int>;
%template(float_double_it) double_it <float>;

#file: setup.py
from distutils.core import setup, Extension
simple_module = Extension('_simple',
                          sources=['simple.i', 'simple.hh'],
                          swig_opts=['-c++'],
                         )
setup (name = 'simple',
       ext_modules = [simple_module],
       py_modules = ["simple"],
       )

我很感谢您提供的示例,虽然它是简化的,但是它说明了问题。您不需要直接包含实现(但是您需要包含它),但是您必须向SWIG编译器提供一些实现,即使它是一个简化版本。
以上内容应该可以帮助您开始。

我删掉了头文件以使代码更简短。也许我应该把它留下来,这样看起来更正常。如果你用包含头文件的语句替换我写的两个地方 "template <typename T> T double_it (T a);",你会得到类似于你的代码。主要区别在于你现在在接口文件中包含了 double_it 的实现,因此不需要链接。如果我这样做,我也可以让它工作,但是如果实现在单独的 .cc 文件中,我遇到了麻烦。 - Ben Reynwar
我在我的示例中添加了一个头文件,使其看起来更正常。 - Ben Reynwar
你真的必须将实现放在头文件中,以便编译器能够找到它并生成所需的版本。唯一的替代方法是在.cc文件中显式实例化模板,以确保存在所需的实例化(以确保编译器生成所需的版本,并且在链接时可用)。“template class double_it<int>; template class double_it<float>;”你遇到的问题实际上是关于C++和模板实例化的一般性问题,而不是SWIG特定的问题。 - lefticus

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