Предотвратить удаление линков
Я использую статические глобальные конструкторы переменных как трюк, чтобы удобно регистрировать функции, идея идет примерно так:
typedef int (*FuncPtr)(int);
struct RegHelper
{
RegHelper(const char * Name, FuncPtr Func)
{
Register(Name, Func);
}
}
#define REGISTER(func) RegHelper gRegHelper_ ## func (#func, func);
Теперь я могу зарегистрировать функции таким образом (я использую его для реализации какого-то отражения):
int Foo(int a)
{
return a * 123;
}
REGISTER(Foo)
int Bar(int a)
{
return a * 456;
}
REGISTER(Bar)
Проблема заключается в том, что если я использую это в статической библиотеке, иногда компоновщик обнаруживает, что блок компиляции не используется, и он упускает все это. Таким образом, глобальные переменные не создаются, и функции не регистрируются...
Мой вопрос: что я могу сделать, чтобы обойти это? Вызов фиктивных функций в каждом модуле компиляции во время инициализации, похоже, вызывает построение глобальных переменных, но это не очень безопасно. Любое другое предложение?
Ответы
Ответ 1
Чтобы решить эту проблему, выполните следующие действия:
- Visual studio (в том же решении): Linker > General > Use library Dependency Inputs = yes
- Gcc: ссылка непосредственно с .o файлами
Я не нашел решение, которое мне действительно нравится.
Ответ 2
См. ответ здесь: заставить визуальную студию связывать все символы в файле lib
Это действительно работало для меня. Другие предложения не сделали.
Ответ 3
Да, у меня тоже была эта проблема. Единственные верные пути вокруг него, которые я нашел, были:
или
- переместить объекты регистрации в исполняемый файл
Ни один из них не идеален, хотя решение DLL в порядке, если вы не против использования DLLS, и мне тоже было бы интересно узнать о других решениях.
Ответ 4
Обратите внимание на "Лучший способ создания списка данных по типу"
Есть два важных важных понятия. Во-первых:
(void) register_object;
использует объект, чтобы гарантировать, что компоновщик не отделяет его, и
template<typename D> typename automatic_register<D>::exec_register
automatic_register<D>::register_object;
гарантирует, что для каждого экземпляра выделяется статический глобальный. Вы должны хранить свои данные в этом объекте. Его немного отличается в том, что для каждого объекта, а не для класса, но если вы адаптируете свой макрос для создания
// Global list of objectsh
struct FpList
{
FpList( FuncPtr func ) :
func(func)
{
head = next;
next = this
}
FpList* next;
FuncPtr func;
static FpList* head;
};
// In .cxx:
FpList* FpList::head = 0;
Затем измените свой макрос регистрации так, чтобы REGISTER (Foo), чтобы он создавал:
struct register_Foo : FpList
{
register_Foo( FuncPtr fn ): FpList(fn)
{
(void) register_object;
}
static register_Foo register_object;
};
Я думаю, этого недостаточно. Вам все равно нужно установить шаблон, передать if & Foo и убедиться, что
register_Foo register_Foo::register_object
Экземпляр создается где-то. Код шаблона для auto_register показывает, как это сделать в заголовке. Если вы можете поместить свой макрос в .cxx, просто объявите:
register_Foo register_Foo::register_object( &Foo );
как часть вашего макроса. Я думаю, что это может сработать. (все из памяти, так кто знает).
Ответ 5
Если вы находитесь в среде UNIX, вызывающей ld с параметром "весь архив", принудительно включайте все объектные файлы в статическую библиотеку независимо от использования.
Ответ 6
Еще одно возможное решение этой проблемы. Получите постоянное значение через вызов функции. Вот так:
constant.h
const char blah[10];
extern const char *get_blah();
constant.c
#include "header.h"
const char *get_blah()
{ return blah; }
Это помогло мне сделать трюк!