你做错了什么(或者至少不是你在问题中描述的那样)。当然,您在答案中发布的内容也有效,但这只是一种解决方法,因为“常规”方式应该有效。
这是一个小例子。
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(2ndlink 命令)导出 foo 以及(在下一个 dumpbin 输出中可以看到):
- 指定此选项等同于添加
#pragma comment(linker, "/include:foo")(在dll.cpp - 或任何直接传递给链接器的文件中)
-
/export:foo 不是必需的,因为该函数已经由 __declspec(dllexport) 导出
- 我没有完成最后(应用程序),因为 foo 存在于 dumpbin 输出中就足够了(从 Dependency Walker)
更新#0
毕竟你可能没有做错事。但请记住,它不可扩展(如果您有数百个这样的符号)。查看[MS.Docs]: Overview of LIB,它在导出内容方面提供了与link 相同的选项。但它们似乎被忽略了。
在构建一个库时,可能希望在构建 时指定在链接时包含的所有符号(通过选项或通过 #pragma 注释) .lib,而不是在链接时。显然,它们被忽略(我已经测试过了),除非在直接传递给链接器的 .obj 文件(或选项)中指定了东西。这是因为[MS.Docs]: Building an Import Library and Export File(强调是我的):
请注意,如果您在初步步骤中创建导入库,则在创建 .dll 之前,您必须在构建 .dll 时传递与构建导入库时相同的一组目标文件强>。
所以在将 .obj 文件传递给链接器时是有区别的:
- 直接(命令行):包含在.dll(或.exe)中
- 间接(通过命令行传递的 .lib 的一部分):它不包含在 .dll 中,仅搜索符号
这完全有道理,因为 lib 只是 .obj 文件的集合(存档)(在 Nix 上,存档器是 ar (以前称为 ranlib))。一个例子:
输出:
[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
更新#1
我和[MS.Docs]: Linker options(/INCLUDE 和 /EXPORT)玩了一会儿。增加了一些复杂性。
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
如所见(就像在 docs 中一样):
-
/EXPORT:搜索(在 .lib 中)符号 (foo02) 并简单地导出它李>
-
/INCLUDE:搜索(在.lib中)符号(foo02),获取包含的目标文件(lib0.obj),并将其包含在 .dll 中:
- 因此,.obj 文件中标记为导出的其他 2 个符号(foo00、foo01)被导出
结论
深入研究后发现 [MS.Docs]: /WHOLEARCHIVE (Include All Library Object Files) 声明(强调是我的):
/WHOLEARCHIVE 选项强制链接器包含来自指定静态库的每个目标文件,或者如果未指定库,则来自所有静态库指定给链接命令。
...
Visual Studio 2015 Update 2 中引入了 /WHOLEARCHIVE 选项。
输出:
[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