Menu Share

How to manage dependencies with CMake and VCPKG

by | Last Updated:
ANSI C, C++

Save Share Print

Managing dependencies for C++ has been pretty hard for years. C++ is an old language and doesn’t have some concepts that the more modern languages have like a package manager. Package manager would usually download for you some external code that already implements functionality that you want. When creating games for example raylib is a nice library that adds a lot of coding functionality that you wouldn’t have to worry about and just use straight on.

Table of Contents

Before continuing

To completely understand the contents of this article you should know:

VCPKG

My choice when doing package management for C++ is VCPKG which is an open-source tool created by Microsoft. It nicely integrates when used directly for Visual C++ development (without CMake) and could as easily be integrated into a CMake project. The vcpkg tool will download C++ code compile it into libraries and will take care to copy the needed file to our end directory when we build our project. Sounds like magic so lets begin!

Install VCPKG

To start you can download vcpkg from its github repository here https://github.com/microsoft/vcpkg . Then extract it relative to the project in a folder called “vcpkg” so that we produce the following structure.

root
├── vcpkg/
│ └── ...extracted files...
├── src/
│ └── main.cpp
└── CMakeLists.txt

Following the instructions in the vcpkg github repository then we would need to execute this command from the root of our project:

> ./vcpkg/bootstrap-vcpkg.bat

This would install everything needed for us to start doing package management for C++ on the current project.

Install a package

I will use the raylib project as an example. To install a library for use with cmake you would then need to run the following command from the root of your project:

> ./vcpkg/vcpkg.exe install raylib:x64-windows

This will instruct vcpkg to search for raylib and download it. It will also set it up for compilation using a x64 processor set up and compile it for windows. The compiled package will be put into “.\vcpkg\installed\x64-window” and split into the relevant directories for include, lib and other files.

Use packages in your C/C++ code

To be able to link and use the raylib package in our C++ code then we would need to add the following lines into our CMakeLists.txt file:

# ...set this right below the cmake_minimum_required
set(CMAKE_TOOLCHAIN_FILE ./vcpkg/scripts/buildsystems/vcpkg.cmake)

# ...somewhere after the call to project

include_directories(./vcpkg/installed/x64-windows/include)
link_directories(./vcpkg/installed/x64-windows/lib)

# ...and after our target Main

target_link_libraries(Main PRIVATE raylib.lib)

We also need to generate cmake with the VCPKG toolchain. To do this when executing cmake generation we would change it by adding the following flag:

> cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake

Then I took the first example from the raylib site and put it into the Main.cpp file. You can also play around with all other examples on this link https://www.raylib.com/examples.html.

/*******************************************************************************************
*
*   raylib [core] example - Basic window
*
*   Welcome to raylib!
*
*   To test examples in Notepad++, provided with default raylib installer package, 
*   just press F6 and run [raylib_compile_execute] script, it will compile and execute.
*   Note that compiled executable is placed in the same folder as .c file
*
*   You can find all basic examples on [C:\raylib\raylib\examples] directory and
*   raylib official webpage: [www.raylib.com]
*
*   Enjoy using raylib. :)
*
*   This example has been created using raylib 1.0 (www.raylib.com)
*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
*
*   Copyright (c) 2013-2020 Ramon Santamaria (@raysan5)
*
********************************************************************************************/

#include "raylib.h"

int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------------------
    const int screenWidth = 800;
    const int screenHeight = 450;

    InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");

    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
    //--------------------------------------------------------------------------------------

    // Main game loop
    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        // Update
        //----------------------------------------------------------------------------------
        // TODO: Update your variables here
        //----------------------------------------------------------------------------------

        // Draw
        //----------------------------------------------------------------------------------
        BeginDrawing();

            ClearBackground(RAYWHITE);

            DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY);

        EndDrawing();
        //----------------------------------------------------------------------------------
    }

    // De-Initialization
    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

We then just build and run like normal. The vcpkg toolchain would take care of copying any dependencies like .dll files in the output directory.

Cross platform solution

A more cross-platform solution would be to use the find_package utility that the vcpkg toolchain provides. To do this you need to make the following changes in the CMakeLists.txt file:

# Remove these lines of code
#include_directories(./vcpkg/installed/x64-windows/include)
#link_directories(./vcpkg/installed/x64-windows/lib)
# ... so that we can replace them with:

find_package(raylib CONFIG REQUIRED)

# ...and after our target Main

target_include_directories(Main PRIVATE ${raylib_INCLUDE_DIRS})
target_link_libraries(Main PRIVATE ${raylib_LIBRARIES})

I have not come up randomly with these. The usage is described in the download directory of the packages and is usually printed on running the install command. This would be:

./vcpkg/packages/raylib_x64-windows/share/raylib/usage

Skeleton project

You can always use my skeleton project on starting with vcpkg that already has vcpkg prepared for CMake as well with the include directories set up. It pretty much sums up everything provided in this article so far.


You can follow up with:

Save Share Print

Leave a comment