Я нашел источник проблемы, и на самом деле он не имеет ничего общего с TBB, а с библиотекой Poco.
Рассмотрим минимальный пример:
#include <Poco/Poco.h>
#include <tbb/tbb.h>
void main()
{
}
Это вызовет ошибку компилятора.
Отслеживание пути
При включении tbb.h critical_section.h включается в строку 51 файла tbb.h. Однако 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/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 (что, по моему мнению, уже является плохим признаком).
Но не волнуйтесь, дальше будет хуже.
Если мы проследим иерархию включения на один уровень выше, мы достигнем 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
- Включить заголовки TBB (заголовки Windows уже включены, поэтому TBB не нужно снова включать их в tbb/windows_api.h)
- TBB проверяет версию Windows через
_WIN32_WINNT
и распознает Windows 8.1 (как установлено Poco)
- TBB считает, что
InitializeCriticalSectionEx
определено, потому что версия Windows 8.1 (или нет? Poco говорит: получите 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).
Обновлять
Поко в теме. Обновления можно найти здесь.
person
Timo
schedule
26.04.2018