0

我有一个完全在头文件(HKnotVector.h)中实现的类。我还有一个 SWIG 接口文件 (HKnotVector.i),它定义了一些 std_vector.i 类型映射。HKnotVector.h 需要来自另一个文件 (common.h) 的定义。如果我将 common.h 的相关部分复制/粘贴到 HKnotVector.i 中,一切正常。

当我尝试#include "common.h"进入 HKnotVector.h 时,问题就来了。SWIG 和 python 能够构建扩展,但我收到以下警告:HKnotVector.h:7: Error: Nothing known about namespace 'util'

以下是 HKnotVector.h 的相关部分:

/* file HKnotVector.h */
#include "common.h"
#include <vector>
#include <iostream>

using namespace std;
using namespace util;

namespace hbs
{
    class HKnotVector
    {
        public:
        HKnotVector( uint degree, const DoubleVec &knots )
            : mDeg( degree ), mKnots( knots )
        {
            getKVecData( mKnots, mGroups, mReverseGroups, mMultipleCount );
        }
        // A lot of missing code
        protected:
        uint mDeg;
        DoubleVec mKnots;
        IntVec mGroups;
        IntVecVec mReverseGroups;
        IntVec mMultipleCount;
        void getKVecData( const DoubleVec &knots, IntVec &knot_groups,
                          IntVecVec &reverse_knot_groups, IntVec &multiple_counts ) const
        {
            // Do cool stuff
        }
    };
}

common.h的相关部分:

/* file common.h */
#include <iostream>
#include <vector>

typedef unsigned int uint;

using namespace std;

namespace util
{
    typedef std::vector< double > DoubleVec;
    typedef std::vector< int > IntVec;
    typedef std::vector< IntVec > IntVecVec;
    // A whole bunch of more stuff
}

HKnotVector.i 的全部内容:

/* file HKnotVector.i */
%module hbspy
%{
#include "HKnotvector.h"
%}

%include "std_vector.i"
namespace std {
    %template(IntVec)    vector<int>;
    %template(DoubleVec) vector<double>;
    %template(IntVecVec) vector<vector<int> >;
}

%include "HKnotvector.h"

最后我有一个尝试创建 HKnotVector 实例的测试 python 文件:

import hbspy

# Test HKnotVector
py_knots = [0., 0., 0., .25, .5, .75, 1., 1., 1.]
knots = hbspy.DoubleVec(py_knots)
print('knots object: %s\n\n\n' % knots)
kv = hbspy.HKnotVector(2, knots)

当我编译使用swig -c++ -python HKnotVector.i然后构建扩展并运行测试文件时,这就是我得到的:

knots object: <hbspy.DoubleVec; proxy of <Swig Object of type 'std::vector< double > *' at 0x100499450> >

Traceback (most recent call last):
File "./doit", line 17, in <module>
  execfile('test.py')
File "test.py", line 18, in <module>
  kv = hbspy.HKnotVector(2, knots)
File "/Users/spencerlyon2/Research/HBS/hbs/swig/hbspy.py", line 249, in __init__
  this = _hbspy.new_HKnotVector(*args)
NotImplementedError: Wrong number or type of arguments for overloaded function 'new_HKnotVector'.
Possible C/C++ prototypes are:
  hbs::HKnotVector::HKnotVector()
  hbs::HKnotVector::HKnotVector(uint,DoubleVec const &)
  hbs::HKnotVector::HKnotVector(hbs::HKnotVector const &)

当我打印打结时,您可以看到它的类型为std::vector < double > *,common.h 为typdefd DoubleVec。我无法弄清楚为什么我传递knots给构造函数会给出这个错误,而第二个“C/C++ 原型”似乎很明显应该得到满足。

我想强调的是,如果我只是将 common.h 中的相关代码复制/粘贴到 HKnotVector.i 中,我不会收到此错误。

我有两个想法可能会让某人走上正确的道路:

  1. 当我在 .i 文件上运行 swig 时出现的错误表明对命名空间一无所知util,这DoubleVec就是typedefd in common.h
  2. 我可能(?)需要去%include common.h某个地方,所以 swig 对它了如指掌。

编辑 (5-11-13)

如果我尝试%include "common.h"在 HKnotVector.i 中(就在该%include "../include/HKnotVector.h"行上方),则扩展构建时没有命名空间错误(HKnotVector.h:7: Error: Nothing known about namespace 'util'),但 python 无法导入它。这就是我在使用以下代码构建后尝试运行 test.py 时发生的情况%include "common.h"

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    import hbspy
  File "/Users/spencerlyon2/Research/HBS/hbs/swig/hbspy.py", line 26, in <module>
    _hbspy = swig_import_helper()
  File "/Users/spencerlyon2/Research/HBS/hbs/swig/hbspy.py", line 22, in swig_import_helper
    _mod = imp.load_module('_hbspy', fp, pathname, description)
ImportError: dlopen(/Users/spencerlyon2/Research/HBS/hbs/swig/_hbspy.so, 2): Symbol not found: __ZN4utillsERSoRKNS_4AxisE
  Referenced from: /Users/spencerlyon2/Research/HBS/hbs/swig/_hbspy.so
  Expected in: dynamic lookup

我不知道是什么__ZN4utillsERSoRKNS_4AxisE,但我假设它是扩展模块或 SWIG 定义的一些内部符号。


编辑 2 (5-11-13)

如果我去 common.h 并删除指定util命名空间的行并注释掉using namespace util;HKnotVector.h 中的行,一切正常。

这对我来说很奇怪,因为swig 文档明确指出“对 C++ 命名空间的支持是全面的......”并且“默认包装行为是在目标语言中展平命名空间。这意味着所有命名空间的内容都合并在一起在生成的脚本语言模块中。” 这似乎是我想要的行为,即我希望成为 python 能够访问所有内容,util就好像它在全局命名空间中一样。

在这个小示例中,删除命名空间规范非常简单明了。然而,这只是一个已经深入使用命名空间的大型项目的一小部分。尽管我得到了这个示例来编译,但删除命名空间并不是一个可行的长期解决方案。

4

1 回答 1

3

正如您所发现的,当 SWIG 处理头文件时,默认情况下它不会递归到顶级头文件包含的头文件中,因此您必须%include "common.h"专门将其定义公开给 SWIG。

您还发现,using在头文件中使用语句是一种不好的做法,因为它们会将所有内容都导入一个命名空间。在这种情况下,它会混淆 SWIG。任何.cpp包含带有 using 语句的标头的文件都被迫污染其全局命名空间。标题应该尊重命名空间并完全指定它们并将using语句留给.cpp文件。

请参阅为什么在 C++ 中将“使用命名空间”包含到头文件中是一个坏主意?

于 2013-05-12T00:24:01.133 回答