C++ с кроссплатформенностью и зависимостями

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++ проектов с зависимостями. Всем удачного дня!

@Reformat
30.03.2021 19:38 UTC
Первоисточник

Комментарии

@Vanger
30.03.2021 14:44 UTC
0
Conan же, но по тексту почему то Konan
@Reformat
30.03.2021 14:49 UTC
+1
Моя оплошность, спасибо, уже исправил
@qark
30.03.2021 17:56 UTC
0

vcpkg и системный пакетный менеджер не конфликтуют?

@Reformat
31.03.2021 00:12 UTC
0
Не сталкивался с таким. У них ведь разные директории хранения и vcpkg в PATH установленные зависимости не дописывает
@crackedmind
30.03.2021 19:01 UTC
+1
Во-первых, почему vcpkg install, а не манифест vcpkg.json?

{
    "name": "test",
    "version-string": "0.1.0",
    "port-version": 0,
    "homepage": "",
    "description": "",
    "dependencies": [
      "fmt",
      "cli11",
      "catch2"
    ]
  }


В этом случае vcpkg автоматом поставит нужные библиотеки с нужным триплетом, при первой конфигурации проекта.

Во-вторых, под виндой делать vcpkg integrate install не всегда желательно, т.к. пути пропишутся для всех msbuild проектов. Лучше уж ручками добавить путь до тулчейна.

В-третьих, зачем CMAKE_CXX_STANDARD глобально выставляется?

@Reformat
31.03.2021 05:38 UTC
0
Я пробовал использовать vcpkg manifest mode но столкнулся с появившимися ошибками CMake, которых нет в classic mode + в документации написано что manifest mode все еще в бета версии.
@Reformat
31.03.2021 05:38 UTC
0
> CMAKE_CXX_STANDARD
Чтобы для всех проектов была одна версия языка
@NightShad0w
30.03.2021 19:03 UTC
+1

А причем здесь CMake, если vcpkg — это пакетный менеджер, и ничего более.
conan — именно что интеграция локального окружения проекта в процесс сборки. И не предполагает использования для релизной продакшен сборки. Скорее, дополняет пробел в автозаполнении сборочного окружения, если пакетов не доступно для целевой платформы.
vcpkg — пакетный менеджер, который или излишен, или не полон. Conan — девелоперское окружение за две команды консоли в любой системе, не сломав систему. CMake — сборка по де-факто соглашениям, без обязаловки.
CMake — гибкая система сборки с сотнями конфигурируемых и установленных по умолчанию во вменяемые значения параметров. Зависимости могут предоставлять CMake конфиги, и тогда find_package() все для нас сделает, и нам не важно — vcpkg пакет, yum, apt, pacman, или -DCMAKE_FOO_ROOT=/usr/local/foo.
А зависимости могут и не предоставлять конфиги, тогда или pkg-config, штатно оборачиваемый CMake модулями, или вручную написанный модуль, подсунутый через CMAKE_MODULE_PATH.

@Arenoros
30.03.2021 21:07 UTC
+1

Эмм, не совсем понял чем вам conan в проде не устраивает, не знаю многие ли его используют но он отлично применяется, у align technology даже не плохой доклад был об этом на предыдущей cpp russia

@Reformat
31.03.2021 05:40 UTC
0
При том что нужна кроссплатфоременная сборка без лишних телодвижений
31.03.2021 09:56 UTC
0
обычно разработанные у Билла продукты вне windows особо не отличаются хорошестью
01.04.2021 13:03 UTC
0
На данный момент это уже можно считать мифом.
@Sektor2350
31.03.2021 10:14 UTC
-1
Пишу на C#/Kotlin, зашел посмотреть как вы страдаете
@Reformat
31.03.2021 11:04 UTC
0
Тоже пишу на Kotlin, но у Kotlin нет упаковки в один self-executable binary file для CLI утилит
@Sazonov
31.03.2021 11:08 UTC
0

Может подскажите, как можно сказать vcpkg использовать определенный тулчейн?
К примеру, я хочу под Windows получить собранный с помощью clang-cl boost .

@DmitrySokolov
07.04.2021 15:07 UTC
+1
Для C++ есть и другой развитый пакетный менджер Conan, но он требует добавления файла conanfile.txt, а vcpkg обходится одним стадартным CMakeLists.txt

На самом деле можно все зависимости держать в CMakeLists.txt:


if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
  message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
  file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/v0.16.1/conan.cmake"
                "${CMAKE_BINARY_DIR}/conan.cmake"
                TLS_VERIFY ON)
endif()

include(${CMAKE_BINARY_DIR}/conan.cmake)

conan_cmake_configure(REQUIRES fmt/6.1.2 
                      GENERATORS cmake_find_package)

conan_cmake_autodetect(settings)

conan_cmake_install(PATH_OR_REFERENCE .
                    BUILD missing
                    REMOTE conan-center
                    SETTINGS ${settings})

Ссылка на доки: https://docs.conan.io/en/latest/howtos/vs2017_cmake.html#using-cmake-conan

@DmitrySokolov
07.04.2021 15:12 UTC
+1

И этим способом даже не надо самому устанавливать пакеты xxx install y z – они будут на этапе конфигурирования загружены.

@DmitrySokolov
07.04.2021 15:18 UTC
+1
  1. Установка зависимостей


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

На самом деле, это ничем от conan не отличается, просто замените vcpkg на conan, и название пакета приведите к формату, который использует conan.


Фишка conan в том, что все зависимости описываются в файле и потом одной командой устанавливаются conan install .

@saracen
09.04.2021 00:16 UTC
+1
Conan тоже умеет обходиться одним лишь CMakeLists.txt. На гитхабе есть официальная обертка cmake-conan, который сам создаст и спрячет в build все выхлопные файлы.