如何通过命令行设置 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