C++ по прежнему используется не только для написания ОС, игр и драйверов, но и для неприхотливых к ресурсам утилит командной строки. Между тем конкуренты на этом поприще, например Rust, предлагают систему сборки c менеджером зависимостей по умолчанию. Для C++ де-факто тоже есть стандартная система сборки CMake, но как подключать внешние библиотеки без боли? Вспомним, что для многих развитых технологий есть нечто вроде странички https://start.yourtechnology.io, создающих базовый стандартный проект, чтобы не тратить время на boilerplate конфигурацию. В этой статье рассматривается именно такой шаблон для создания C++ проектов с менеджером зависимостей vcpkg.

Почему vcpkg?

Во первых, из желания предельно упростить базовый проект и уменьшить количество файлов конфигурации в нем. Для C++ есть и другой развитый пакетный менджер Conan, но он требует добавления файла conanfile.txt, а vcpkg обходится одним стадартным CMakeLists.txt. Во вторых, vcpkg хорошо зарекомендовал себя и имеет стабильную поддержку в лице Microsoft.

1. Установка тулчейна для работы

Прежде всего нам понадобится CMake и сам менеджер зависимостей vcpkg, его можно установить через ваш любимый пакетный менеджер (например brew install vcpkg), или собрать вручную отсюда.

2. Установка зависимостей

Проверить есть ли нужная библиотека
vcpkg search yourdepname
Установить
vcpkg install yourdepname

Обратите внимание, что на машине осуществляющей сборку, библиотеки не кладутся в директории рядом с проектом, а устанавливаются в систему глобально, чтобы vcpkg мог их потом переиспользовать в других проектах. Например, для работы нашего шаблона требуется библиотека тестирования, парсер аргументов командой строки и форматированный вывод:
vcpkg install catch2
vcpkg install cli11
vcpkg install fmt

Приятным бонусом, после установки зависимости, vcpkg сам подскажет что дописать в CMakeLists.txt

Промежуточный итог

Как выглядит CMakeLists.txt после первичных манипуляций? Вовсе не страшно как можно было подумать, что на мой взгляд явно говорит в пользу vcpkg:

cmake_minimum_required(VERSION 3.17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(proj)
file(GLOB proj_sources src/*.cpp)
add_executable(proj ${proj_sources})
find_package(fmt CONFIG REQUIRED)
target_link_libraries(proj PRIVATE fmt::fmt fmt::fmt-header-only)
find_package(CLI11 CONFIG REQUIRED)
target_link_libraries(proj PRIVATE CLI11::CLI11)

project(test)
#[[Changing the entry point for tests]]
list(FILTER proj_sources EXCLUDE REGEX ".*Main.cpp$")
file(GLOB test_sources test/*.cpp)
add_executable(test ${proj_sources} ${test_sources})
find_package(Catch2 CONFIG REQUIRED)
target_link_libraries(test PRIVATE Catch2::Catch2)
target_link_libraries(test PRIVATE CLI11::CLI11)
target_link_libraries(test PRIVATE fmt::fmt fmt::fmt-header-only)

3. Сборка в один бинарник

Итак, у нас есть простой CMake проект использующий вышеуказанные вещи, как собрать один исполняемый файл? Если вы используете IDE, то весь третий шаг можно сократить просто установив для параметра CMake options результат выполнения команды vcpkg integrate install

Без IDE чуть сложнее, сначала подготовим CMake в директории вашего проекта:

cmake `vcpkg integrate install | tail -1 | cut -d \"` -f2 -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -B cmake-build-release

Если вы используете Windows, то вместо кода в `` кавычках, подставьте сюда вручную результат выполнения все той же команды vcpkg integrate install

Затем, сборка будет осуществляться командой:
cmake --build cmake-build-release --target all

Расширять такой проект по прежнему просто вызывая
vcpkg install [...].

С++ в 21ом году совсем не страшный. Прилагаю GitHub шаблон, где все это уже реализовано включая точку входа. Чтобы использовать его для создания нового проекта, нажмите кнопку "Use this template" справа  вверху.
Интересно услышать критику подхода и альтернативные решения для кроcплатформенных C++ проектов с зависимостями. Всем удачного дня!