Visual Studio 中的 GCC 样式弱链接?

Posted

技术标签:

【中文标题】Visual Studio 中的 GCC 样式弱链接?【英文标题】:GCC style weak linking in Visual Studio? 【发布时间】:2010-02-18 17:09:00 【问题描述】:

GCC 能够通过__attribute__((weak)) 进行弱符号链接。我想在用户可以在其应用程序中覆盖的静态库中使用弱符号。 GCC 风格的弱符号可以让我这样做,但我不知道它是否可以用 Visual Studio 完成。

Visual Studio 是否提供类似的功能?

【问题讨论】:

见Windows Static Library with Default Functions。这是您想要实现的目标吗? 查看answer by Michael Burr -- MSVC 实际上默认 对此行为。如果您覆盖已在依赖库中定义的符号,.lib 中的符号将被忽略。 VC++ 没有公开将符号声明为弱的明确方式——但有两种选择接近。检查:ofekshilon.com/2014/02/10/linker-weak-symbols 【参考方案1】:

你可以做到,这里有一个C语言的例子:

/*
 * pWeakValue MUST be an extern const variable, which will be aliased to
 * pDefaultWeakValue if no real user definition is present, thanks to the
 * alternatename directive.
 */

extern const char * pWeakValue;
extern const char * pDefaultWeakValue = NULL;

#pragma comment(linker, "/alternatename:_pWeakValue=_pDefaultWeakValue")

【讨论】:

这是一个正确的答案。你能找到一些文档来备份它吗? 这是一个未记录的功能。我在浏览 msvcrt 源代码时偶然发现了它。 @Ringo 如果pWeakValue 已经定义了,它仍然可以被alternatename 选项替换。 至少在 VS2019 中,这也适用于函数,只要它们在 C++ 代码中声明为 extern "C"。至少我无法让它与损坏的 C++ 函数名称一起使用,但它确实与 extern "C" 函数一起使用。 Raymond Chen 写了一篇关于 /ALTERNATENAME 链接器开关的博文devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024【参考方案2】:

MSVC++ 有__declspec(selectany),它涵盖了弱符号的部分功能:它允许您使用外部链接定义多个相同的符号,指示编译器选择几个可用符号中的任何一个。但是,我认为 MSVC++ 没有任何东西可以涵盖弱符号功能的另一部分:在库中提供“可替换”定义的可能性。

顺便说一句,这让人想知道对标准可替换 ::operator new::operator delete 函数的支持如何在 MSVC++ 中工作。

【讨论】:

MSVC++ 是否有类似这个宏的东西可以与main() 一起使用,以便让包括this 文件在内的任何代码覆盖main() ::operator newnothrownew.obj 中作为目标代码提供。我假设 CRT 使用与 __fltused-trick 类似的概念来将目标代码拉入模块,除非它已在其他地方定义。 OBJ 和 LIB 的经典链接器规则在 The Old New Thing 中进行了描述。 @IInspectable 固定链接:Understanding the classical model for linking: You can override an LIB with another LIB, and a LIB with an OBJ, but you can’t override an OBJ.【参考方案3】:

MSVC 过去的行为是,如果在 .obj 文件和 .lib 中定义符号,它将使用 .obj 文件中的符号而不会发出警告。我记得它还可以处理符号在多个库中定义的情况,它将使用库中列表中第一个命名的库。

我不能说我已经尝试过一段时间了,但是如果他们改变了这种行为(尤其是 .obj 定义的符号会覆盖 .lib 文件中的符号),我会感到惊讶。

【讨论】:

对 VS 2010 RC 的简短测试表明我描述的行为仍然存在。 在某种程度上我更喜欢这种行为而不是弱属性。据我所知,这一直是 MS 编译器中的行为(自 1988 年以来一直使用 MS 编译器(C5.0)。几年前我在 GCC 中遇到它时对此感到困惑。我认为使用它是合乎逻辑的链接时找到的第一次出现的函数,尽管必须注意链接的是你认为的函数。 为什么微软不能让这更explicit?而且我找不到任何描述这种行为的官方文件。我想知道这是设计使然还是偶然...【参考方案4】:

我知道的唯一方法。将每个符号放在单独的库中。具有覆盖的用户对象也必须组合到库中。然后将所有内容链接到一个应用程序。用户库必须指定为输入文件,您的库必须使用/DEFAULTLIB: 选项传输到链接器。

【讨论】:

【参考方案5】:

没有与此属性等效的 MS-VC。见http://connect.microsoft.com/VisualStudio/feedback/details/505028/add-weak-function-references-for-visual-c-c。我要提出一些可怕的建议:在这里阅读它的目的:http://www.kolpackov.net/pipermail/notes/2004-March/000006.html 它本质上是定义函数,如果它们的符号存在,则使用,否则不使用,所以......

为什么不为此目的使用预处理器,并提出“如果您需要这样做”的巨大警告? (我不喜欢推荐预处理器)。

例子:

#ifdef USE_MY_FUNCTION
     extern void function();
#endif

然后在应用程序逻辑中适当地调用,由#ifdef 语句包围。如果您的静态库已链接,作为链接过程的一部分,请调整定义以定义 USE_MY_FUNCTION。

不是很直接的等价物,而且非常丑陋,但这是我能想到的最好的。

【讨论】:

【参考方案6】:

来自here:

...如果不需要咨询图书馆就可以满足所需的符号, 那么库中的OBJ将不会被使用。 这使您可以覆盖 通过将符号显式放置为 OBJ 将符号放入库中。你也可以 覆盖库中的符号以将其放入另一个库中 在您要覆盖的搜索之前进行搜索。但您不能 覆盖显式 OBJ 中的符号,因为它们是 初始条件。

这种行为是由链接器采用的算法引起的。

所以简而言之,覆盖一个函数,

使用 GCC,您必须使用 __attribute__((weak))。您不能依赖目标文件在链接器中的输入顺序来决定使用哪个函数实现。

使用 VS 工具链,您可以依赖对象/lib 文件的顺序,并且您必须将函数的实现放在实现原始函数的 LIB 之前。您可以将您的实现作为 OBJ 或 LIB。

【讨论】:

以上是关于Visual Studio 中的 GCC 样式弱链接?的主要内容,如果未能解决你的问题,请参考以下文章

在Visual Studio或GCC中使用表情符号作为c ++中的标识符名称

是否有视觉(例如 Visual Studio 中的 nuget 样式)包管理器?

为啥使用 Visual Studio 而不是 GCC 编译时没有错误?

为啥 cygwin 使用 Visual Studio BuildTools 而不是 gcc?

如何共享Visual Studio 2017代码样式和格式?

为啥 gcc 的输出比 Visual Studio 慢得多(对于此代码)?