oneTBB: интеграция и сборка через CMake

848bbefa94d870a86a9b76d770c3235a.png

oneAPI Threading Building Blocks (oneTBB) — популярная библиотека для параллельного программирования на C++ с открытым исходным кодом, опубликована на GitHub. Пару лет назад команда разработки решилась на глобальный рефакторинг библиотеки (проект TBB revamp), в который удалось вписать долгожданную смену системы сборки с GNU Makefiles на CMake. Свежая версия вышла в релиз в рамках инициативы oneAPI, обновив имя на oneTBB. В этой статье я расскажу про то, как подключить oneTBB в CMake-проект и как собрать, протестировать и установить oneTBB.

Как подключить oneTBB в свой CMake-проект

Эта часть может быть полезна тем, кто хочет использовать библиотеку oneTBB в своём проекте.

Существует два основных способа подключения стороннего проекта: как готовый пакет и как исходный код.

Способ 1. Подключение готового пакета oneTBB

Для подключения пакета нужна функция find_package(TBB <...>). Такой способ работает для тех пакетов oneTBB, в которых есть соответствующая поддержка — TBBConfig-файлы. Официальные oneAPI пакеты распространяются с такой поддержкой из коробки. Архивы, прикреплённые к релизам oneTBB на GitHub, тоже поддерживают такой способ, но нужно дать CMake«у знать, куда распакован пакет, через переменную CMAKE_PREFIX_PATH. Некоторые сторонние дистрибутивы oneTBB также поддерживают этот способ. На самом деле, поддержка TBBConfig-файлов появилась задолго до релиза oneTBB, это произошло в одном из обновлений TBB 2017. Реализация в oneTBB во многом совместима с реализацией из предыдущих версий.

После успешного вызова find_package(TBB <...>) в проекте станут доступны импортированные таргеты TBB::tbb, TBB::tbbmalloc и т.д. в зависимости от запрошенных и доступных компонентов. Эти таргеты можно подключить к своему таргету — target_link_libraries(my_app PRIVATE TBB::tbb). Несмотря на «link» в названии функции, она добавит зависимость не только на стадию линковки, но и на стадию компиляции (путь до заголовочных файлов oneTBB подставится в строку компиляции).

Код

# Создаём приложение
add_executable(my_app)
target_sources(my_app PRIVATE my_app.cpp)

# Ищем готовый пакет oneTBB 2021.5.0 (или новее)
find_package(TBB 2021.5.0 REQUIRED)

# Подключаем импортированный таргет TBB::tbb к приложению
target_link_libraries(my_app PRIVATE TBB::tbb)

Детальнее посмотреть и попробовать этот способ можно на примере, в котором:

  • my_app.cpp — исходник приложения, вызывающего TBB_runtime_version() и печатающего результат в консоль;

  • CMakeLists.txt — CMake-конфигурация для сборки приложения, где и показан способ подключения oneTBB;

  • run.sh — скрипт для запуска примера на линуксе;

  • README.md — небольшое описание примера.

В этом примере используется готовый пакет со страницы oneTBB/releases, который ставится в текущую папку. Такая CMake-конфигурация будет работать и в случае установки oneTBB из многих других источников.

Во время сборки можно заметить, как подключается библиотека:

  • на этапе компиляции подключаются заголовочные файлы: -isystem /include

  • на этапе линковки проставляется rpath и подключается библиотека: -Wl,-rpath,/lib/intel64/gcc4.8 /lib/intel64/gcc4.8/libtbb.so.12

Так как путь до библиотеки уже есть в rpath, для запуска не нужно выставлять какие-то дополнительные переменные окружения. С помощью ldd можно проверить, что oneTBB «виден»:

> ldd ./build/my_app | grep tbb
        libtbb.so.12 => /lib/intel64/gcc4.8/libtbb.so.12 (0x00007f867622c000)

Способ 2. Подключение oneTBB в виде исходного кода

Если подходящего пакета нет или требуется сборка с особыми параметрами, то можно использовать исходный код oneTBB, собирая его вместе с проектом.

До вызова функции, подключающей oneTBB, можно дополнительно настроить конфигурацию с помощью переменных, которые описаны в начале oneTBB/cmake/README.md (TBB_STRICT, TBB_TEST и т.д.), общие переменные CMAKE_BUILD_TYPE, CMAKE_CXX_STANDARD и другие также будут учитываться при построении oneTBB.

В самом простом варианте можно скачать исходники библиотеки в папку с проектом и добавить в CMakeLists.txt команду add_subdirectory(). Дальше можно использовать таргеты из oneTBB проекта и подключать их к своим таргетам, как в способе 1 — target_link_libraries(my_app PRIVATE TBB::tbb).

Код

# Создаём приложение
add_executable(my_app)
target_sources(my_app PRIVATE my_app.cpp)

# Настраиваем конфигурацию oneTBB - явно отключаем тесты
option(TBB_TEST OFF)

# Подключаем в проект подпапку с исходниками oneTBB,
# которая должна быть предварительно скачана в проект
add_subdirectory(oneTBB)

# Подключаем таргет TBB::tbb к приложению
target_link_libraries(my_app PRIVATE TBB::tbb)

Вместо add_subdirectory можно использовать функции FetchContent_Declare и FetchContent_MakeAvailable из модуля FetchContent, что позволит автоматически скачивать исходники oneTBB, например с GitHub.

Код

# Создаём таргет приложения
add_executable(my_app)
target_sources(my_app PRIVATE my_app.cpp)

# Загружаем исходники oneTBB 2021.5.0 с GitHub на этапе конфигурации
include(FetchContent)
FetchContent_Declare(
  onetbb
  GIT_REPOSITORY https://github.com/oneapi-src/oneTBB.git
  GIT_TAG v2021.5.0
)

# Настраиваем конфигурацию oneTBB - явно отключаем тесты
option(TBB_TEST OFF)

# Делаем исходники oneTBB доступными в текущем проекте (аналогично add_subdirectory)
FetchContent_MakeAvailable(onetbb)

# Подключаем таргет TBB::tbb к приложению
target_link_libraries(my_app PRIVATE TBB::tbb)

Детальнее посмотреть и попробовать этот способ можно на примере, в котором:

  • my_app.cpp — исходник приложения, вызывающего TBB_runtime_version() и печатающего результат в консоль;

  • CMakeLists.txt — CMake-конфигурация для сборки приложения, где и показан способ подключения oneTBB с помощью модуля FetchContent;

  • run.sh — скрипт для запуска примера на линуксе;

  • README.md — небольшое описание примера.

При построении явно используется таргет my_app, который через зависимость вызывает построение таргета TBB::tbb. Если не использовать никакого таргета или использовать таргет all, то построятся все таргеты из проекта oneTBB, попавшие в all, а не только те, на которые есть зависимость.

Как сконфигурировать, построить и протестировать oneTBB

Эта часть может быть полезна тем, кто хочет самостоятельно собирать oneTBB, делать какие-то доработки и предлагать изменения в библиотеку.

Подробное и актуальное описание системы сборки можете найти в oneTBB/cmake/README.md. Ниже кратко опишу основные шаги.

Конфигурация

Конфигурируется проект типично — командой cmake. Настроить конфигурацию можно как общими переменными (CMAKE_BUILD_TYPE, CMAKE_CXX_STANDARD и т.д.), так и проектными (TBB_STRICT, TBB_TEST и т.д.).

Построение

Строится проект также типично: например, командой cmake --build. Проект включает в себя несколько компонентов, для каждого из которых есть таргет, если компонент поддерживается на системе и не отключен при конфигурации: tbb, tbbmalloc, tbbmalloc_proxy, разные варианты tbbbind. Каждый из этих таргетов строится в динамическую библиотеку. Статическую версию тоже можно построить (BUILD_SHARED_LIBS), но разработчики oneTBB не рекомендуют и официально не поддерживают такой вариант.

В проект входят Python-bindings (таргет python_build), которые включаются опцией TBB4PY_BUILD и собираются через Setuptools под капотом. Для сборки нужен Python 3.5+ и SWIG.

Если тесты не отключены через TBB_TEST=OFF, то для каждого из них создаётся таргет, который можно построить отдельно.

Тестирование

При включенной опции TBB_TEST в проект включаются тесты. Набор тестов зависит от включенных компонентов и от платформы. Тесты будут включать дополнительные сценарии, если в системе установлен Intel® Software Development Emulator. Построенные тесты можно запустить с помощью утилиты ctest.

Установка

Подробная инструкция установки из исходников с примерами описана в oneTBB/INSTALL.md.

Для установки можно использовать таргет install, либо напрямую вызывать cmake_install.cmake скрипт, с помощью которого можно установить конкретный компонент: runtime, devel или tbb4py.

Настроить путь установки можно на этапе конфигурации проекта через переменную CMAKE_INSTALL_PREFIX. По умолчанию установится в /usr/local на Unix и в C:\Program Files\TBB на Windows.

Кроме того, в проекте реализована простая zip конфигурация для упаковщика CPack. После конфигурации и сборки проекта можно сделать oneTBB пакет в виде zip-архива. В распакованном виде такой пакет можно подключать к проектам, как описано выше в способе 1.

Более подробную и актуальную информацию о системе сборки (и не только) можно найти в репозитории oneTBB на GitHub. Проект активный, поэтому баг-репорты, фича-реквесты или просто вопросы приветствуются через Issues, а свой вклад можно внести через Pull Request.

© Habrahabr.ru