c++ - 英特尔 TBB - 'InitializeCriticalSectionEx' : identifier not found compiler error

标签 c++ c++17 tbb poco-libraries vcpkg

我有一个依赖于 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/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没有定义。

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 头文件。

现在想象一下,我们项目中的第一个包含是来自 Poco 的头文件。这意味着,_WIN32_WINNT将设置为 Windows XP 并且 windows.h 将包含 Windows XP 的窗口标题(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 header ,然后它重新定义 _WIN32_WINNT是 Windows 8.1。我不知道为什么会这样,也许有一个很好的理由,idk。

如果我们现在查看最顶部的最小示例,我们会看到 Poco 包含在 TBB 之前。现在发生的是:
  • 包括 Poco header
  • 套装_WIN32_WINNT到 Windows XP
  • 包括窗口标题(Windows XP 版本,因为 2)
  • 重置 _WIN32_WINNT到 Windows 8.1
  • 包含 TBB header (Windows header 已经包含在内,因此 TBB 不需要在 tbb/windows_api.h 中再次包含它们)
  • TBB 通过 _WIN32_WINNT 检查 Windows 版本并识别 Windows 8.1(由 Poco 设置)
  • TBB思InitializeCriticalSectionEx已定义,因为 Windows 版本是 8.1(或者是吗?Poco 说:get rekt)和 InitializeCriticalSectionEx从 Windows Vista 开始定义。
  • 不幸的是,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 版本是 1.8.1-1,使用 x64(通过 vcpkg)构建。

    更新

    Poco正在讨论这个问题。可以找到更新here .

    关于c++ - 英特尔 TBB - 'InitializeCriticalSectionEx' : identifier not found compiler error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50039499/

    相关文章:

    php.net 的 PHP 开始标签

    c++ - 为什么我可以在 C++ 中访问大于数组大小的数组索引?

    C++如何遍历不同的类型

    c++ - Qt Widget应用程序 "Library not registered"错误

    c++ - 信号量实现 - 在通知条件变量之前,notify() 是否应该释放互斥体?

    c++ - 避免 local() 调用 tbb enumerable_thread_specific 变量

    c++ - Tbb 并发 HashMap 迭代器

    c++ - 基于 lambda arity 的特化函数模板

    C++ 标准:ODR 和 constexpr std::string_view

    c++ - lambda tbb parallel reduce with a few arguments