У меня есть настройка, которая не работает, и я понятия не имею, что я делаю здесь неправильно —
Я пытаюсь преобразовать проект из созданных вручную Makefile-ов в autotools, и я думаю, что большая часть его настроена правильно, так как приложение и все его удобные библиотеки создаются и связываются правильно, но есть некоторые проблемы с инициализаторами глобального состояния удобные библиотеки.
Некоторые библиотеки следуют шаблону, подобному следующему в коде:
// in global scope of somemodule.cpp
namespace {
bool registered = ModuleShare::registerModule<SomeModule>("SomeModule");
}
этот код вместе с исходным модулем скомпилирован в удобную библиотеку с использованием libtool
// libsomething Makefile.am
noinst_LTLIBRARIES = libsomething.la
libsomething_la_SOURCES = \
[ ... ]
moduleshare.cpp moduleshare.h \
somemodule.cpp somemodule.h \
[ ... ]
и эта библиотека создается и на нее ссылаются в приложении Makefile.am следующим образом:
// someapp Makefile.am
bin_PROGRAMS = someapp
someapp_SOURCES = someapp.c someapp.h
someapp_CPPFLAGS = -I ${top_srcdir}/something
someapp_LDADD = ${top_srcdir}/something/libsomething.la
Я изменил ModuleShare :: registerModule, чтобы убедиться, что он не вызывается:
template<typename T>
static bool registerModule(const std::string &module){
printf("%s\n", module.c_str());
[ ... ]
return true;
}
Что может быть причиной этого?
РЕДАКТИРОВАТЬ:
На этом этапе я выяснил, что эта проблема связана с компоновщиком, которому разрешено удалять неиспользуемые символы во время компоновки. Если я связать вручную, используя --whole-archive
все работает как положено.
Исходя из фона C, я также пытался
static void
__attribute__((constructor))
register (void)
{
ModuleShare::registerModule<SomeModule>("SomeModule");
}
но это также не приводит к ожидаемому поведению, которое странно, учитывая, что я очень полагаюсь на эту конструкцию в своих частных проектах на Си.
На данный момент я открыт для предложений в любом направлении. Я знаю, что libtool не предоставляет флаги для каждой библиотеки в LDADD, и я не могу и просто не хочу компилировать все с —whole-archive только для того, чтобы избавиться от этих симптомов. У меня есть только ограниченный контроль над базой кода, но я думаю, что мне действительно нужно спросить здесь, каков хороший и надежный способ инициализации состояния программы в удобной библиотеке с помощью автоинструментов?
EDIT2:
Я думаю, что я на шаг ближе — кажется, что в коде приложения нет обращений к удобной библиотеке, и, следовательно, компоновщик его пропускает. Приложение вызывает библиотеку только через шаблонную функцию, определенную в заголовочном файле SomeModule
, который опирается на статические инициализаторы, вызываемые в вспомогательных библиотеках.
Эта реверсия зависимостей распространяется на всю сборку.
Тем не менее, я не уверен, как решить эту проблему: /
Спасибо,
Энди
Этот ответ может потребовать слишком много изменений кода для вас, но я упомяну об этом. Как я уже упоминал ранее, модель удобных библиотек является своего рода статической связью, в которой библиотеки объединяются перед окончательной связью с инкапсулирующей библиотекой. Только в этом случае «библиотека» является исполняемым файлом. Так что я представляю эту вещь в безымянном пространстве имен (static
переменные по существу), особенно не связанные ссылки будут удалены. С приведенным выше кодом это сработало так, как я ожидал.
Я смог получить registerModule
напечатать это сообщение без специальных трюков с компоновщиком в удобной библиотеке:
somemodule.cpp
// in global scope
namespace registration {
bool somemodule = ModuleShare::registerModule<SomeModule>("SomeModule");
}
someapp.cpp
// somewhere
namespace registration {
extern bool somemodule;
... // and all the other registration bools
}
// in some code that does initialization, possibly
if (!(registration::somemodule && ...)) {
// consequences of initialization failure
}
Поскольку вы используете autotools, вы можете оказаться в ситуации, когда возможно использование только gcc. В этом случае вы можете применить атрибут `used ‘, чтобы gcc заставил компоновщик включить символ:
namespace {
__attribute__ ((used))
bool registered = ModuleShare::registerModule<SomeModule>("SomeModule");
}
Вместо того, чтобы использовать —whole-archive, вы пытались просто добавить -u registered
?
Как ld
ручные состояния:
-u symbol
--undefined=symbol
Force symbol to be entered in the output file as an undefined symbol. Doing this may, for example, trigger linking of additional modules from standard libraries. -u may be repeated with different option arguments to
enter additional undefined symbols. This option is equivalent to the "EXTERN" linker script command.
Редактировать: Я думаю, что то, что вы пытаетесь достичь, очень похоже на управление плагинами в Qt. это статья подробно это немного. А также этот это официальная документация 4.8.
Принимая во внимание, что вспомогательные библиотеки построены статически, может быть, этого было бы достаточно, чтобы создать фиктивный экземпляр внутри этой вспомогательной библиотеки (или фиктивное использование registered
) и объявить это extern
где вы его используете (это то, что делают Q_EXPORT_PLUGIN2 и Q_IMPORT_PLUGIN).