如何在链接到可执行文件时强制将对象文件包含在静态库中?

时间:2010-06-07 18:01:09

标签: c++ linux linker static-libraries

我有一个C ++项目,由于其目录结构被设置为静态库A,它链接到共享库B,它链接到可执行文件C。 (这是一个使用CMake的跨平台项目,所以在Windows上我们得到A.libB.dllC.exe,在Linux上我们得到libA.a,{{1} }和libB.so。)库C有一个init函数(A,在A_init中定义),从库A/initA.cpp的init函数调用(B中定义的B_init,从B/initB.cpp的主要调用。因此,在关联C时,B(以及A_init中定义的所有符号)都会链接到initA.cpp(这是我们想要的行为)。

问题在于B库还定义了一个函数(A,在Af中定义),旨在通过动态加载(即A/Afort.f / { Windows上为{1}},Linux上为LoadLibrary / GetProcAddress。由于库dlopen中没有对dlsym的引用,因此Af中的符号不​​会包含在B中。在Windows上,我们可以通过使用pragma来创建引用:

A/Afort.o

由于这是一个pragma,它只适用于Windows(使用Visual Studio 2008)。为了让它在Linux上运行,我们尝试将以下内容添加到B

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

这不会导致符号A/initA.cpp包含在extern void Af(void); static void (*Af_fp)(void) = &Af; 的最后一个链接中。我们如何强制将符号Af链接到B

6 个答案:

答案 0 :(得分:12)

事实证明我最初的尝试主要在那里。以下作品:

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)

答案 1 :(得分:6)

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

gcc -u symbol

答案 2 :(得分:3)

您可以在构建B时使用--undefined选项:

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

答案 3 :(得分:3)

有一种更好的方法来编写FORCE_UNDEFINED_SYMBOL宏。只需将该函数指针强制转换为void *即可。然后它适用于任何功能 - 或者数据。此外,当宏的gcc部分也适用于MSVC时,为什么还要使用MSVC编译指示。所以我的简化版本是:

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

因此使用:

FORCE_UNDEFINED_SYMBOL(Af)

但它必须在包含剥离符号的库的程序中使用。

答案 4 :(得分:0)

尝试将这些行放入B/initB.cpp,以便他们(希望)在链接时强制进入libB.so库。

但为什么你必须以这种方式去做呢?你不能设置它,以便可执行文件引用该函数(或它的调用者),导致链接器自动执行正确的操作吗?

答案 5 :(得分:0)

如果你可以使用gcc的 C ++ 0x 功能( -std = c ++ 0x ),那么函数默认模板参数可以做到这一点。从当前的c ++标准来看,函数模板不允许使用默认参数。在c ++ 0x中启用这些功能后,您可以执行以下操作: -

在静态库的一些头文件中......

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

然后在其对应的cpp文件中使用显式模板实例化...

template void Af();

这将生成函数Af的符号,尽管它尚未被调用/引用。 这不会影响调用者,因为由于默认模板参数,您无需指定类型。只需在函数声明之前添加template <class T = int >,并在其实现文件中显式实例化它。

HTH,