【问题标题】:How to let MinGW compiled program link to dll built by cygwin?如何让MinGW编译的程序链接到cygwin构建的dll?
【发布时间】:2022-11-13 17:50:42
【问题描述】:

我的程序使用了一些包含 POSIX 函数调用并且不能用 MinGW 编译的库,我将 Qt6 用于 MinGW(没有 Qt6 用于 cygwin 或 msys2)。所以我需要让我的程序链接到由cygwin构建的dll。它链接成功,但无法运行。

例如,这里有两个文件a.c和b.c:

/* a.c */
int a() {
  return 1;
}
/* b.c */
extern int a();

int main() {
  return a();
}

我使用 cygwin 将 a.c 编译为 a.dll:

(In cygwin shell)
$ gcc -c a.c -o a.o
$ gcc -shared a.o -o a.dll
$ ldd a.dll
        ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x7ff9d5450000)
        KERNEL32.DLL => /cygdrive/c/Windows/System32/KERNEL32.DLL (0x7ff9d50f0000)
        KERNELBASE.dll => /cygdrive/c/Windows/System32/KERNELBASE.dll (0x7ff9d2e90000)
        msvcrt.dll => /cygdrive/c/Windows/System32/msvcrt.dll (0x7ff9d5370000)
        cygwin1.dll => /cygdrive/c/Users/notify/Documents/cygwin1.dll (0x180040000)
        advapi32.dll => /cygdrive/c/Windows/System32/advapi32.dll (0x7ff9d3b70000)
        sechost.dll => /cygdrive/c/Windows/System32/sechost.dll (0x7ff9d3c20000)
        RPCRT4.dll => /cygdrive/c/Windows/System32/RPCRT4.dll (0x7ff9d51b0000)
        CRYPTBASE.DLL => /cygdrive/c/Windows/SYSTEM32/CRYPTBASE.DLL (0x7ff9d2440000)
        bcryptPrimitives.dll => /cygdrive/c/Windows/System32/bcryptPrimitives.dll (0x7ff9d2b50000)

然后我使用 MinGW 编译 b.c 并将其链接到 a.dll:

(In MSYS2 MINGW64 shell)
$ gcc -c b.c -o b.o
$ gcc b.o -L. a.dll -o b.exe
$ ldd b.exe
        ntdll.dll => /c/Windows/SYSTEM32/ntdll.dll (0x7ff9d5450000)
        KERNEL32.DLL => /c/Windows/System32/KERNEL32.DLL (0x7ff9d50f0000)
        KERNELBASE.dll => /c/Windows/System32/KERNELBASE.dll (0x7ff9d2e90000)
        msvcrt.dll => /c/Windows/System32/msvcrt.dll (0x7ff9d5370000)
        a.dll => /c/Users/notify/Documents/a.dll (0x5e4da0000)
        cygwin1.dll => /c/Users/notify/Documents/cygwin1.dll (0x180040000)
$ ./b.exe
      0 [main] b (1828) C:\Users\notify\Documents\b.exe: *** fatal error - cygheap base mismatch det
ected - 0x180350408/0x18034C408.
This problem is probably due to using incompatible versions of the cygwin DLL.
Search for cygwin1.dll using the Windows Start->Find/Search facility
and delete all but the most recent version.  The most recent version *should*
reside in x:\cygwin\bin, where 'x' is the drive on which you have
installed the cygwin distribution.  Rebooting is also suggested if you
are unable to find another cygwin DLL.

我怎么解决这个问题?

【问题讨论】:

    标签: c cygwin mingw


    【解决方案1】:

    回答

    不要混合使用 MinGW 和 Cygwin 二进制文件!

    事实上,您应该将它们视为不同的平台:

    • MinGW / MinGW-w64 以原生 Windows 为目标
    • Cygwin 不针对本机 Windows,而是使用 POSIX 兼容层。

    它们的标准库不同且彼此不兼容。

    这也适用于 MSVC,因此也不要将 MinGW / MinGW-w64 或 Cygwin 与 MSVC 混合使用。

    解决方案

    使用相同的编译器编译项目的所有组件和依赖项。

    一些技巧

    更喜欢 MinGW-w64

    最好尽可能使用 MinGW / MinGW-w64,因为它针对本机 Windows。

    参数:

    • Cygwin 构建将需要重新分发 Cygwin DLL 以及您的应用程序,当您希望它可用于其他系统或人员时。
    • Cygwin 兼容层可能会导致开销,因此您的应用程序的性能可能低于使用 MinGW / MinGW-w64 构建时的性能

    最后:MinGW-w64 比 MinGW 更新,所以你应该使用 MinGW-w64 而不是 MinGW。 MinGW-w64 支持 32 位和 64 位 Windows。您可以通过 MSYS2 的包管理器 pacman 安装 MinGW-w64,或者您可以从 https://winlibs.com/ 获得独立构建

    MinGW / MinGW-w64 中缺少 POSIX 函数

    使用 MinGW / MinGW-w64 的一个缺点是缺少一些 POSIX 函数(例如fork())。

    所以你需要用他们的 Windows 替代品替换它们。

    在fork() 用于生成守护进程的情况下,您可能需要重新设计代码的和平,而不是为fork() 寻找替代方案,因为Windows 不使用守护进程而是服务。因此,您需要为 Windows 编写一些特定于 Windows 的代码,以允许您的应用程序作为 Windows 服务运行。您可以使用#ifdef _WIN32 将您的 POSIX 代码仍然保留在您的应用程序中,以便它仍然可以在 POSIX 平台上编译。

    对于某些 POSIX 函数,已经有一些库提供了具有兼容 C 标头的 Windows 替代方案,例如:

    【讨论】:

      猜你喜欢
      • 2020-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多