windows.h winsock2.h winsock.h的关系
前两天编译openssl工程
遇到如下错误
--------------------Configuration: ssleay32 - Win32 Debug--------------------
Compiling...
ssl_algs.c
D:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/mswsock.h(69) : error C2146: syntax error : missing ')' before identifier 's'
D:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/mswsock.h(69) : error C2061: syntax error : identifier 's'
D:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/mswsock.h(69) : error C2059: syntax error : ';'
......
查看为
/* * Microsoft extended APIs. */ int PASCAL FAR WSARecvEx ( SOCKET s, char FAR *buf, int len, int FAR *flags );
SOCKET未定义。
通过加#error 指令二分查找,找到了如下头文件的包含关系
file: e_os.h
# ifdef WINDOWS # if !defined(_WIN32_WCE) && !defined(_WIN32_WINNT) /* * Defining _WIN32_WINNT here in e_os.h implies certain "discipline." * Most notably we ought to check for availability of each specific * routine with GetProcAddress() and/or guard NT-specific calls with * GetVersion() < 0x80000000. One can argue that in latter "or" case * we ought to /DELAYLOAD some .DLLs in order to protect ourselves * against run-time link errors. This doesn't seem to be necessary, * because it turned out that already Windows 95, first non-NT Win32 * implementation, is equipped with at least NT 3.51 stubs, dummy * routines with same name, but which do nothing. Meaning that it's * apparently sufficient to guard "vanilla" NT calls with GetVersion * alone, while NT 4.0 and above interfaces ought to be linked with * GetProcAddress at run-time. */ # define _WIN32_WINNT 0x0400 # endif# if !defined(OPENSSL_NO_SOCK) && defined(_WIN32_WINNT) /* * Just like defining _WIN32_WINNT including winsock2.h implies * certain "discipline" for maintaining [broad] binary compatibility. * As long as structures are invariant among Winsock versions, * it's sufficient to check for specific Winsock2 API availability * at run-time [DSO_global_lookup is recommended]... */ # include <winsock2.h> # include <ws2tcpip.h> /* yes, they have to be #included prior to <windows.h> */ # endif # include <windows.h> # include <stdio.h> # include <stddef.h> # include <errno.h> # include <string.h>
而<winsock2.h>文件开始还没有任何实质性定义(如SOCKET)之前又如下代码
/* * Pull in WINDOWS.H if necessary */ #ifndef _INC_WINDOWS #include <windows.h> #endif /* _INC_WINDOWS */ <windows.h>文件中含有如下代码: #if(_WIN32_WINNT >= 0x0400) #include <winsock2.h> #include <mswsock.h> #else #include <winsock.h> #endif /* _WIN32_WINNT >= 0x0400 */
如果_WIN32_WINNT被定义且值大于等于0x0400的时候将有最开始的winsock2.h 包了windows.h windows.h包了winsock2.h和mswsock.h,但后者包winsock2.h的时候因为防止头文件重复包含的缘故并没有再去 引入实质内容。如此一来随后包含mswsock.h时该文件内用到的SOCKET符号将出现未定义的编译错误。
寻这段代码上下看会看到:
#ifndef WIN32_LEAN_AND_MEAN #include <cderr.h> 略 #include <shellapi.h> #ifndef _MAC #include <winperf.h> #if(_WIN32_WINNT >= 0x0400) #include <winsock2.h> #include <mswsock.h> #else #include <winsock.h> #endif /* _WIN32_WINNT >= 0x0400 */ 略 #endif /* !MAC */ #endif /* !NOGDI */ #endif /* WIN32_LEAN_AND_MEAN */
MSDN上对WIN32_LEAN_AND_MEAN有如下解释:
Faster Builds with Smaller Header Files
You can reduce the size of the Windows header files by excluding some of the less common API declarations as follows:
Define WIN32_LEAN_AND_MEAN to exclude APIs such as Cryptography, DDE, RPC, Shell, and Windows Sockets.
Define one or more of the NOapi symbols to exclude the API. For example, NOCOMM excludes the serial communication API. For a list of support NOapi symbols, see Windows.h.
意思是说你可以通过排除很少使用的API声明文件降低windows头文件的大小。定义WIN32_LEAN_AND_MEAN以排除涉及Cryptography,DDE,RPC,Shell和SOCKET。
现在我们自己明确include我们需要的头文件,没必要由windows.h代劳,因而可定义该宏进行exclude。
如此一来,很和谐的编译完成。