How to manage dependencies with CMake and VCPKG
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.
If you like this content consider checking out my course on CMake where I cover this and much more.
Table of Contents
- Before continuing
- VCPKG
- Install VCPKG
- Install a package
- Use packages in your C/C++ code
- Cross platform solution
- Skeleton project
Before continuing
To completely understand the contents of this article you should know:
- Basics of CMake. You can start from this post that explains the basics of cmake
- Basics of C++. Start from this post that explains the basics of C++.
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.
- 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.
Note: When downloading vcpkg make sure to use a stable version of vcpkg by going to tags and selecting a corresponding tag commit. This version is the one I tested with. If you are using git you can do the following command:
git clone -b "2020.11" https://github.com/microsoft/vcpkg
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:
Brilliant post this match. I was checking constantly this portal and I'm excited! Extremely useful info specifically the last post :) I was looking for this particular info for a long time. Thank you and good luck...
Leave a comment