使我的代码可以swiggable的推荐方法?

时间:2011-03-03 19:38:47

标签: c++ swig

我目前正在重构一个用C ++编写的Tcl插件库。最初代码是手写的。存在第二个库,它为Java做同样的事情。

重构的库将是一个单独的C ++库,可用于创建不同语言的绑定。

我对SWIG的首次测试很有希望。但是,也会生成大量垃圾。各种基类和实用程序都已导出。从脚本的角度来看,这些没有意义,只会增加混乱。

我能想到的可能解决方案是:

  1. 使用原始代码库中的#ifndef SWIG过滤掉不需要的代码
  2. 围绕API类创建一个兼容SWIG的包装器。
  3. 区分公共标头和私人标头。公共头是纯抽象基类,不包含任何实现。私有头继承并实现它们。只有SWIG公共标题。
  4. 与上述解决方案相反:为每个API类继承SWIG兼容类。
  5. 我目前正倾向于解决方案3。但是,我不确定,所以我想知道SO社区对此的看法。随意分享您的想法。

    更新

    我忘了列出一个解决方案:

    • SWIG不应导出的代码可能不属于您班级的公共部分。

    也许这就是答案。我星期一再看看。

    更新

    我找到了一个解决方案。看到我的回答。

3 个答案:

答案 0 :(得分:3)

任何意味着C ++库对C ++用户不太有用的方法都不是理想的解决方案。

  1. #ifdef在.hpp文件中间的SWIG:用不必要的瑕疵来捣乱你的C ++,所以它并不理想
  2. SWIG特定接口:这是一个可行的选择,但只有在您希望向SWIG公开的代码比基础C ++ API高得多的情况下才有意义。
  3. 公共与私人界面:可能有意义,但你又要问API的C ++用户花了多少钱?你是否过分限制公共接口?谁有权访问私有界面?是否应考虑pImpl idiom
  4. 每个界面的SWIG兼容类:可能需要更多工作。
  5. 首先,要将与SWIG相关的代码与API的其余部分分开。

    您可能不希望将.hpp文件直接导入SWIG(如果在初始设计库时未考虑SWIG),但如果这样做,则需要使用SWIG .i文件来帮助你收拾残局。我们使用了三种基本方法,每种方法都有不同的用例。

    首先,直接包容。如果您知道您的API非常干净并且非常适合SWIG解析,那么这非常有用:

    // MyClass.i
    %{
      #include "MyClass.hpp" // included for the generated .cxx file
    %}
    
    %include "MyClass.hpp" // included and parsed directly by SWIG
    

    第二种情况是代码大部分都在那里。这是考虑了SWIG的代码,但实际上需要一些我们不希望暴露给SWIG的C ++用户:

    // MyClass.i
    %{
      #include "MyClass.hpp" // included for the generated .cxx file
    %}
    
    %ignore MyClass::someFunction(); // This function really just causes us problems
    %include "MyClass.hpp" // included and parsed directly by SWIG
    

    第三种情况,也许是您想要使用的情况,是直接选择要向SWIG公开的功能。

    // MyClass.i
    %{
      #include "MyClass.hpp" // included for the generated .cxx file
    %}
    
    // With this example we provide exactly as much information to SWIG as we want
    // it to have. Want it to know the base class? Add it. Don't want it to know about
    // a function? Leave it out. want to add a new function? %extend it.
    class MyClass
    {
      void importantFunction();
      void importantFunction2();
    }
    

答案 1 :(得分:2)

我也会使用apprach#3。我在我的项目中使用了类似的方法,它也被COM使用(由私有实现类继承的接口)。

以这种方式检测错误和维护代码非常容易!不幸的是,你将最终将所有功能都实现为虚拟,但它不应该是一个大问题......

分离界面将使其保持清洁和易懂!

答案 2 :(得分:0)

我的最终解决方案:只需SWIG原始代码库。为了避免生成不相关的代码,我使用以下技术。按优先顺序排列:

  1. 将非swig代码设为私有或受保护。如果它不需要被唤醒,那么它可能不需要公开。

  2. 如果可能,请更改原始代码,使其与SWIG更兼容。我用抽象基类替换了curiously recurring template pattern。我愿意为SWIG做出这样的牺牲:)

  3. %ignore语句添加到接口文件中。

  4. 使用#ifndef SWIG对其进行过滤。我不喜欢污染我原来的代码,所以我只把它作为最后的手段。

  5. 关于我以前的想法:

      
        
    • 围绕API类创建一个兼容SWIG的包装器。
    •   
    • 区分公共标头和私人标头。公共标题是   纯抽象基类   不包含任何实现。私人的   标头继承并实现它们。   只有SWIG公共标题。
    •   
    • 与上述解决方案相反:继承SWIG兼容类   每个API类。
    •   

    所有这些解决方案都需要编写兼容SWIG的包装代码。这有点傻,因为你放弃SWIG是最强大的卖点:自动生成包装代码。如果我为SWIG编写自己的包装代码,那么我也可以编写常规的JNI代码。

    那就是说,我意识到对于一些项目来说,编写包装代码可能是最具成本效益的解决方案。但是,我的情况并非如此。