Подтвердить что ты не робот

Как принудительно включить объектный файл в статическую библиотеку при связывании с исполняемым файлом?

У меня есть проект на С++, который из-за его структуры каталогов настроен как статическая библиотека A, которая связана с общей библиотекой B, которая связана с исполняемым C. (Это кросс-платформенный проект с использованием CMake, поэтому в Windows мы получаем A.lib, B.dll и C.exe, а в Linux мы получаем libA.a, libB.so и C.) Библиотека A имеет функцию init (A_init, определенную в A/initA.cpp)), которая вызывается из библиотеки B функции init (B_init, определенной в B/initB.cpp)), которая вызывается из C main. Таким образом, при связывании B, A_init (и всех символов, определенных в initA.cpp), связывается с B (что является нашим желаемым поведением).

Проблема заключается в том, что библиотека A также определяет функцию (Af, определенную в A/Afort.f), которая предназначена для динамической загрузки (т.е. LoadLibrary/GetProcAddress в Windows и dlopen/dlsym в Linux). Поскольку в библиотеке B нет ссылок на Af, символы из A/Afort.o не включены в B. В Windows мы можем искусственно создать ссылку с помощью прагмы:

#pragma comment (linker, "/export:_Af")

Поскольку это прагма, она работает только в Windows (с использованием Visual Studio 2008). Чтобы заставить его работать в Linux, мы попытались добавить следующее в A/initA.cpp:

extern void Af(void);
static void (*Af_fp)(void) = &Af;

Это не приводит к включению символа Af в окончательную ссылку B. Как мы можем привязать символ Af к B?

4b9b3361

Ответ 1

Оказывается, моя первоначальная попытка была в основном там. Следующие работы:

extern "C" void Af(void);
void (*Af_fp)(void) = &Af;

Для тех, кто хочет создать автономный макрос препроцессора, чтобы инкапсулировать это:

#if defined(_WIN32)
# if defined(_WIN64)
#  define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:" #x))
# else
#  define FORCE_UNDEFINED_SYMBOL(x) __pragma(comment (linker, "/export:_" #x))
# endif
#else
# define FORCE_UNDEFINED_SYMBOL(x) extern "C" void x(void); void (*__ ## x ## _fp)(void)=&x;
#endif

Используется таким образом:

FORCE_UNDEFINED_SYMBOL(Af)

Ответ 2

MSVC #pragma comment(linker, "/include:__mySymbol")

gcc -u symbol

Ответ 3

Вы можете использовать опцию --undefined при создании B:

g++ -Wl,--undefined,Af -o libB.so ...

Ответ 4

Существует лучший способ написать макрос FORCE_UNDEFINED_SYMBOL. Просто нарисуйте эту функцию указателем на void *. Затем он работает с любой функцией - или данными в этом отношении. Кроме того, зачем беспокоиться с праймами MSVC, когда часть gcc вашего макроса будет работать и для MSVC. Поэтому моя упрощенная версия:

#define FORCE_UNDEFINED_SYMBOL(x) void* __ ## x ## _fp =(void*)&x;

Используется таким образом:

FORCE_UNDEFINED_SYMBOL(Af)

Но он должен использоваться в программе, которая включает в себя библиотеку, которая имеет свои символы.

Ответ 5

Попробуйте поместить эти строки в B/initB.cpp, чтобы они (надеюсь) были вынуждены в библиотеку libB.so за время ссылки.

Но почему вы должны делать это таким образом вообще? Не можете ли вы настроить его так, чтобы исполняемые ссылки, которые функционируют (или вызывающий его), заставляют компоновщик делать правильную вещь автоматически?

Ответ 6

Если вы можете использовать С++ 0x функции gcc (-std = С++ 0x), то аргументы шаблона по умолчанию могут делать трюк. Начиная с текущего стандарта С++ аргументы по умолчанию для шаблонов функций не допускаются. Если они включены в С++ 0x, вы можете сделать что-то вроде: -

В некотором заголовочном файле статической библиотеки...

template< class T = int >
void Af()
{
}

Затем в соответствующем файле cpp используйте явное создание экземпляра шаблона...

template void Af();

Это приведет к созданию символов для функции Af, хотя она еще не вызвана/не указана. Это не повлияет на вызывающих абонентов из-за того, что из-за аргумента шаблона по умолчанию вам не нужно указывать тип. Просто добавьте template <class T = int > перед объявлением функции и явно создайте экземпляр в своем файле реализации.

НТН,