我目前正在重构一个用C ++编写的Tcl插件库。最初代码是手写的。存在第二个库,它为Java做同样的事情。
重构的库将是一个单独的C ++库,可用于创建不同语言的绑定。
我对SWIG的首次测试很有希望。但是,也会生成大量垃圾。各种基类和实用程序都已导出。从脚本的角度来看,这些没有意义,只会增加混乱。
我能想到的可能解决方案是:
#ifndef SWIG
过滤掉不需要的代码我目前正倾向于解决方案3。但是,我不确定,所以我想知道SO社区对此的看法。随意分享您的想法。
我忘了列出一个解决方案:
也许这就是答案。我星期一再看看。
我找到了一个解决方案。看到我的回答。
答案 0 :(得分:3)
任何意味着C ++库对C ++用户不太有用的方法都不是理想的解决方案。
首先,要将与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原始代码库。为了避免生成不相关的代码,我使用以下技术。按优先顺序排列:
将非swig代码设为私有或受保护。如果它不需要被唤醒,那么它可能不需要公开。
如果可能,请更改原始代码,使其与SWIG更兼容。我用抽象基类替换了curiously recurring template pattern。我愿意为SWIG做出这样的牺牲:)
将%ignore
语句添加到接口文件中。
使用#ifndef SWIG
对其进行过滤。我不喜欢污染我原来的代码,所以我只把它作为最后的手段。
关于我以前的想法:
- 围绕API类创建一个兼容SWIG的包装器。
- 区分公共标头和私人标头。公共标题是 纯抽象基类 不包含任何实现。私人的 标头继承并实现它们。 只有SWIG公共标题。
- 与上述解决方案相反:继承SWIG兼容类 每个API类。
所有这些解决方案都需要编写兼容SWIG的包装代码。这有点傻,因为你放弃SWIG是最强大的卖点:自动生成包装代码。如果我为SWIG编写自己的包装代码,那么我也可以编写常规的JNI代码。
那就是说,我意识到对于一些项目来说,编写包装代码可能是最具成本效益的解决方案。但是,我的情况并非如此。