其他分享
首页 > 其他分享> > c – Intel TBB – ‘InitializeCriticalSectionEx’:未找到标识符编译器错误

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
>包括TB​​B标头(已包含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