избегая дублирования шаблона SWIG при использовании многих генерируемых SWIG модулей - PullRequest
4 голосов
/ 18 ноября 2011

При генерации интерфейсного модуля с помощью 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 файла составляет около 16 КБ, из которых 95% - это стандартный шаблон, а размер конечного исполняемого файла примерно равен сумме этих значений, около 39 КБ. Если каждый компилирует каждый интерфейсный файл с -ffunction-sections и связывает с -Wl,--icf=safe, размер конечного исполняемого файла составляет 34 КБ, но все еще явно много дублирования (при использовании nm в исполняемом файле можно увидеть множество определенных функций Несколько раз, и, глядя на их источник, становится ясно, что для большинства из них было бы хорошо использовать одно глобальное определение.

Ответы [ 2 ]

2 голосов
/ 19 ноября 2011

Я вполне уверен, что SWIG не имеет возможности сделать это. Сейчас я размышляю, но я думаю причина вполне может заключаться в обеспокоенности по поводу видимости этого для модулей, построенных с различными версиями SWIG. Представьте себе следующий сценарий:

Две библиотеки X и Y обе предоставляют интерфейс для своего кода с помощью SWIG. Они оба хотят, чтобы материал "SWIG glue" был виден в разных единицах перевода, чтобы уменьшить размер кода. Все будет хорошо, если X и Y будут использовать одну и ту же версию SWIG. Что произойдет, если X использует SWIG 1.1, а Y - SWIG 1.3? Оба модуля прекрасно работают сами по себе, но в зависимости от того, как платформа обрабатывает общие объекты и как сам язык их загружает (RTLD_GLOBAL?), Некоторые потенциально очень плохие вещи могут произойти из-за комбинации двух модулей, используемых в одной виртуальной машине. .

Я подозреваю, что штраф за дублирование кода довольно низок - стоимость замены виртуальной машины на собственный код, как правило, довольно высока, что, вероятно, превосходит немного уменьшенные попадания в кэш команд, хотя может быть интересно увидеть реальные тесты. С другой стороны, это код, который не нужно беспокоить пользователям, так как он автоматически генерируется и правильно хранится с интерфейсами, написанными для соответствующей версии.

1 голос
/ 08 октября 2013

Возможно, я немного опоздал, но вот обходной путь:

  • В SWIG (<= 1,3) есть <code>-noruntime опция командной строки
  • Поскольку SWIG 2.0 -noruntime устарел, теперь нужно передать -DSWIG_NOINCLUDE препроцессору C, а не самому Swig

Я совершенно не уверен, что это правильно, но это, по крайней мере, работает для меня. Я собираюсь прояснить этот вопрос в списке рассылки SWIG.

...