Avoiding duplication of the SWIG pattern when using many modules generated by SWIG

When creating an interface module with SWIG, the generated C / C ++ file contains a ton of static template functions. Therefore, if you want to modulate the use of SWIG-generated interfaces using many separate compiled small interfaces in one application, as a result of these duplicate functions, a lot of bloating ends.

Using the gcc -ffunction-sections option and the linker --icf=safe GNU --icf=safe option for the compiler) you can remove some of the duplication, but by no means all (I think that it will not stick together everything that takes place in it - what many of these functions do).

My question is: I wonder if there is a way to remove more of this duplicate template, ideally one that does not rely on GNU specific compiler / linker options.

In particular, is there a / SWIG flag / something that says "do not include a template in every output file"? Actually there is a SWIG option, -external-runtime , which tells it to generate an output file with a "template only", but there is no visible way to suppress the copy included in each normal output file. [I think this kind of thing should be pretty simple to implement in SWIG, so I'm surprised that it doesn't seem to exist ... but I can't find anything documented.]

Here is a small example:

Given the swg-oink.swg interface file for the swt_oink module:

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

... and a similar swg-barf.swg for swt_barf :

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

... and the main test file, 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; } 

and compile them as:

 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 

then the size of each xxx _wrap.o file is about 16 KB, of which 95% is a template, and the size of the final executable file is approximately equal to the sum of these, about 39 KB. If you compile each interface file using -ffunction-sections and links with -Wl,--icf=safe , the size of the final executable file is 34 KB, but there is obviously a lot of duplication (using nm in the executable file, you can see many functions defined several times, and looking at their source, it is clear that for most of them it would be good to use one global definition).

+4
source share
2 answers

I am sure that SWIG has no way to do this. I’m thinking now, but I think the reason may be the concern about the visibility of this for modules built with different versions of SWIG. Imagine the following scenario:

The two libraries X and Y provide an interface for their code using SWIG. They both prefer that SWIG glue be displayed in different translation units to reduce code size. It will be good and good if both X and Y use the same version of SWIG. What happens if X uses SWIG 1.1 and Y uses SWIG 1.3? Both modules work fine, but depending on how the platform processes common objects and how the language loads them ( RTLD_GLOBAL ?), Some potentially very bad things will come from a combination of two modules used in the same virtual machine.

The code duplication limit is quite low, I suspect that the cost of exchanging between the VM and native code is usually quite high, which probably overshadows the slightly reduced instruction cache hits, although it would be interesting to see real benchmarks. At the top is code that no one needs to worry about, since it is all automatically generated and everything is stored correctly with interfaces written for the corresponding version.

+2
source

I may be a little late, but here is a workaround:

  • In SWIG (<= 1.3) there is a command line option -noruntime
  • Since SWIG 2.0 -noruntime deprecated, so now you need to pass -DSWIG_NOINCLUDE to the C preprocessor - not to swig itself

I'm completely not sure if this is correct, but at least it works for me. I am going to clarify this issue on the SWIG mailing list.

+1
source

Source: https://habr.com/ru/post/1381839/


All Articles