Manage dependencies with CMake FetchContent for C++ and OpenGL projects
How to setup Visual Studio Code and CMake to automatically handle the dependencies of your OpenGL and C++ projects.
[Disclaimer: If you don’t want to follow the tutorial and directly look at the code, you can find an advanced version on my GitHub]
Over the years I tried to write my own little graphics engine using C++ and OpenGL. To do so I started using GLFW to handle the multi-platform window creation, the input/events management together with other libraries and utilities like glad and glm.
I am admittedly not very good with C++ and especially in dealing with its complex dependency management (or lack of thereof) and the building environment, so I always wanted to have the simplest way to keep my projects in check and manage the libraries and dependencies in the easiest way.
After having spent years doing it “wrong”, first downloading the source files for the libraries and later at least using git submodules to automate their downloads and updates, I found out about CMake and its FetchContent
module.
CMake and FetchContent
CMake is a build-system generator that using a Domain System Language (DSL) allows you to describe what and how to build and compile your code. The FetchContent
module provides some ways to automatically manage the dependencies of your code, fetching them from other local or remote repositories and defining how to build and integrate them in your code.
CMake is platform and compiler agnostic, it just provides scripts that can be used on several operative systems and can be integrated in your development environment and with your tools. For this reason, it helped me to create projects that can be easily ported and developed on different machines, running MacOSX or Windows without any problem.
By using an IDE like Visual Studio Code, you can leverage several extensions that use your CMake scripts to automatically configure, compile and run your projects.
In this short tutorial I want to show you how I used these tools to quickly set up a C++ project that can be automatically compiled by VSCode with all the needed dependencies fetched from remote GIT repositories.
I start by creating a simple CMakeLists.txt
file that contains our settings for CMake in order to generate the build system that VSCode can use to compile the project.
As you can see, after having told which minimum version of CMake to use, I defined the name of my project (cpp-gl-base
), told where my dependencies will be listed, which file to compile (main.cpp
) and which libraries are needed to be linked with it. Nothing too complicated so far, especially for such a simple situation like this with just one single source file to take care.
The other CMakeLists.txt
lives in the deps/
directory mainly for the sake of separating the concerns between the one dedicated to our source files and the one for the dependencies. In theory this content could be pasted instead of the add_subdirectory(deps)
and it will work as well.
Here we start by including the FetchContent
module that provides two directives: FetchContent_Declare
tells where to get the content to be fetched from and FetchContent_MakeAvailable
to add it to the content in your build system.
As you can see in the case of our three libraries, we use a GitHub repository but it can be a local or remote archive or another source control repo. By defining a GIT_TAG
we can clamp our dependencies to a specific version, streamlining the stabilization of the codebase and easing any update.
If you want to learn more about this module, you can check the FetchContent Documentation and this CMake Workshop.
The main.cpp
Now that we have created the two CMakeLists.txt files, we can add our source code to the directory and compile our project. You should have a directory structure like this:
To test our project with some real C++ and OpenGL code, I took the simple GLFW example on the official library’s documentation and just added a couple of more lines to use glad
to load the OpenGL function pointers. The code just inits the framework, instantiates a 640x480 window managed by GLFW, establishes a basic render loop that clear and swap the buffers and listens to input and window events.
If you want to know more about graphics and game programming, there are plenty of documentation and tutorials on the web to learn game engine development with C++ and OpenGL; my favorite one is LearnOpenGL and it uses GLFW, glad and glm as well.
Visual Studio Code
If you open this project’s directory in Visual Studio Code, it should automatically ask you to download some extensions to manage the CMake workflow for you. Let it install them and VSCode will configure, download and compile the dependencies we listed in our scripts.
VSCode will ask you to choose a “build kit” and depending on your operative system and configuration, you can choose your compiler of choice. In my case - on a MacBook - I have installed and configured Clang
but your mileage may vary.
At the bottom of the IDE you will see a “play” button (circled in red on the picture above): by clicking it VSCode will compile your project and launch it, opening the executable and showing you the awesome little “Hello World” OpenGL window ready to display your game.
Conclusions
This little tutorial should just touch the surface of many topics and it is not intended to be an exhaustive guide on how to develop graphical engine or games in C++ and OpenGL. Nevertheless I hope it provides you an entry point to start with a good base and be able to continue your journey with solid foundations when it comes to dependencies management.
I created a repo on GitHub that contains a little more advanced main.cpp
code and with more libraries added as dependencies in the CMakeLists.txt file: Assimp for 3D assets importing, stb_image for image loading/decoding from file/memory and FreeType to render text. Check it out if you are interested in seeing the next ideal step after this tutorial!
Thanks for your attention and have fun!
Luca
^Back to top