У меня есть проект VS (C ++), основанный на OpenCV и TBB, поэтому я создал листы свойств для каждой библиотеки и включил их в проект. Все работало нормально, и код скомпилирован.
Вчера я начал использовать vcpkg менеджер пакетов. Я установил OpenCV и TBB через vcpkg, и все, казалось, работало. Я создал пустой проект, включил заголовки обоих и проверил, работают ли новые скомпилированные библиотеки. После проверки я вернулся к своему основному проекту и удалил листы свойств, чтобы я мог использовать библиотеки из vcpkg. Я не изменил код с момента последней успешной компиляции.
Но когда я пытаюсь скомпилировать код сейчас, я получаю эту ошибку два раза (в main.cpp и в подмодуле)
tbb \ crit_section.h (53): ошибка C3861: «InitializeCriticalSectionEx»: идентификатор не найден
Кто-нибудь знает, что здесь происходит или почему происходит эта ошибка?
Я нашел ошибку сам. Я добавляю тег poco-library, потому что на самом деле это конфликт между TBB и Poco.
Я нашел источник проблемы, и это на самом деле не имеет ничего общего с TBB, но с Библиотека Poco.
Рассмотрим минимальный пример:
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
Это вызовет ошибку компилятора.
Когда в том числе tbb.h, critical_section.h включен в строку 51 tbb.h. Тем не мение, ciritcal_section.hpp включает в себя машина / winwdows_api.h который выглядит следующим образом (ненужные вещи вырезаны):
Т / машина / 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
не определено.
Эта проблема отслеживается машина / 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 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. Что теперь происходит:
_WIN32_WINNT
в Windows XP_WIN32_WINNT
в Windows 8.1_WIN32_WINNT
и распознает Windows 8.1 (как установлено Poco)InitializeCriticalSectionEx
определяется, потому что версия Windows 8.1 (или это? Poco говорит: получить рект) и InitializeCriticalSectionEx
определяется начиная с Windows Vista.Либо включить 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 по этому вопросу. Обновления можно найти Вот.
Других решений пока нет …