英特尔 TBB - 'InitializeCriticalSectionEx':找不到标识符编译器错误
Intel TBB - 'InitializeCriticalSectionEx': identifier not found compiler error
我有一个依赖 OpenCV 和 TBB 的 VS (C++) 项目,因此我为每个库创建了 属性 工作表并将它们包含在项目中。一切正常,代码编译成功。
昨天,我开始使用 vcpkg 包管理器。我通过 vcpkg 安装了 OpenCV 和 TBB,一切似乎都正常。我创建了一个空项目,包含了两者的头文件并测试了新编译的库是否有效。验证之后,我回到我的主项目并删除了 属性 工作表,这样我就可以使用 vcpkg 中的库了。自上次成功编译以来,我没有以任何方式更改代码。
但是,当我现在尝试编译代码时,出现了两次此错误(在 main.cpp 和子模块中)
tbb\critical_section.h(53): error C3861: 'InitializeCriticalSectionEx': identifier not found
有人知道这里发生了什么或为什么会出现此错误吗?
更新
我自己发现了错误。我添加了 poco-libraries 标签,因为它实际上是 TBB 和 Poco 之间的冲突。
我找到了问题的根源,它实际上与 TBB 无关,而与 Poco library 有关。
考虑最小的例子:
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
这将引发编译器错误。
追踪路径
当包含tbb.h时,critical_section.h包含在的第51行tbb.h。然而,ciritcal_section.hpp 包括 machine/winwdows_api.h 看起来像这样(不必要的东西被删掉):
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
如您所见,windows.h包含在之前检查_WIN32_WINNT
宏。这个宏在 sdkddkver.h 中定义(包含在 windows.h 中),如果它还没有定义(在我的如果设置为 Win10):
sdkddkver.h:
#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
#define _WIN32_WINNT 0x0A00
#endif
在windows.h中,_WIN32_WINNT
宏控制实际包含windowsheader文件的哪个版本。如果 _WIN32_WINNT
设置为比 Windows Vista 更早的版本,则函数 InitializeCriticalSectionEx
未定义。
这个问题被 machine/winwdows_api.h 捕获(如您在该文件的代码块中所见),只需定义一个宏 InitializeCriticalSectionEx
调用适当的替代函数。
到目前为止一切顺利。
问题
万恶之源在于Poco库的Poco/UnWindows.h。当包含 poco header 时,在某些时候 UnWindows.h 将被包含。
Poco/UnWindows.h(缩写):
#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>
预处理器检查 _WIN32_WINNT
是否已经定义,如果没有,则将其设置为 0x0501,即 Windows XP。 之后,windows.h被收录。在上一章中,我提到 _WIN32_WINNT
控制实际包含 windows header 文件的哪个版本。
现在想象一下,我们项目中的第一个包含是来自 Poco 的 header。这意味着,_WIN32_WINNT
将被设置为 Windows XP 并且 windows.h 将包括 windows headers Windows XP(在我看来这已经是一个坏兆头)。
不过别担心,情况会变得更糟。
如果我们向上追踪包含层次结构,我们会到达 Poco/Platform_WIN32.h.
Poco/Platform_WIN32.h(缩写):
#include "Poco/UnWindows.h"
...
#if defined (_WIN32_WINNT_WINBLUE)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WINBLUE
...
很有趣,不是吗?首先,它包含 UnWindows.h,它设置 _WIN32_WINNT
并导致包含 Windows XP headers,接下来它重新定义 _WIN32_WINNT
为 Windows 8.1。我不知道为什么这样做,也许有一个很好的理由,idk。
如果我们现在查看最上面的最小示例,我们会发现 Poco 包含在 TBB 之前。现在发生的是:
- 包括 Poco headers
- 将
_WIN32_WINNT
设置为 Windows XP
- 包括windowsheaders(WindowsXP版本,因为2)
- 将
_WIN32_WINNT
重置为 Windows 8.1
- 包含 TBB headers(windows headers 已经包含,因此 TBB 不需要在 tbb/windows_api 中再次包含它们.h)
- TBB 通过
_WIN32_WINNT
检查 windows 版本并识别 Windows 8.1(由 Poco 设置)
- TBB 认为
InitializeCriticalSectionEx
已定义,因为 Windows 版本是 8.1(或者是?Poco 说:get rekt)并且 InitializeCriticalSectionEx
已定义,因为 Windows远景
- 不幸的是,Poco 确保加载了 Windows XP header,因此编译器说:不。
解决方案
要么预先包含windows.h你自己,要么预先设置_WIN32_WINNT
你自己:
#define _WIN32_WINNT 0x0A00 // either this
#include <Windows.h> // or this
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
也许 Poco 贡献者中的某些人可以在这里澄清一些事情。 Poco 版本是 1.8.1-1,使用 x64(通过 vcpkg)构建。
更新
Poco 正在处理这个问题。可以找到更新 here。
我有一个依赖 OpenCV 和 TBB 的 VS (C++) 项目,因此我为每个库创建了 属性 工作表并将它们包含在项目中。一切正常,代码编译成功。
昨天,我开始使用 vcpkg 包管理器。我通过 vcpkg 安装了 OpenCV 和 TBB,一切似乎都正常。我创建了一个空项目,包含了两者的头文件并测试了新编译的库是否有效。验证之后,我回到我的主项目并删除了 属性 工作表,这样我就可以使用 vcpkg 中的库了。自上次成功编译以来,我没有以任何方式更改代码。
但是,当我现在尝试编译代码时,出现了两次此错误(在 main.cpp 和子模块中)
tbb\critical_section.h(53): error C3861: 'InitializeCriticalSectionEx': identifier not found
有人知道这里发生了什么或为什么会出现此错误吗?
更新
我自己发现了错误。我添加了 poco-libraries 标签,因为它实际上是 TBB 和 Poco 之间的冲突。
我找到了问题的根源,它实际上与 TBB 无关,而与 Poco library 有关。
考虑最小的例子:
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
这将引发编译器错误。
追踪路径
当包含tbb.h时,critical_section.h包含在的第51行tbb.h。然而,ciritcal_section.hpp 包括 machine/winwdows_api.h 看起来像这样(不必要的东西被删掉):
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
如您所见,windows.h包含在之前检查_WIN32_WINNT
宏。这个宏在 sdkddkver.h 中定义(包含在 windows.h 中),如果它还没有定义(在我的如果设置为 Win10):
sdkddkver.h:
#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
#define _WIN32_WINNT 0x0A00
#endif
在windows.h中,_WIN32_WINNT
宏控制实际包含windowsheader文件的哪个版本。如果 _WIN32_WINNT
设置为比 Windows Vista 更早的版本,则函数 InitializeCriticalSectionEx
未定义。
这个问题被 machine/winwdows_api.h 捕获(如您在该文件的代码块中所见),只需定义一个宏 InitializeCriticalSectionEx
调用适当的替代函数。
到目前为止一切顺利。
问题
万恶之源在于Poco库的Poco/UnWindows.h。当包含 poco header 时,在某些时候 UnWindows.h 将被包含。
Poco/UnWindows.h(缩写):
#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>
预处理器检查 _WIN32_WINNT
是否已经定义,如果没有,则将其设置为 0x0501,即 Windows XP。 之后,windows.h被收录。在上一章中,我提到 _WIN32_WINNT
控制实际包含 windows header 文件的哪个版本。
现在想象一下,我们项目中的第一个包含是来自 Poco 的 header。这意味着,_WIN32_WINNT
将被设置为 Windows XP 并且 windows.h 将包括 windows headers Windows XP(在我看来这已经是一个坏兆头)。
不过别担心,情况会变得更糟。
如果我们向上追踪包含层次结构,我们会到达 Poco/Platform_WIN32.h.
Poco/Platform_WIN32.h(缩写):
#include "Poco/UnWindows.h"
...
#if defined (_WIN32_WINNT_WINBLUE)
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT _WIN32_WINNT_WINBLUE
...
很有趣,不是吗?首先,它包含 UnWindows.h,它设置 _WIN32_WINNT
并导致包含 Windows XP headers,接下来它重新定义 _WIN32_WINNT
为 Windows 8.1。我不知道为什么这样做,也许有一个很好的理由,idk。
如果我们现在查看最上面的最小示例,我们会发现 Poco 包含在 TBB 之前。现在发生的是:
- 包括 Poco headers
- 将
_WIN32_WINNT
设置为 Windows XP - 包括windowsheaders(WindowsXP版本,因为2)
- 将
_WIN32_WINNT
重置为 Windows 8.1 - 包含 TBB headers(windows headers 已经包含,因此 TBB 不需要在 tbb/windows_api 中再次包含它们.h)
- TBB 通过
_WIN32_WINNT
检查 windows 版本并识别 Windows 8.1(由 Poco 设置) - TBB 认为
InitializeCriticalSectionEx
已定义,因为 Windows 版本是 8.1(或者是?Poco 说:get rekt)并且InitializeCriticalSectionEx
已定义,因为 Windows远景 - 不幸的是,Poco 确保加载了 Windows XP header,因此编译器说:不。
解决方案
要么预先包含windows.h你自己,要么预先设置_WIN32_WINNT
你自己:
#define _WIN32_WINNT 0x0A00 // either this
#include <Windows.h> // or this
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
也许 Poco 贡献者中的某些人可以在这里澄清一些事情。 Poco 版本是 1.8.1-1,使用 x64(通过 vcpkg)构建。
更新
Poco 正在处理这个问题。可以找到更新 here。