英特尔 TBB - "初始化关键部分 Ex":找不到标识符编译器错误

Intel TBB - 'InitializeCriticalSectionEx': identifier not found compiler error

本文关键字:找不到 标识符 Ex 编译器 错误 键部 TBB 初始化 英特尔      更新时间:2023-10-16

我有一个依赖OpenCV和TBB的VS(C (项目,因此我为每个库创建了属性表,并将其包括在项目中。一切都很好,并且编译了代码。

昨天,我已经开始使用VCPKG软件包管理器。我通过VCPKG安装了OpenCV和TBB,一切似乎都起作用。我创建了一个空的项目,其中包括两者的标题,并测试了新编译的库是否有效。验证这一点后,我回到了主要项目并删除了属性表,因此我可以使用VCPKG的库。自上次成功编译以来,我没有以任何方式更改代码。

但是,当我尝试编译代码时,我两次都会收到此错误(在main.cpp和subpoule中(

tbb critical_section.h(53(:错误c3861:'prinitizecriticalsectionex':找不到标识符

有人知道这里发生了什么还是为什么发生此错误?

更新

我自己发现了错误。我正在添加Poco-libraries标签,因为它实际上是TBB和Poco之间的冲突。

我找到了问题的根源,实际上它与TBB无关,而与POCO库无关。

考虑最小示例:

#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{   
}

这将抛出编译器错误。

追踪路径

包括 tbb.h criality_section.h 包括 tbb.h 的第51行中。但是, 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宏控制实际上包括Windows头文件的哪个版本。如果将_WIN32_WINNT设置为更早的版本,而不是Windows Vista,则未定义函数InitializeCriticalSectionEx

通过简单地定义称为适当的替代功能的宏InitializeCriticalSectionEx,通过 Machine/winwdows_api.h (如您在该文件的代码块中看到的那样(捕获。

到目前为止很好。

问题

所有邪恶的根源在于poco库的 poco/untindows.h 。包括POCO标头时,将包括某个点 undindows.h

poco/untindows.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已经定义,如果没有定义,则将其设置为Windows XP的0x0501。之后,包括 Windows.h 。在上一章中,我提到_WIN32_WINNT实际上包含了哪个版本的Windows头文件。

现在想象,我们项目中的第一个包括Poco的标题。这意味着,_WIN32_WINNT将设置为Windows XP和 Windows.h 将包括 Windows XP 的Windows标题(IMO已经是一个不好的符号(。

但不用担心,情况会变得更糟。

如果我们跟踪Include层次结构一个级别,我们可以联系 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
...

有趣,不是吗?首先,它包括 unvindows.h ,它设置了_WIN32_WINNT并导致Windows XP标头,接下来它重新定义_WIN32_WINNT为Windows 8.1。我不知道为什么这样做,也许有充分的理由,idk。

现在,如果我们现在查看最顶部的最小示例,我们会看到POCO在TBB之前包括。现在发生的事情是:

  1. 包括Poco标头
  2. _WIN32_WINNT设置为Windows XP
  3. 包括Windows标题(由于2(,Windows XP版本
  4. 重置_WIN32_WINNT到Windows 8.1
  5. 包括TBB标头(已经包含Windows标题,因此TBB不需要再次将它们包含在 tbb/windows_api.h (
  6. TBB通过_WIN32_WINNT检查Windows版本,并识别Windows 8.1(由POCO设置(
  7. TBB认为InitializeCriticalSectionEx是定义的,因为Windows版本为8.1(或者是?Poco说:获取REKT(,并且InitializeCriticalSectionEx是因为Windows Vista。
  8. 不幸的是,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构建的1.8.1-1(通过VCPKG(。

更新

Poco在这个问题上。更新可以在此处找到。