你正在做一些错误的事情(或者至少不是你在问题描述中所描述的)。当然,你在答案中发布的内容也可以工作,但那只是一个解决方法,因为“常规”方式应该可以工作。这里有一个小例子。
lib00.cpp:
extern "C" __declspec(dllexport) bool foo()
{
return true;
}
dll00.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 > nul
[prompt]>
[prompt]> dir /b
dll00.cpp
lib00.cpp
[prompt]>
[prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib00.obj lib00.cpp
lib00.cpp
[prompt]>
[prompt]> lib /nologo /out:lib00.lib lib00.obj
[prompt]>
[prompt]> cl /c /nologo /DDLL /Fodll00.obj dll00.cpp
dll00.cpp
[prompt]>
[prompt]> link /nologo /dll /out:dll00.dll dll00.obj lib00.lib
Creating library dll00.lib and object dll00.exp
[prompt]>
[prompt]> dir /b
dll00.cpp
dll00.dll
dll00.exp
dll00.lib
dll00.obj
lib00.cpp
lib00.lib
lib00.obj
[prompt]>
[prompt]> dumpbin /nologo /exports dll00.dll
Dump of file dll00.dll
File Type: DLL
Section contains the following exports for dll00.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
[prompt]>
[prompt]> :: ----- Re-link dll, instructing it to include foo -----
[prompt]>
[prompt]> link /nologo /dll /include:foo /out:dll00.dll dll00.obj lib00.lib
Creating library dll00.lib and object dll00.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00.dll
Dump of file dll00.dll
File Type: DLL
Section contains the following exports for dll00.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
注:
如您所见,我使用了命令行,但相同的命令(更多参数)可以由 VStudio IDE 调用。
添加 /include:foo(第二个 Link 命令)也会导出 foo(正如下一个 DumpBin 输出中所看到的):
指定此选项等同于添加 #pragma comment(linker, "/include:foo")
(在 dll.cpp 或任何直接传递给链接器的文件中)
/export:foo 不是必需的,因为该函数已经由 __declspec(dllexport) 导出
我没有一直跟到最后(应用程序),因为 DumpBin 的输出中出现 foo 就足够了(从 Dependency Walker 也可以看到)。
更新 #0
您可能并没有做错事。但请记住,这不可扩展(如果您有数百个这样的符号)。查看 [MS.Learn]: LIB 概述,它提供与导出相关的与 Link 相同的选项。但它们似乎被忽略了。
当构建 .lib 时,也许您想在链接时指定所有要包含的符号(无论是通过选项还是通过 #pragma comment),当构建 .lib 时而不是在链接时。显然,它们被忽略了(我已经测试过了),除非在直接传递给链接器的 .obj 文件(或选项)中指定。这是因为[MS.Learn]: 构建导入库和导出文件(强调 是我的):
请注意,如果您在创建 .dll 之前进行了预备步骤以创建您的导入库,则 在构建 .dll 时必须传递与构建导入库时相同的一组对象文件。
因此,在将 .obj 文件传递给链接器时存在差异:
这完全是有道理的,因为lib只是一个.obj文件的集合(档案)(在Nix上,archiver是Ar(曾经称为RanLib))。 例如:
输出:
[prompt]> del *.obj *.exp *.lib *.dll
[prompt]>
[prompt]> dir /b
dll00.cpp
lib00.cpp
[prompt]>
[prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib00.obj lib00.cpp
lib00.cpp
[prompt]>
[prompt]> cl /c /nologo /DDLL /Fodll00.obj dll00.cpp
dll00.cpp
[prompt]>
[prompt]> :: Pass lib00.obj directly to linker
[prompt]>
[prompt]> link /nologo /dll /out:dll00.dll dll00.obj lib00.obj
Creating library dll00.lib and object dll00.exp
[prompt]>
[prompt]> lib /nologo /out:lib00.lib lib00.obj
[prompt]>
[prompt]> dir
Volume in drive E is SSD0-WORK
Volume Serial Number is AE9E-72AC
Directory of e:\Work\Dev\StackOverflow\q056330888
23/01/30 09:15 <DIR> .
23/01/30 09:15 <DIR> ..
23/01/30 09:12 72 dll00.cpp
23/01/30 09:14 106,496 dll00.dll
23/01/30 09:14 733 dll00.exp
23/01/30 09:14 1,790 dll00.lib
23/01/30 09:14 604 dll00.obj
23/01/30 09:07 71 lib00.cpp
23/01/30 09:15 822 lib00.lib
23/01/30 09:13 604 lib00.obj
8 File(s) 111,192 bytes
2 Dir(s) 51,727,843,328 bytes free
[prompt]>
[prompt]> dumpbin /nologo /exports dll00.dll
Dump of file dll00.dll
File Type: DLL
Section contains the following exports for dll00.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
[prompt]>
[prompt]> :: Now do the same with the one from inside the .lib
[prompt]>
[prompt]> del lib00.obj
[prompt]>
[prompt]> lib lib00.lib /extract:lib00.obj
Microsoft (R) Library Manager Version 14.16.27048.0
Copyright (C) Microsoft Corporation. All rights reserved.
[prompt]>
[prompt]> dir lib00.obj
Volume in drive E is SSD0-WORK
Volume Serial Number is AE9E-72AC
Directory of e:\Work\Dev\StackOverflow\q056330888
23/01/30 09:16 604 lib00.obj
1 File(s) 604 bytes
0 Dir(s) 51,727,839,232 bytes free
[prompt]>
[prompt]> link /nologo /dll /out:dll00.dll dll00.obj lib00.obj
Creating library dll00.lib and object dll00.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00.dll
Dump of file dll00.dll
File Type: DLL
Section contains the following exports for dll00.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
更新 #1
我简要尝试了一下[MS.Learn]: 链接器选项(/INCLUDE和/EXPORT)。增加了一些复杂度。
lib01.cpp:
#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
lib10.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]>
[prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib01.obj lib01.cpp
lib01.cpp
[prompt]>
[prompt]> cl /c /nologo /D_LIB /DSTATIC /Folib10.obj lib10.cpp
lib10.cpp
[prompt]>
[prompt]> lib /nologo /out:lib0110.lib lib01.obj lib10.obj
[prompt]>
[prompt]> cl /c /nologo /DDLL /Fodll00.obj dll00.cpp
dll00.cpp
[prompt]>
[prompt]> :: ----- "Regular" behavior -----
[prompt]>
[prompt]> link /nologo /dll /out:dll00.dll dll00.obj lib0110.lib
Creating library dll00.lib and object dll00.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00.dll
Dump of file dll00.dll
File Type: DLL
Section contains the following exports for dll00.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
[prompt]>
[prompt]> :: ----- /export a symbol -----
[prompt]>
[prompt]> link /nologo /dll /out:dll00_export.dll /export:foo02 dll00.obj lib0110.lib
Creating library dll00_export.lib and object dll00_export.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00_export.dll
Dump of file dll00_export.dll
File Type: DLL
Section contains the following exports for dll00_export.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 0000E1A0 foo02
Summary
2000 .data
1000 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
[prompt]>
[prompt]> :: ----- /include a symbol -----
[prompt]>
[prompt]> link /nologo /dll /out:dll00_include.dll /include:foo02 dll00.obj lib0110.lib
Creating library dll00_include.lib and object dll00_include.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00_include.dll
Dump of file dll00_include.dll
File Type: DLL
Section contains the following exports for dll00_include.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
如同(就像在 Docs中看到的):
结论
深入研究后发现[MS.Learn]: /WHOLEARCHIVE(包括所有库对象文件)说明了以下内容(我加粗了强调部分):
/WHOLEARCHIVE选项会强制链接器从指定的静态库中包含每个对象文件,或者如果未指定库,则从指定给LINK命令的所有静态库中都包含。
...
/WHOLEARCHIVE选项是在Visual Studio 2015 Update 2中引入的。
输出结果:
[prompt]> :: ----- YAY ----- /wholearchive ----- YAY -----
[prompt]>
[prompt]> link /nologo /dll /out:dll00_wholearchive.dll /wholearchive:lib0110.lib dll00.obj lib0110.lib
Creating library dll00_wholearchive.lib and object dll00_wholearchive.exp
[prompt]>
[prompt]> dumpbin /nologo /exports dll00_wholearchive.dll
Dump of file dll00_wholearchive.dll
File Type: DLL
Section contains the following exports for dll00_wholearchive.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 .gehcont
1000 .gxfg
1000 .pdata
9000 .rdata
1000 .reloc
E000 .text
/include:foo
(强制将该符号包含在DLL中)和/export:foo
(导出该符号)选项吗?你可能需要使用名称混淆(_foo@0
或类似的名称)。 - 1201ProgramAlarm