Подключение системных библиотек в CMake через pkg-config

Posted on сент. 10, 2023

Решил попробовать примитивно потыкаться в работу с векторной графикой. Вроде бы все свой путь в программировании начинают с рисования квадратов и кругов, а я проскочил данный этап в угоду неясно чему слабым калькуляторам.

Все привычно – создал проект на cmake, собираюсь подключать следующие вещи: Cairo , CairoMM (обвязка для C++), SDL2. И тут вдруг выясняется, что для этих библиотек не существует готовых модулей для find_package 😱.

Ну и что, не писать же их вручную, в самом же деле? Готовые файлы FindCairo.cmake были обнаружены в проектах Qtwebkit, poppler, но это значит выдергивать файлы из чужих проектов, лицензии, адаптация, фу.

Есть альтернативный ход – воспользоваться “пакетным менеджером” для C++, например, vcpkg. В его структуре есть рецепты для cairo и sdl2. Однако на простецкий проект тащить целый vcpkg не хочется – я уже установил библиотеки в систему, зачем мне дополнительный слой костылей?

И тут вспоминаю о том, что вообще-то есть способ запросить у системы список установленных библиотек, флаги для компиляции, пути к хэдерам и т.д. Имя этому способу – pkg-config. Он позволяет выяснить вышеперечисленные параметры о библиотеках, которые предоставляют в своем дистрибутиве файл <package.pc>. Может его можно как-то использовать внутри CMake?

Можно! И для этого даже не требуется самостоятельно писать функции с доступом к этой утилите. Воспользуемся модулем FindPkgConfig:

find_package(PkgConfig)

Нам имеет смысл воспользоваться одной из двух функций:

  • pkg_search_module – проверяет существование модуля и использует первый найденный;
  • pkg_check_module – провеяет все совпадающие с запросом модулию

Воспользуемся этим знанием и поищем библиотеки CairoMM (какую есть) и SDL2 старше версии 2.0.1:

pkg_search_module(CAIRO REQUIRED cairomm-1.0)
pkg_search_module(SDL REQUIRED sdl2>=2.0.1)

И вуаля! Теперь эти библиотеки (при условии, что они установлены в систему, конечно) доступны под ожидаемыми переменными:

target_include_directories(test_exe PRIVATE ${CAIRO_INCLUDE_DIRS})
target_link_libraries(test_exe PRIVATE ${CAIRO_LIBRARIES})

target_include_directories(test_exe PRIVATE ${SDL_INCLUDE_DIRS})
target_link_libraries(test_exe PRIVATE ${SDL_LIBRARIES})

Победа! 🎉

Оказывается, что таким же образом подключается библиотека libmodbus, с подключением которой ранее пришлось повозиться. Жаль все правильные мысли сразу в голову не приходят.