如何通过命令行设置 VC++ 动态链接?
How does one setup VC++ dynamic linking via command-line?
虽然我通过 Visual Studio 设置 运行-time DLL 加载没有问题,但我在通过 Visual Studio CLI 工具手动执行时遇到了一些问题。
假设我们有以下 2 个我们想要编译的简单 C++ 源文件,一个用于二进制可执行文件,一个用于 DLL:
main.cpp
void say_hello();
int main()
{
say_hello();
return 0;
}
say_hello.cpp
#include <stdio.h>
void say_hello()
{
printf("Hello DLL World!");
}
将 say_hello.cpp
文件编译为 DLL 然后通过 main.cpp
的调用动态 link 它的步骤是什么?
根据我通读的 MSDN 文档,我能够成功编译 say_hello.dll
和应用程序,然后 运行 它并使用以下命令:
cl say_hello.cpp /LD
lib say_hello.obj
cl say_hello.lib main.cpp
不幸的是,这似乎只允许通过 say_hello.lib
文件静态 linking 应用程序(这可以通过删除 .lib 和 .dll 文件来确认,这仍然允许二进制 运行 成功)。
我必须将什么 commands/parameters 传递到 compiling/linking 阶段才能让 main.exe
使用 DLL 而不是静态库?
这是一个例子。并非每件事都是完全必要的(例如 DLLMain),但我认为这些是您应该查找的东西 ;-)
SayHello.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
// see https://msdn.microsoft.com/en-us/library/56h2zst2.aspx : Decorated Names
extern "C" { // somehow making it superfluous to put the code in SayHello.cPP ...but anyway ;-)
// see https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx : dllexport, dllimport
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx : (optional) DllMain entry point
BOOL WINAPI DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
}
main.cpp
extern "C" { __declspec(dllimport) void say_hello(); } // we did this in SayHello.cpp, so we have to do it here too.
// otherwise the name wouldn't match
int main() {
say_hello();
return 0;
}
然后是compiling/linking
cl /D_USRDLL /D_WINDLL SayHello.cpp /LD /link /OUT:SayHello.dll
/LD 告诉 linker 构建一个 DLL 和 以使用 /MT,参见 /MD, /MT, /LD (Use Run-Time Library)。 (通过 OUT: 参数,您 可以 更改 .dll 的名称;这里是默认名称,仅用于演示目的。如果您省略它,您也可以跳过 /link 参数,因为将不再有 linker 参数。)
cl.exe /MT main.cpp /link /SUBSYSTEM:CONSOLE "SayHello.lib"
匹配 dll 的 运行-time 库设置,创建 console application (main.cpp has a int main()
) and linking the stub lib of SayHello (instead of using LoadLibrary("SayHello.dll")/GetProcAddress(...))
我将 VolkerK 的答案标记为正确,因为它包含一些其他重要的 Windows DLL API 绝对值得一读的详细信息,但我想总结一下 根据 Igor Tandetnik 和 VolkerK 的评论,最小 更改可以使动态链接在最简单的示例中正常工作。
在DLL中至少要导出一个函数之前添加宏__declspec(dllexport)
是必须的,否则库编译命令不会创建导入库来指示哪些函数可用用于动态链接。
第二个 "lib say_hello.obj" 是完全错误的,因为 DLL 编译命令将正确生成 say_hello.lib(而 lib 命令只会生成一个静态库并最终覆盖第一个命令)。
这是最基本的完整工作示例:
main.cpp
void say_hello();
int main()
{
say_hello();
return 0;
}
say_hello.cpp
#include <stdio.h>
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
编译命令:
cl say_hello.cpp /LD
cl main.cpp say_hello.lib
虽然我通过 Visual Studio 设置 运行-time DLL 加载没有问题,但我在通过 Visual Studio CLI 工具手动执行时遇到了一些问题。
假设我们有以下 2 个我们想要编译的简单 C++ 源文件,一个用于二进制可执行文件,一个用于 DLL:
main.cpp
void say_hello();
int main()
{
say_hello();
return 0;
}
say_hello.cpp
#include <stdio.h>
void say_hello()
{
printf("Hello DLL World!");
}
将 say_hello.cpp
文件编译为 DLL 然后通过 main.cpp
的调用动态 link 它的步骤是什么?
根据我通读的 MSDN 文档,我能够成功编译 say_hello.dll
和应用程序,然后 运行 它并使用以下命令:
cl say_hello.cpp /LD
lib say_hello.obj
cl say_hello.lib main.cpp
不幸的是,这似乎只允许通过 say_hello.lib
文件静态 linking 应用程序(这可以通过删除 .lib 和 .dll 文件来确认,这仍然允许二进制 运行 成功)。
我必须将什么 commands/parameters 传递到 compiling/linking 阶段才能让 main.exe
使用 DLL 而不是静态库?
这是一个例子。并非每件事都是完全必要的(例如 DLLMain),但我认为这些是您应该查找的东西 ;-)
SayHello.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
// see https://msdn.microsoft.com/en-us/library/56h2zst2.aspx : Decorated Names
extern "C" { // somehow making it superfluous to put the code in SayHello.cPP ...but anyway ;-)
// see https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx : dllexport, dllimport
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx : (optional) DllMain entry point
BOOL WINAPI DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
}
main.cpp
extern "C" { __declspec(dllimport) void say_hello(); } // we did this in SayHello.cpp, so we have to do it here too.
// otherwise the name wouldn't match
int main() {
say_hello();
return 0;
}
然后是compiling/linking
cl /D_USRDLL /D_WINDLL SayHello.cpp /LD /link /OUT:SayHello.dll
/LD 告诉 linker 构建一个 DLL 和 以使用 /MT,参见 /MD, /MT, /LD (Use Run-Time Library)。 (通过 OUT: 参数,您 可以 更改 .dll 的名称;这里是默认名称,仅用于演示目的。如果您省略它,您也可以跳过 /link 参数,因为将不再有 linker 参数。)
cl.exe /MT main.cpp /link /SUBSYSTEM:CONSOLE "SayHello.lib"
匹配 dll 的 运行-time 库设置,创建 console application (main.cpp has a int main()
) and linking the stub lib of SayHello (instead of using LoadLibrary("SayHello.dll")/GetProcAddress(...))
我将 VolkerK 的答案标记为正确,因为它包含一些其他重要的 Windows DLL API 绝对值得一读的详细信息,但我想总结一下 根据 Igor Tandetnik 和 VolkerK 的评论,最小 更改可以使动态链接在最简单的示例中正常工作。
在DLL中至少要导出一个函数之前添加宏
__declspec(dllexport)
是必须的,否则库编译命令不会创建导入库来指示哪些函数可用用于动态链接。第二个 "lib say_hello.obj" 是完全错误的,因为 DLL 编译命令将正确生成 say_hello.lib(而 lib 命令只会生成一个静态库并最终覆盖第一个命令)。
这是最基本的完整工作示例:
main.cpp
void say_hello();
int main()
{
say_hello();
return 0;
}
say_hello.cpp
#include <stdio.h>
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
编译命令:
cl say_hello.cpp /LD
cl main.cpp say_hello.lib