Не допускать удаления экспортируемой функции компоновщиком
У меня есть программа, котораястатически ссылки с несколькими библиотеками c ++, которые экспортируют несколько функций:
extern "C"
{
KSrvRequestHandler* CreateRequestHandler( const char* name );
bool DestroyRequestHandler( KSrvRequestHandler* handler );
const char** ListRequestHandlerTypes();
}
Затем основная программа вызывает эти функции, используя GetProcAddress / dlsym:
#ifdef WIN32
HINSTANCE hDll = GetModuleHandle( NULL );
mCreateHandler = GetProcAddress( hDll, createFuncName );
mDestroyHandler = GetProcAddress( hDll, destroyFuncName );
mGetHandlerTypes = GetProcAddress( hDll, listFuncName );
#else // POSIX
void* handle = dlopen( NULL, 0 );
mCreateHandler = dlsym( handle, createFuncName );
mDestroyHandler = dlsym( handle, destroyFuncName );
mGetHandlerTypes = dlsym( handle, listFuncName );
dlclose( handle );
#endif // !POSIX
Итак, ключевой момент здесь заключается в том, что я вызываю функцию в своей основной программе, используя динамическое связывание.
(Почему я делаю это выходит за рамки вопроса, но короткий ответ: это архитектура плагинов, но у меня есть несколько стандартных плагинов, которые связаны непосредственно с основным двоичным файлом - но я все еще хочу загрузить их через ту же загрузку плагинов интерфейс. Например, для встроенных плагинов я загружаю их, передавая текущий исполняемый файл в качестве источника интерфейсов плагинов.)
Вот проблема: компоновщик не знает, что мне понадобятся эти функции, и не связывает их.
Как заставить эти функции быть связаны между собой? Для динамической библиотеки их экспорта достаточно. Но для exe, даже экспортированная dll функция удаляется компоновщиком.
Я знаю, что, вероятно, смогу принудительно установить связь, заставив основной двоичный файл назначить эти адреса функций чему-либо или какому-нибудь другому подобному хаку Есть ли правильный способ сделать это?
@ ОБНОВЛЕНИЕ: Итак, у меня есть решение, которое работает, но оно внутри безобразно. Все еще ищу лучший путь.
Поэтому мне нужно как-то определить нужные мне символы в объекте, который загружает встроенные интерфейсы. Я не думаю, что есть способ заставить компоновщик ссылаться на символ иначе. Например. Я не знаю, как создать библиотеку с функцией, которая всегда связана, независимо от того, нужна она или нет. Это полностью на усмотрение шага ссылки для исполняемого файла.
Поэтому в исполняемом файле у меня есть макрос, который определяет необходимые мне встроенные интерфейсы. Каждый встроенный плагин имеет префикс для всех своих функций интерфейса, поэтому в верхней части файла я делаю:
DEFINE_BUILT_IN_PLUGIN( PluginOne )
DEFINE_BUILT_IN_PLUGIN( PluginTwo )
Это заставит определения функций мне нужно. Но макрос для этого настолько уродлив, что я переполнен чувствами ярости и неуверенности в себе (для удобства чтения я удалил косые черты из макроса):
#define FORCE_UNDEFINED_SYMBOL(x)
void* _fp_ ## x ## _fp =(void*)&x;
if (((ptrv) _fp_ ## x ##_fp * ( rand() | 1 )) < 1 )
exit(0);
#define DEFINE_BUILT_IN_PLUGIN( PREFIX )
extern "C"
{
KSrvRequestHandler* PREFIX ## CreateRequestHandler( const char* name );
bool PREFIX ## DestroyRequestHandler( KSrvRequestHandler* handler );
const char** PREFIX ## ListRequestHandlerTypes();
}
class PREFIX ## HandlerInterfaceMagic
{
public:
PREFIX ## HandlerInterfaceMagic()
{
FORCE_UNDEFINED_SYMBOL( PREFIX ## CreateRequestHandler );
FORCE_UNDEFINED_SYMBOL( PREFIX ## DestroyRequestHandler );
FORCE_UNDEFINED_SYMBOL( PREFIX ## ListRequestHandlerTypes );
}
};
PREFIX ## HandlerInterfaceMagic PREFIX ## HandlerInterfaceMagicInstance;
Поскольку компилятор является оптимизирующим родом, в FORCE_UNDEFINED_SYMBOLS я собираюсь изо всех сил обмануть компилятор и связать функцию, на которую нет ссылок. Этот макрос работает только внутри функции. Поэтому я должен создать этот фальшивый класс Magic. Должен быть лучший способ.
Во всяком случае - это работает.