使用 MinGW 和 wclang 交叉编译 DLL 时,我真的需要 __declspec(dllexport) 吗?

Do I really need __declspec(dllexport) when cross-compiling a DLL with MinGW and wclang?

这里有类似的问题,但没有完全回答我的问题:

当我使用 MinGW 和 wclang 从 Mac OS X 交叉编译 DLL 时,为什么我的 DLL 可以在不使用 [=14= 的情况下正常工作]?

MinGW DLL sample docs,以及我看到的每一个参考,都说在函数声明之前使用 __declspec(dllexport)。然而,我的 9,000 行库中的 none 代码使用了它,并且 DLL 运行良好!

例如,这是一个以相同方式构建的人为示例库:

#include <stdio.h>

extern "C" {

int hello(const char* name) {
  printf("Hello, %s!\n", name);
  return 0;
}

}

在 Mac OS X 10.10.3:

上编译
w32-clang++ test.cpp -shared -o test.dll

生成美观的 DLL:

我的 Windows 申请:

#include "stdafx.h"
#include <Windows.h>
#include <iostream>

typedef int(*hellofn)(const char*);

int _tmain(int argc, _TCHAR* argv[])
{
  DWORD err;

  HINSTANCE dll = LoadLibrary(L"E:\test.dll");
  if (!dll) {
    err = GetLastError();
    std::cout << "Can't load library: " << err << std::endl;
    return 1;
  }

  hellofn hello = (hellofn)GetProcAddress(dll, "hello");
  if (!hello) {
    err = GetLastError();
    std::cout << "Could not load the function: " << err << std::endl;
    return 2;
  }

  int ret = hello("nerd");
  std::cout << "hello() returned " << ret << std::endl;

  return 0;
}

效果很好:

我是不是搬起石头砸自己的脚,还是有什么魔法我没看到?我在想 wclang (MinGW+clang) 知道以某种方式自动使用 __stdcall 并且不会破坏函数名称?

不,在使用 MinGW 构建 DLL 时,您不需要__declspec(dllexport); (事实上​​ ,我自己经常省略它)。需要注意的是,如果只有一个要包含在 DLL 中的符号被如此装饰,那么您希望导出的所有其他符号 必须 同样被装饰,(除非您通过 --export-all-symbols 构建 DLL 时链接器的选项)。

如果您只包含 未修饰的 符号,那么将导出所有全局符号,就像默认指定 --export-all-symbols 一样。

但是,这与 __stdcall__cdecl 调用约定或名称修改没有任何关系;它只是 DLL 导出中符号可见性的决定因素 table。如果您不将函数声明为 __stdcall__cdecl,那么它们将默认为 __cdecl;这没问题,前提是提供 DLL 和调用者都同意该约定。同样,如果双方就任何名称修改约定达成一致(这通常意味着,特别是在 C++ 的情况下,他们在构建时都使用相同的编译器),那么就不会有链接问题。