4

使用 SWIG 生成接口模块时,生成的 C/C++ 文件包含大量静态样板函数。因此,如果想通过在同一个应用程序中使用许多单独编译的小接口来模块化 SWIG 生成的接口的使用,那么由于这些重复的功能,最终会导致很多臃肿。

使用 gcc 的-ffunction-sections选项和 GNU 链接器的--icf=safe选项(-Wl,--icf=safe对编译器),可以删除一些重复,但绝不是全部(我认为它不会合并任何有重定位的东西——其中很多功能做)。

我的问题:我想知道是否有办法删除更多这种重复的样板,最好是不依赖于 GNU 特定的编译器/链接器选项。

特别是,是否有 SWIG 选项/标志/某些内容显示“不在每个输出文件中包含样板”?实际上一个 SWIG 选项,-external-runtime它告诉它生成一个“仅样板”输出文件,但没有明显的方法来抑制每个正常输出文件中包含的副本。[我认为这种事情在 SWIG 中实现起来应该相当简单,所以我很惊讶它似乎不存在......但我似乎找不到任何记录。]

这是一个小例子:

swg-oink.swg给定模块的接口文件swt_oink

%module swt_oink
%{ extern int oinker (const char *x); %}
extern int oinker (const char *x);

...以及类似的swg-barf.swg界面swt_barf

%module swt_barf
%{ extern int barfer (const char *x); %}
extern int barfer (const char *x);

...和一个测试主文件,swt-main.cc

extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

extern int luaopen_swt_oink (lua_State *);
extern int luaopen_swt_barf (lua_State *);
}

int main ()
{
  lua_State *L = lua_open();
  luaopen_swt_oink (L);
  luaopen_swt_barf (L);
}

int oinker (const char *) { return 7; }
int barfer (const char *) { return 2; }

并像这样编译它们:

swig -lua -c++ swt-oink.swg
g++ -c -I/usr/include/lua5.1 swt-oink_wrap.cxx
swig -lua -c++ swt-barf.swg
g++ -c -I/usr/include/lua5.1 swt-barf_wrap.cxx
g++ -c -I/usr/include/lua5.1 swt-main.cc
g++ -o swt swt-main.o swt-oink_wrap.o swt-barf_wrap.o

那么每个xxx_wrap.o文件的大小约为 16KB,其中 95% 是样板文件,最终可执行文件的大小大致是这些的总和,约 39K。如果用 编译每个接口文件-ffunction-sections,并用 链接-Wl,--icf=safe,最终可执行文件的大小为 34KB,但显然仍有很多重复(nm在可执行文件上使用可以看到多次定义的大量函数,并查看它们的源代码,很明显,对它们中的大多数使用单一的全局定义就可以了)。

4

2 回答 2

2

我相当确定 SWIG 没有这样做的选项。我现在在猜测,但我认为原因很可能是担心使用不同版本的 SWIG 构建的模块的可见性。想象以下场景:

两个库 X 和 Y 都使用 SWIG 为其代码提供接口。他们都选择让“SWIG 胶水”在不同的翻译单元中可见,以减少代码大小。如果 X 和 Y 都使用相同版本的 SWIG,这一切都会很好。如果 X 使用 SWIG 1.1 而 Y 使用 SWIG 1.3 会发生什么?两个模块单独工作都很好,但是取决于平台如何处理共享对象以及语言本身如何加载它们(RTLD_GLOBAL?)在同一 VM 中使用两个模块的组合可能会发生一些非常糟糕的事情。

我怀疑代码重复的代价非常低——在 VM 和本机代码之间交换的成本通常非常高,这可能会使略微减少的指令缓存命中相形见绌,尽管看到真正的基准测试可能会很有趣。从好的方面来说,这是用户无需担心的代码,因为它都是自动生成的,并且都正确地保留了为相应版本编写的接口。

于 2011-11-19T17:55:39.633 回答
1

我可能有点晚了,但这里有一个解决方法:

  • 在 SWIG (<= 1.3 ) 中有-noruntime命令行选项
  • 由于 SWIG 2.0-noruntime已被弃用,所以现在应该传递-DSWIG_NOINCLUDE给 C 预处理器 - 而不是传递给 swig 本身

我完全不确定这是否正确,但至少对我有用。我将在 SWIG 的邮件列表中澄清这个问题。

于 2013-10-08T08:04:02.180 回答