I found the source of the problem and it has actually nothing to do with TBB but with the Poco library.
Consider the minimum example:
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
This will throw an compiler error.
Tracing down the path
When including tbb.h, critical_section.h is included in line 51 of tbb.h. However, ciritcal_section.hpp includes machine/winwdows_api.h which looks like this (unnecessary stuff is cut out):
tbb/machine/winwdows_api.h:
#if _WIN32 || _WIN64
#include <windows.h>
#if _WIN32_WINNT < 0x0600
#define InitializeCriticalSectionEx inlineInitializeCriticalSectionEx
inline BOOL WINAPI inlineInitializeCriticalSectionEx( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD )
{
return InitializeCriticalSectionAndSpinCount( lpCriticalSection, dwSpinCount );
}
#endif
As you can see, windows.h is included before the check of the _WIN32_WINNT
macro. This macro is defined in sdkddkver.h (which is included in windows.h), iff it's not already defined (in my case it's set to Win10):
sdkddkver.h:
#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
#define _WIN32_WINNT 0x0A00
#endif
In windows.h, the _WIN32_WINNT
macro controls which version of the windows header files are actually included. If _WIN32_WINNT
is set to an earlier version than Windows Vista, the function InitializeCriticalSectionEx
is not defined.
This issue is catched by machine/winwdows_api.h (as you can see in the code block of that file) by simply defining a macro InitializeCriticalSectionEx
that calls an appropriate alternative function.
So far so good.
The problem
The root of all evil lies in Poco/UnWindows.h of the Poco library. When including a poco header, at some point UnWindows.h will be included.
Poco/UnWindows.h (shortened):
#if defined(_WIN32_WINNT)
#if (_WIN32_WINNT < 0x0501)
#error Unsupported Windows version.
#endif
#elif defined(NTDDI_VERSION)
#if (NTDDI_VERSION < 0x05010100)
#error Unsupported Windows version.
#endif
#elif !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x0501
#define NTDDI_VERSION 0x05010100
#endif
#endif
#include <windows.h>
The preprocessor checks, if _WIN32_WINNT
is already defined, and if not, sets it to 0x0501 which is Windows XP. After that, windows.h is included. In the previous chapter I mentioned that _WIN32_WINNT
controls which version of the windows header files are actually included.
Now imagine, the very first include in our project is a header from Poco. This means, that _WIN32_WINNT
will be set to Windows XP and windows.h will include the windows headers of Windows XP (which imo is already a bad sign).
But don't worry, it gets worse.
If we trace the include hierarchy one level up, we reach Poco/Platform_WIN32.h.
Poco/Platform_WIN32.h (shortened):
#include "Poco/UnWindows.h"
...
#if defined (_WIN32_WINNT_WINBLUE)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WINBLUE
...
Funny, isn't it? First, it includes UnWindows.h, which sets _WIN32_WINNT
and causes Windows XP headers to be included, and next it redefines _WIN32_WINNT
to be Windows 8.1. I have no clue why it does that, maybe there is a good reason, idk.
If we now look at the minimum example at the very top we see that Poco is included before TBB. What now happens is:
- Include Poco headers
- Set
_WIN32_WINNT
to Windows XP
- Include windows headers (Windows XP version, because of 2)
- Reset
_WIN32_WINNT
to Windows 8.1
- Include TBB headers (windows headers are already included, so TBB doesn't need to include them again in tbb/windows_api.h)
- TBB checks the windows version via
_WIN32_WINNT
and recognizes Windows 8.1 (as set by Poco)
- TBB thinks
InitializeCriticalSectionEx
is defined, because the Windows version is 8.1 (or is it? Poco says: get rekt) and InitializeCriticalSectionEx
is defined since Windows Vista.
- Unfortunately Poco ensured that the Windows XP headers are loaded, so compiler says: no.
The solution
Either include windows.h yourself beforehand, or set _WIN32_WINNT
yourself beforehand:
#define _WIN32_WINNT 0x0A00 // either this
#include <Windows.h> // or this
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
Maybe someone of the Poco contributors can clarify some things here. The Poco version is 1.8.1-1 built with x64 (via vcpkg).
Update
Poco is on the issue. Updates can be found here.