chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.72k stars 1.19k forks source link

"WinSock.h has already been included" #1441

Open apolukhin opened 4 months ago

apolukhin commented 4 months ago

There's a feature request to Boost.Stacktrace https://github.com/boostorg/stacktrace/issues/155 that look like should go to ASIO:

""" The order in which you include stacktrace.hpp & asio.hpp can cause a compilation error on Windows.
I tested this on MSVC 19.34.31947 with Boost 1.84.0.

For example, this code doesn't compile:

#include <boost/stacktrace/stacktrace.hpp>
#include <boost/asio.hpp>

This is the error message:

boost\asio\detail\socket_types.hpp(24): fatal error C1189: #error:  WinSock.h has already been included

It compiles fine if you swap the order:

#include <boost/asio.hpp>
#include <boost/stacktrace/stacktrace.hpp>

The same code compiles without issue on Linux (tested with gcc 10 on Debian 11).
This isn't really a huge problem as all you have to do to fix it is include socket_types.hpp before stacktrace.hpp, but the inconsistency is weird when cross-compiling. """

mabrarov commented 4 months ago

Hi @apolukhin,

socket_types.hpp(24) has following check:

# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
#  error WinSock.h has already been included
# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)

and WinSock2.h (part of Windows SDK, installed with Visual Studio 2019 in my case) has

#ifndef _WINSOCK2API_
#define _WINSOCK2API_
#define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */

It seems that Asio just checks if winsock.h was included instead of WinSock2.h. Similar check exists in ws2def.h too:

#if !defined(_WINSOCK2API_) && defined(_WINSOCKAPI_)
#error Do not include winsock.h and ws2def.h in the same module. Instead include only winsock2.h.
#endif

Maybe winsock.h comes to Boost.Stacktrace headers within Windows.h which has following code:

#ifndef _MAC
#if defined(_68K_) || defined(_MPPC_)
#define _MAC
#endif
#endif
...
#ifndef WIN32_LEAN_AND_MEAN
...
#ifndef _MAC
#include <winperf.h>
#include <winsock.h>
#endif
...
#endif

_MAC and _68K_ make me suspecting that reporter of https://github.com/boostorg/stacktrace/issues/155 has some specific build environment / configuration which needs to be fixed (and Asio just did a good job by highlighting that).

Sorry, I misread last #ifndef _MAC as #ifdef _MAC, so the strikethrough part of my comment is not correct.

mabrarov commented 4 months ago

It looks like there is no way for Asio to solve this issue:

  1. https://stackoverflow.com/questions/21399650/cannot-include-both-files-winsock2-windows-h
  2. https://stackoverflow.com/questions/9153911/is-there-a-difference-between-winsock-h-and-winsock2-h

The most of Windows builds I know use WIN32_LEAN_AND_MEAN macro. Maybe it's the only solution for https://github.com/boostorg/stacktrace/issues/155. Replacing every

#include <windows.h>

with something like

#ifdef WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif

in Boost (because it is not just Boost.Stacktrace who includes windows.h) seems to be overkill (though some Boost libraries define WIN32_LEAN_AND_MEAN in compilation units and / or in Jamfiles).