Oh, So There Are C++ Package Managers?

I know I have beaten this topic up a little bit in a previous post, but when coming from a language like Python, you really get comfortable with the idea of just using pip to install all of your modules.  Need PyTorch?  Just run pip install torch and you can use it as soon as it is finished installing (usually).  When you step into the world of C++ though, it is really not that simple anymore.

C++ has a few ways to install packages and generally none of them are as simple as pip. On top of that, there is a lot of information out there on the “proper” way to install packages.  Some developers swear by using git submodule add to include a project directly from github or gitlab into their projects.  Others will use a system package manager like apt or yum (and now chocolatey on Windows too), which is almost as simple as using something like pip.

There is yet another candidate though, which is C++ package managers.  There are a handful of them already, but the big two are Conan and vcpkg.  C++ package managers work on multiple systems, handle version conflicts between packages for you, and allow for easy update of packages with new releases.  Of course, I am assuming you, the reader, came from a language that already has package managers so I won’t bore you too much with the details.

Getting Started with Vckpg

At this point, I am sure you are itching to actually learn to use a package manager so let’s pick vckpg.  This is completely my personal preference, so feel free to try out Conan if you would prefer, but for the sake of simplicity I will only be introducing one in this post.  The initial setup is pretty straightforward and you can see it on their getting started page.  

It’s nice and simple, but of course I am a fan of having my projects wrapped in a docker environment so I’ll give a demonstration of that.  Keep in mind this can be any docker image setup for C++. You can just clone vcpkg and build it yourself in your own project the same way that I did in my dockerfile.

Here’s an example of what my Dockerfile looks like:

Dockerfile
FROM gcc:13.2.0

# Only set this if you are working on an ARM device
ENV VCPKG_FORCE_SYSTEM_BINARIES=1

RUN apt update
RUN apt -y install git ninja-build cmake build-essential tar curl zip unzip bison libdbus-1-dev libxi-dev libxtst-dev

RUN ln -s /usr/bin/ninja /usr/bin/ninja-build

RUN git clone https://github.com/Microsoft/vcpkg.git

RUN ./vcpkg/bootstrap-vcpkg.sh

ENV PATH=/vcpkg/:${PATH} 

WORKDIR /code

Version Control with Vckpg

When you make a project that uses vcpkg, there are two ways to use vcpkg.  Classic mode lets you just install packages the same way you would with a system package manager.  That’s not great though when you are trying to follow good development practices.  Instead, the recommended mode is manifest mode.  To use manifest mode all you need to do is add a manifest file, which can be as simple as this:

JSON
{
    "dependencies": [
      "eigen3"
    ]
}

My example here is just a super simple manifest mode that only contains Eigen3 in it.  However, if you check out their documentation on manifests, you can get much more detailed with it, including adding versions, etc.

Using CMake Together with Vckpg

This is optional if you are using something else to build with, but vcpkg works pretty seamlessly together with cmake.  To add packages from vcpkg you just need to set your toolchain file to the vcpkg.cmake file inside wherever you installed vckpg.  Then you can add your packages using find_package and link them to your executable with target_link_libraries.

Here’s an example of what that looks like.

CMake
cmake_minimum_required(VERSION 3.8)

set(CMAKE_TOOLCHAIN_FILE vcpkg/scripts/buildsystems/vcpkg.cmake)

project(main)

add_executable(main main.cpp)

find_package(Eigen3 3.3 REQUIRED NO_MODULE)
target_link_libraries(main PRIVATE Eigen3::Eigen)

Cheat Code

If you don’t have any requirements for which docker image to use, you could always use a Microsoft C++ image.  They already have vcpkg installed on them so setup is super simple. There’s a copy of an example dockerfile and docker-compose.yaml in this repository.  The only thing you have to be careful of is where you set your toolchain file, which you will need to confirm the location of before running cmake, but that’s easy right!

Dockerfile
FROM mcr.microsoft.com/devcontainers/cpp:ubuntu

Source Code

For the source code used in this article, including a docker-compose.yaml file to make building easier, check out this folder in the blog git repo. Also, here is a link to the folder with the Cheat Code example as well.

Final Remarks

For the most part I find vckpg to be very straightforward to use and easy to integrate with cmake.  I plan to use it for most of my projects now, because I think its a better way of maintaining dependencies than relying on installing manually or adding projects as git submodules.

The only major downside I can see so far is that packages are not always consistently maintained and I had quite a bit of trouble trying to get libtorch to install properly.  That isn’t a dealbreaker though.  If I couldn’t get a package to install properly, I would simply use vcpkg for everything I could and install what I needed with a system package manager or add it as a submodule.  I hope I don’t have to do that too often though because it feels kind of dirty.


Posted

in

by

Tags:

Comments

Leave a Reply

en_USEN