在链接到动态库的静态库中导出符号 [英] Exporting symbols in static library that is linked to dynamic library
问题描述
我在MSVC2017中具有以下情形:
I have the following scenario in MSVC2017:
- 具有功能
bool foo()
的静态库
- 一个动态链接库,链接到上面的静态库
- 使用显式运行时链接加载动态链接库并通过
GetProcAddress
调用
foo()
的应用程序
- A static library with the function
bool foo()
- A dynamic link library that links to the static library above
- An application that loads the dynamic link library using explicit run-time linking and calls
foo()
viaGetProcAddress
在静态库中,foo()
的定义如下:
In the static library, foo()
is defined as follows:
extern "C" __declspec(dllexport) bool foo()
{
return true;
}
现在,由于动态链接库未使用foo()
,因此不会导出其符号,因此在应用程序使用GetProcAddress
时找不到该符号.
Now, because foo()
is not used by the dynamic link library, its symbol is not exported and thus not findable when the application used GetProcAddress
.
我尝试过:
#pragma comment(linker, "/include:foo")
和:
#pragma comment(linker, "/export:foo")
如果我将定义移至动态链接库(不是可行的解决方案),则可以使用Dependency Walker查看导出的foo()
,但是当我将定义保留在静态库中时,我似乎无法导出符号.链接器开关上方.我认为这是因为该符号仍未使用,因此无论如何仍不会导出?
I can see the exported foo()
using Dependency Walker if I move the definition to the dynamic link library (not a viable solution) but I cannot seem to get the symbol exported when I keep the definition in the static library with the above linker switches. I presume this is because the symbol is still not used, and thus still not exported regardless?
我想要Windows上的MSVC和Linux上的Clang的解决方案.谢谢!
I would like a solution for both MSVC on Windows and Clang on Linux. Thanks!
推荐答案
您做错了(或至少没有按照问题中的描述进行操作).当然,您在答案中发布的内容也可以使用,但这只是一种解决方法,因为常规"方式应该可以使用.
这是一个小例子.
You're doing something wrong (or at least not as you describe in the question). Of course, what you posted in your answer works as well, but that's only a workaround, as the "regular" way should work.
Here's a small example.
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\pc032\Microsoft\VisualStudioCommunity\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]> :: ----- Re-link dll, instructing it to include foo -----
[prompt]>
[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) 导出
- As noticed, I used command line, but the same commands (more arguments) are invoked by VStudio IDE
- Adding /include:foo (2nd link command) exports foo as well (as seen in the next dumpbin output):
- Specifying this option is identical to adding
#pragma comment(linker, "/include:foo")
(in dll.cpp - or any file that is being directly passed to the linker) - /export:foo is not necessary, as the function is already exported by __declspec(dllexport)
您可能根本没有做错任何事情.但是请记住,它不可扩展(如果您有数百个这样的符号).查看 [MS.Docs]:LIB概述,它在导出内容方面提供与 link 相同的选项.但是它们似乎被忽略了.
You might not be doing things wrong after all. But bear in mind that it's not scalable (if you have hundreds of such symbols). Looking at [MS.Docs]: Overview of LIB, it provides the same options as link in regards to exporting stuff. But they seem to be ignored.
在构建lib时,当构建时,可能希望指定链接时要包含的所有符号(通过选项或通过 #pragma注释). .lib ,而不是链接时.显然,它们会被忽略(我已经对其进行了测试),除非在直接传递给链接器的 .obj 文件(或选项)中指定了内容.这是因为 [ MS.Docs]:构建导入库和导出文件(重点是我的):
When building a lib, maybe one would like to specify all the symbols to be included at link time (either via option or via #pragma comment), when building the .lib, and not when linking. Apparently, they are ignored (I've tested it), unless stuff is specified in .obj files (or options) passed directly to the linker. This is because [MS.Docs]: Building an Import Library and Export File (emphasis is mine):
请注意,如果在准备步骤中创建导入库,则在创建.dll之前,在构建.dll时必须传递与在构建导入库时传递的对象文件集相同的对象文件 strong>.
Note that if you create your import library in a preliminary step, before creating your .dll, you must pass the same set of object files when building the .dll, as you passed when building the import library.
因此,将 .obj 文件传递到链接器时会有所不同:
So there's a difference when passing an .obj file to the linker:
- 直接(命令行):它包含在 .dll (或 .exe ) 中
- 间接(通过命令行传递的 .lib 的一部分):它不包含在 .dll 中,仅搜索符号
- Directly (command line): it is included in the .dll (or .exe)
- Indirectly (part of a .lib passed via command line): it is not included in the .dll, it is only searched for symbols
这完全有道理,因为lib只是 .obj 文件的集合(存档)(在 Nix 上,存档器是 ar (以前称为 ranlib )).一个例子:
This totally makes sense as a lib is just a collection (archive) of .obj files (on Nix the archiver is ar (formerly known as ranlib)). An example:
输出:
[prompt]> del *.obj *.exp *.lib *.dll [prompt]> dir /b dll.cpp lib.cpp [prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib.obj lib.cpp lib.cpp [prompt]> cl /c /nologo /DDLL /Fodll.obj dll.cpp dll.cpp [prompt]> :: Pass lib.obj directly to linker [prompt]> link /nologo /dll /out:dll.dll dll.obj lib.obj Creating library dll.lib and object dll.exp [prompt]> lib /nologo /out:lib.lib lib.obj [prompt]> [prompt]> dir Volume in drive E is SSD0-WORK Volume Serial Number is AE9E-72AC Directory of e:\Work\Dev\StackOverflow\q056330888 20/04/08 14:28 <DIR> . 20/04/08 14:28 <DIR> .. 19/06/30 20:03 114 dll.cpp 20/04/08 14:27 88,576 dll.dll 20/04/08 14:27 729 dll.exp 20/04/08 14:27 1,764 dll.lib 20/04/08 14:27 604 dll.obj 20/04/08 14:04 68 lib.cpp 20/04/08 14:28 822 lib.lib 20/04/08 14:27 604 lib.obj 8 File(s) 93,281 bytes 2 Dir(s) 83,419,111,424 bytes free [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 [prompt]> :: Now do the same with the one from inside the .lib [prompt]> del lib.obj [prompt]> lib lib.lib /extract:lib.obj Microsoft (R) Library Manager Version 14.16.27038.0 Copyright (C) Microsoft Corporation. All rights reserved. [prompt]> dir lib.obj Volume in drive E is SSD0-WORK Volume Serial Number is AE9E-72AC Directory of e:\Work\Dev\StackOverflow\q056330888 20/04/08 14:28 604 lib.obj 1 File(s) 604 bytes 0 Dir(s) 83,419,107,328 bytes free [prompt]> link /nologo /dll /out:dll.dll dll.obj lib.obj 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 .tex
我简短地玩过 [MS.Docs]:链接器选项( /INCLUDE 和 /EXPORT ).添加了一些复杂性.
I played briefly with [MS.Docs]: Linker options (/INCLUDE and /EXPORT). Added a bit of complexity into the mix.
lib0.cpp :
//#pragma comment(linker, "/include:foo1") // Apparently, has no effect in an .obj contained by a .lib #pragma comment(linker, "/export:foo01") #if defined(__cplusplus) extern "C" { #endif __declspec(dllexport) bool foo00() { return true; } bool foo01() { return true; } bool foo02() { return true; } #if defined(__cplusplus) } #endif
lib1.cpp :
#pragma comment(linker, "/export:foo11") #if defined(__cplusplus) extern "C" { #endif __declspec(dllexport) bool foo10() { return true; } bool foo11() { return true; } bool foo12() { return true; } #if defined(__cplusplus) } #endif
输出:
[prompt]> del *.obj *.exp *.lib *.dll [prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib0.obj lib0.cpp lib0.cpp [prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib1.obj lib1.cpp lib1.cpp [prompt]> lib /nologo /out:lib.lib lib0.obj lib1.obj [prompt]> cl /c /nologo /DDLL /Fodll.obj dll.cpp dll.cpp [prompt]> :: ----- "Regular" behavior ----- [prompt]> link /nologo /dll /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 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]> :: ----- /export a symbol ----- [prompt]> link /nologo /dll /out:dll.dll /export:foo02 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 0000BB60 foo02 Summary 2000 .data 1000 .pdata 9000 .rdata 1000 .reloc B000 .text [prompt]> [prompt]> :: ----- /include a symbol ----- [prompt]> link /nologo /dll /out:dll.dll /include:foo02 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 3 number of functions 3 number of names ordinal hint RVA name 1 0 00001000 bar 2 1 00001010 foo00 3 2 00001020 foo01 Summary 2000 .data 1000 .pdata 9000 .rdata 1000 .reloc B000 .text
所见(就像在 doc s中一样):
As seen (just like in the docs):
- /EXPORT :(在 .lib 中)搜索符号( foo02 )并仅导出它
- /INCLUDE :在 .lib 中搜索符号( foo02 ),获得包含目标文件( lib0.obj ),并将其包含在 .dll 中:
- 因此,将导出在 .obj 文件中标记为要导出的其他2个符号( foo00 , foo01 ) >
- /EXPORT: searches (in the .lib) for the symbol (foo02) and simply exports it
- /INCLUDE: searches (in the .lib) for the symbol (foo02), gets the containing object file (lib0.obj), and includes it in the .dll:
- As a consequence, the other 2 symbols (foo00, foo01) marked for export in the .obj file are exported
深入了解并发现 [MS.Docs]:/WHOLEARCHIVE(包括所有库对象文件) ,其中指出(强调是我的):
Took a deeper look and found [MS.Docs]: /WHOLEARCHIVE (Include All Library Object Files) which states (emphasis is mine):
/WHOLEARCHIVE选项强制链接器从指定的静态库中包括每个目标文件,或者,如果未指定库,则从所有静态库中 LINK命令.
...
/WHOLEARCHIVE选项是Visual Studio 2015 Update 2中引入的.The /WHOLEARCHIVE option forces the linker to include every object file from either a specified static library, or if no library is specified, from all static libraries specified to the LINK command.
...
The /WHOLEARCHIVE option was introduced in Visual Studio 2015 Update 2.输出:
[prompt]> :: ----- YAY ----- /wholearchive ----- YAY ----- [prompt]> link /nologo /dll /out:dll.dll /wholearchive:lib.lib 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 5 number of functions 5 number of names ordinal hint RVA name 1 0 00001000 bar 2 1 00001040 foo00 3 2 00001050 foo01 4 3 00001010 foo10 5 4 00001020 foo11 Summary 2000 .data 1000 .pdata 9000 .rdata 1000 .reloc B000 .text
这篇关于在链接到动态库的静态库中导出符号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- Specifying this option is identical to adding
- 指定此选项与添加