【问题标题】:MinGW64 and "conflicting declaration of C function int select(...)"MinGW64 和“C 函数 int select(...) 的冲突声明”
【发布时间】:2018-06-10 09:43:44
【问题描述】:

我正在尝试在 MinGW 上构建 Botan,它实际上是 MinGW-w64 (x86_64-pc-msys)。它在 MinGW 上失败,如下所示。我想我已将其缩减为 MCVE

#include <sys/select.h>
#include <winsock2.h>
#include <windows.h>
#include <memory>

int main(int argc, char* argv[])
{
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);

    timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    int rc = select(1, &fds, NULL, NULL, &tv);

    return 0;
}

结果:

$ g++ -m64 -pthread -std=c++11 test.cxx -o test.exe
In file included from /usr/include/w32api/winsock2.h:56:0,
                 from test.cxx:2:
/usr/include/w32api/psdk_inc/_fd_types.h:100:2: warning: #warning "fd_set and associated macros have been defined in sys/types.      This can cause runtime problems with W32 sockets" [-Wcpp]
 #warning "fd_set and associated macros have been defined in sys/types.  \
  ^~~~~~~
In file included from test.cxx:2:0:
/usr/include/w32api/winsock2.h:995:34: error: conflicting declaration of C function ‘int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, PTIMEVAL)’
   WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const PTIMEVAL timeout);
                                  ^~~~~~
In file included from test.cxx:1:0:
/usr/include/sys/select.h:73:5: note: previous declaration ‘int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, timeval*)’
 int select __P ((int __n, fd_set *__readfds, fd_set *__writefds,
     ^~~~~~

首先包含&lt;sys/select.h&gt; 很重要。在 Windows 标头之后包含它不会出现问题。包括&lt;memory&gt; 很重要。 &lt;memory&gt; 包含额外的标头,例如 &lt;sys/select.h&gt;,已经包含在内。

据我所知,MinGW 标头导致了问题。它们提供具有两个不同签名的相同功能:

/usr/include/w32api/winsock2.h

int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, PTIMEVAL)

/usr/include/sys/select.h

int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, timeval*)

问题似乎是最后一个参数。在一种情况下是PTIMEVAL,在另一种情况下是timeval*。这似乎与邮件列表有关,但我不明白我应该做什么:Replace struct timeval usage with PTIMEVAL and define TIMEVAL differently on LP64

What do I have to look out for when porting applications to 64 bit Cygwin? 详细说明可能存在一些指针大小问题,但它是 MinGW 代码(而不是 Botan 代码)。

有什么问题,我该如何解决?


这是博坦的src/lib/utils/socket/socket.cpp

这里是编译错误:

g++ -fstack-protector -m64 -pthread   -std=c++11 -D_REENTRANT -O3 -momit-leaf-frame-pointer  \
-Wall -Wextra -Wpedantic -Wstrict-aliasing -Wcast-align -Wmissing-declarations  \
-Wpointer-arith -Wcast-qual -Wzero-as-null-pointer-constant -Wnon-virtual-dtor  \
-Ibuild/include -c src/lib/utils/socket/socket.cpp -o build/obj/lib/utils_socket.o
In file included from /usr/include/w32api/winsock2.h:56:0,
                 from src/lib/utils/socket/socket.cpp:35:
/usr/include/w32api/psdk_inc/_fd_types.h:100:2: warning: #warning "fd_set and associated macros have been defined in sys/types.      This can cause runtime problems with W32 sockets" [-Wcpp]
 #warning "fd_set and associated macros have been defined in sys/types.  \
  ^~~~~~~
In file included from src/lib/utils/socket/socket.cpp:35:0:
/usr/include/w32api/winsock2.h:995:34: error: conflicting declaration of C function ‘int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, PTIMEVAL)’
   WINSOCK_API_LINKAGE int WSAAPI select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,const PTIMEVAL timeout);
                                  ^~~~~~
In file included from /usr/include/sys/types.h:68:0,
                 from /usr/include/pthread.h:11,
                 from /usr/lib/gcc/x86_64-pc-msys/6.3.0/include/c++/x86_64-pc-msys/bits/gthr-default.h:35,
                 from /usr/lib/gcc/x86_64-pc-msys/6.3.0/include/c++/x86_64-pc-msys/bits/gthr.h:148,
                 from /usr/lib/gcc/x86_64-pc-msys/6.3.0/include/c++/ext/atomicity.h:35,
                 from /usr/lib/gcc/x86_64-pc-msys/6.3.0/include/c++/memory:73,
                 from build/include/botan/types.h:17,
                 from build/include/botan/internal/socket.h:11,
                 from src/lib/utils/socket/socket.cpp:8:
/usr/include/sys/select.h:73:5: note: previous declaration ‘int select(int, _types_fd_set*, _types_fd_set*, _types_fd_set*, timeval*)’
 int select __P ((int __n, fd_set *__readfds, fd_set *__writefds,
     ^~~~~~
make: *** [Makefile:1066: build/obj/lib/utils_socket.o] Error 1

【问题讨论】:

  • 请注意,winsock2.h 的 select 声明中有一个额外的 const,这可能是罪魁祸首。但据我所知, select.h 不是 mingw-w64 的一部分(它也是从 /usr/include 中提取的,这似乎非常错误),如果包括 winsock2.h (win32 套接字 API),你(嗯, botan) 可能不应该包括 select.h (posix (?) select API),我认为它们本质上是冲突的,通常是其中之一。可能是配置问题。此外,我无法重现它,因此提供有关您的构建环境的更多信息会很有帮助。
  • 这里只是猜测,但我会有点担心来自sys/typesfd_set 参数类型的警告。也许使用-pthread 对 msys/Windows 不是很好?
  • @BoPersson - 我想我进一步减少了这个问题。当包含&lt;sys/select.h&gt;、Windows 标头和&lt;memory&gt; 时会发生这种情况。实践中的问题是,我们对标题没有太多控制。包含所有内容都是有原因的,它有一个顺序来确保在正确的时间定义类型。
  • winsock2.h 有在未首先包含时产生问题的历史。
  • 好的,但那是在什么操作系统上?是交叉编译器吗?您从哪里/如何获得这个 x86_64-pc-msys 工具集?你看,你说你正在使用 mingw-w64 但在这种情况下,在 Debian 和 MSYS2 和 Cygwin 上 gcc -dumpmachine 应该给 x86_64-w64-mingw32。并且应该没有 sys/select.h。 Botan 的构建没有问题。

标签: c++ sockets mingw-w64 botan


【解决方案1】:

&lt;sys/select.h&gt; 是 Linux 系统头文件,因此不应在 MinGW 工具链中提供。如果您的系统中有它,您可能以间接或不受支持的方式获得它。所以从你的程序中删除第一行。此外,&lt;windows&gt;&lt;memory&gt; 都不会为这个特定程序带来任何东西。

MinGW 使用 Windows Sockets (2) 库提供的 select 函数,因此,您的程序必须链接到它,在构建命令中使用链接器标志 -lws2_32

【讨论】:

  • 是 Linux 系统头文件”。它不是。它由 POSIX 指定。使用任何产品使用此名称发送文件都没有问题,即使不符合 POSIX 标准。
【解决方案2】:

我正在尝试在 MinGW 上构建 Botan,它实际上是 MinGW-w64 (x86_64-pc-msys)

我怀疑这是错误的目标——您无意中为 MSYS2 环境本身构建,这确实是 POSIXy。这就是为什么例如&lt;sys/select.h&gt; 被拉入并导致冲突。至少,我严重怀疑您是否会尝试使用 &lt;winsock2.h&gt;&lt;windows.h&gt;,如果您打算构建仅在 MSYS2 环境中使用。您应该确保从命令行正确调用了 MSYS/使用了正确的快捷方式,以便配置为为 MINGW64 构建,或者,如果您是,请确保您实际安装了 MINGW64 的 gcc 工具链。如果您没有这样做,那么即使您已正确打开 MINGW64,它默认默认返回到 MSYS2 的 gcc 工具链,该工具链将继续拉入特定于 MSYS2 构建的包含。 GCC for MINGW64 可以通过运行来安装(或重新安装)

pacman -Sy mingw-w64-x86_64-gcc

您还可以使用以下命令安装或重新安装 Windows 特定的标头:

pacman -Sy mingw-w64-x86_64-headers-git 

完成此操作后,运行 uname 以确认您处于正确的构建环境中,这应该会产生

MINGW64_NT-10.0-18363

然后是gcc -dumpmachine,这应该会产生

x86_64-w64-mingw64

对于 MSYS2,这些值为

MSYS_NT-10.0-18363

x86_64-pc-msys

分别。

我为什么知道这个?从字面上看,我彻夜未眠,遇到同样的问题,直到注意到 _WIN32 和 _WIN64 未定义,以及包含文件的来源(/usr/include,而不是/mingw64/x86_64-w64-mingw32/include),我才意识到我正在为 x86_64-pc-msys 而不是 x86_64-w64-mingw32 构建。

(当然,如果您想为 32 位 Windows 构建,上述所有内容也适用。确保您已正确调用 MINGW32 环境,并且您已运行 pacman -Sy mingw-w64-i686-gcc mingw-w64-i686-headers-git,所以您不要最终尝试使用为 MSYS2 配置的 gcc 进行构建。)

无论如何,我确信这个问题已经存在两年了,OP 已经继续前进了。但这是一个容易犯的配置错误。所以,无论如何,我希望这会有所帮助!不要犯我的错误!大家注意安全!

【讨论】: