在链接到动态库的静态库中导出符号

时间:2019-05-27 18:28:47

标签: c++ linker static-libraries dynamic-linking dllexport

我在MSVC2017中具有以下情形:

  1. 具有函数bool foo()
  2. 的静态库
  3. 链接到上面的静态库的动态链接库
  4. 使用显式运行时链接加载动态链接库并通过foo()调用GetProcAddress的应用程序

在静态库中,foo()的定义如下:

extern "C" __declspec(dllexport) bool foo() 
{
    return true;   
}

现在,由于动态链接库未使用foo(),因此不会导出其符号,因此在应用程序使用GetProcAddress时找不到该符号。

我尝试过:

#pragma comment(linker, "/include:foo")

和:

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

如果我将定义移至动态链接库(不是可行的解决方案),则可以使用Dependency Walker看到导出的foo(),但是当我将定义保留在静态库中时,似乎无法导出符号使用上述链接器开关。我认为这是因为该符号仍未使用,因此无论如何仍不会导出?

我想要Windows上的MSVC和Linux上的Clang的解决方案。谢谢!

2 个答案:

答案 0 :(得分:0)

最后,我的解决方案是制作一个名为foo()的虚拟函数,以强制导出该编译单元中的所有符号。

答案 1 :(得分:0)

您做错了(或至少没有按照问题中的描述进行操作)。当然,您在答案中发布的内容也可以使用,但这只是一种解决方法,因为“常规”方式应该可以使用。
这是一个小例子。

lib.cpp

extern "C" __declspec(dllexport) bool foo() {
    return true;
}

dll.cpp

extern "C" __declspec(dllexport) bool bar() {
    return false;
}

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056330888]> sopr.bat
*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***

[prompt]> "c:\Install\x86\Microsoft\Visual Studio Community\2017\VC\Auxiliary\Build\vcvarsall.bat" x64
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.13
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

[prompt]> dir /b
dll.cpp
lib.cpp

[prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib.obj lib.cpp
lib.cpp

[prompt]> lib /nologo /out:lib.lib lib.obj

[prompt]>
[prompt]> cl /c /nologo /DDLL /Fodll.obj dll.cpp
dll.cpp

[prompt]> link /nologo /dll /out:dll.dll dll.obj lib.lib
   Creating library dll.lib and object dll.exp

[prompt]> dir /b
dll.cpp
dll.dll
dll.exp
dll.lib
dll.obj
lib.cpp
lib.lib
lib.obj

[prompt]> dumpbin /nologo /exports dll.dll

Dump of file dll.dll

File Type: DLL

  Section contains the following exports for dll.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 00001000 bar

  Summary

        2000 .data
        1000 .pdata
        9000 .rdata
        1000 .reloc
        B000 .text

[prompt]>
[prompt]> rem Re-link dll, instructing it to include foo

[prompt]> link /nologo /dll /include:foo /out:dll.dll dll.obj lib.lib
   Creating library dll.lib and object dll.exp

[prompt]> dumpbin /nologo /exports dll.dll

Dump of file dll.dll

File Type: DLL

  Section contains the following exports for dll.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           2 number of functions
           2 number of names

    ordinal hint RVA      name

          1    0 00001000 bar
          2    1 00001010 foo
  Summary

        2000 .data
        1000 .pdata
        9000 .rdata
        1000 .reloc
        B000 .text

注释

  • 如前所述,我使用了命令行,但是 VStudio IDE
  • 调用了相同的命令(更多参数)
  • 添加/include:foo(2 nd link 命令)也将导出 foo (如下一个 dumpbin中所示) 输出):
    • 指定此选项与添加#pragma comment(linker, "/include:foo")(在 dll.cpp 中-或直接传递到链接器的任何文件)相同
    • /export:foo是不必要的,因为该功能已由__declspec(dllexport)导出
  • 我没有结束(应用程序),因为 dumpbin 输出中包含 foo 就足够了(从 Dependency Walker < / em>)

@ EDIT0

您可能根本没有做错任何事情。看[MS.Docs]: Overview of LIB,它在导出内容方面提供了与 link 相同的选项。但是它们似乎被忽略了。

构建lib时,也许构建 .lib #pragma comment)。 > ,而不是链接时。显然,它们会被忽略(我已经测试过),除非在直接传递给链接器的 .obj 文件(或选项)中指定了内容。我不知道为什么,也许与[MS.Docs]: Building an Import Library and Export File有关:

  

请注意,如果在准备步骤中创建导入库,则在创建.dll之前,必须在构建.dll时传递与构建导入库时传递的对象集相同的对象文件。

无论如何,我尝试通过从 .lib 中提取 lib.obj 来完成上述操作(它的大小与我用来创建的大小不同> .lib ,然后将其传递给链接器,但该函数仍未导出。注意,如果我直接将(原始) lib.obj (带有#pragma comment (linker, /include:foo)传递给链接器,它将导出 foo