c – Intel TBB – ‘InitializeCriticalSectionEx’:未找到标识符编译器错误
作者:互联网
我有一个依赖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包含在tbb.h的第51行中.但是,ciritcal_section.hpp包含machine / winwdows_api.h,它看起来像这样(不必要的东西被删除):
TBB /机/ 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
如您所见,在检查_WIN32_WINNT宏之前包含了windows.h.这个宏是在sdkddkver.h中定义的(它包含在windows.h中),iff它尚未定义(在我的例子中它设置为Win10):
sdkddkver.h:
#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
#define _WIN32_WINNT 0x0A00
#endif
在windows.h中,_WIN32_WINNT宏控制实际包含哪个版本的Windows头文件.如果_WIN32_WINNT设置为早于Windows Vista的版本,则不会定义函数InitializeCriticalSectionEx.
通过简单地定义一个调用适当替代函数的宏InitializeCriticalSectionEx,可以通过machine / winwdows_api.h(正如您在该文件的代码块中看到的那样)捕获此问题.
到现在为止还挺好.
问题
所有邪恶的根源在于Poco图书馆的Poco / UnWindows.h.当包含poco标题时,在某些时候将包括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头文件.
现在想象一下,我们项目中的第一个包含来自Poco的标题.这意味着,_WIN32_WINNT将被设置为Windows XP,而windows.h将包含Windows XP的Windows标题(imo已经是一个不好的标志).
但不要担心,它会变得更糟.
如果我们跟踪包含层次结构一级,我们到达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标头,然后将_WIN32_WINNT重新定义为Windows 8.1.我不知道为什么会这样,也许有一个很好的理由,idk.
如果我们现在查看最顶层的最小示例,我们会看到Poco包含在TBB之前.现在发生的是:
>包括Poco标题
>将_WIN32_WINNT设置为Windows XP
>包括Windows标题(Windows XP版本,因为2)
>将_WIN32_WINNT重置为Windows 8.1
>包括TBB标头(已包含Windows标头,因此TBB不需要在tbb / windows_api.h中再次包含它们)
> TBB通过_WIN32_WINNT检查Windows版本并识别Windows 8.1(由Poco设置)
> TBB认为InitializeCriticalSectionEx是定义的,因为Windows版本是8.1(或者是它?Poco说:get rekt)和自Windows Vista以来定义的InitializeCriticalSectionEx.
>不幸的是,Poco确保加载了Windows XP标头,因此编译器说:没有.
解决方案
要么事先包含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版本是用x64(通过vcpkg)构建的1.8.1-1.
更新
Poco就是这个问题.更新可以在here找到.
标签:c,c17,tbb,poco-libraries,vcpkg 来源: https://codeday.me/bug/20190724/1521609.html