Intel TBB - InitializeCriticalSectionEx: идентификатор не найден, ошибка компилятора - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть проект VS (C ++), который использует OpenCV и TBB, поэтому я создал листы свойств для каждой библиотеки и включил их в проект. Все работало нормально, и код скомпилирован.

Вчера я начал использовать vcpkg менеджер пакетов. Я установил OpenCV и TBB через vcpkg, и все, казалось, работало. Я создал пустой проект, включил заголовки обоих и проверил, работают ли новые скомпилированные библиотеки. После проверки я вернулся к своему основному проекту и удалил листы свойств, чтобы я мог использовать библиотеки из vcpkg. Я не менял код с момента последней успешной компиляции.

Но когда я пытаюсь скомпилировать код сейчас, я получаю эту ошибку два раза (в main.cpp и в подмодуле)

tbb \ crit_section.h (53): ошибка C3861: 'InitializeCriticalSectionEx': идентификатор не найден

Кто-нибудь знает, что здесь происходит и почему возникает эта ошибка?

Обновление

Я сам нашел ошибку. Я добавляю тег poco-library, потому что на самом деле это конфликт между TBB и Poco.

1 Ответ

0 голосов
/ 26 апреля 2018

Я нашел источник проблемы, и он на самом деле не имеет ничего общего с TBB, а с библиотекой Poco .

Рассмотрим минимальный пример:

#include <Poco/Poco.h>
#include <tbb/tbb.h>

void main()
{   
}

Это приведет к ошибке компилятора.

Отслеживание пути

При включении tbb.h , crit_section.h включается в строку 51 tbb.h . Тем не менее, 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

Как видите, 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 / UnWindows.h библиотеки Poco. При включении заголовка 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 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, а затем переопределяет _WIN32_WINNT как Windows 8.1. Я понятия не имею, почему это происходит, возможно, есть веская причина, ИДК.

Если мы посмотрим на минимальный пример в самом верху, то увидим, что Poco включен до TBB. Что теперь происходит:

  1. Включить заголовки Poco
  2. Установить _WIN32_WINNT для Windows XP
  3. Включить заголовки Windows (версия Windows XP, из-за 2)
  4. Сброс _WIN32_WINNT до Windows 8.1
  5. Включить заголовки TBB (заголовки windows уже включены, поэтому TBB не нужно включать их снова в tbb / windows_api.h )
  6. TBB проверяет версию Windows через _WIN32_WINNT и распознает Windows 8.1 (как установлено Poco)
  7. TBB считает, что InitializeCriticalSectionEx определено, потому что версия Windows - 8.1 (или это? Poco говорит: get 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 - 1.8.1-1, собранная с x64 (через vcpkg).

Обновление

Поко по вопросу. Обновления можно найти здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...