CMake vcpkg JSON Explained
Modern C++ development can feel confusing because there are several tools involved before your code even runs. You write C++ code, but then you also need a compiler, a build system, external libraries, package management, configuration files, and sometimes IDE-specific settings.
This guide explains how CMake, vcpkg, vcpkg.json, CMakePresets.json, and CMakeLists.txt work together in a C++ project. This is not just a copy-paste setup guide. The goal is to understand the logic behind the workflow so you know what each file does, why it exists, and how the pieces connect.
Watch the full video tutorial: How CMake, vcpkg, and JSON Work Together
Why C++ Project Setup Feels Confusing
C++ is powerful, but the setup ecosystem is not as simple as languages like Python, JavaScript, or Rust. In Python, you install packages with pip. In JavaScript, you use npm. In Rust, Cargo handles project creation, dependencies, builds, and tests in one clean workflow.
C++ is older and more fragmented. The language itself does not come with one official package manager or one official build system. That means developers often need to combine multiple tools:
- A compiler such as MSVC, Clang, or GCC
- A build system generator such as CMake
- A package manager such as vcpkg
- A project file such as CMakeLists.txt
- A dependency manifest such as vcpkg.json
- A configuration file such as CMakePresets.json
This looks messy at first, but once you understand the responsibility of each tool, the workflow becomes much more logical.
The Short Version
Here is the clean mental model:
- vcpkg downloads and manages external C++ libraries.
- vcpkg.json lists the libraries your project needs.
- CMake describes how your project should be built.
- CMakeLists.txt tells CMake what targets, files, and libraries your project uses.
- CMakePresets.json stores build configuration so you do not repeat long terminal commands.
- The vcpkg toolchain file connects CMake to libraries installed by vcpkg.
In other words, vcpkg handles dependencies, CMake handles the build structure, and JSON files make the setup repeatable.
What Is vcpkg?
vcpkg is a C and C++ package manager created by Microsoft. Its job is to download, build, and organize external libraries so you do not have to manually download zip files, copy include folders, link binary files, or fight with library paths.
Without a package manager, adding a library to a C++ project often becomes painful. You may need to:
- Find the correct library version manually
- Download source code or prebuilt binaries
- Configure include directories
- Configure library directories
- Link the correct debug and release binaries
- Handle platform-specific differences
- Repeat the setup on every machine
That is exactly the kind of nonsense that wastes hours. vcpkg solves a large part of this by giving you one consistent way to declare and install libraries.
For example, instead of manually setting up Raylib, you can let vcpkg handle it:
vcpkg install raylib
Or, in manifest mode, you can list Raylib inside vcpkg.json and let vcpkg install it as part of the project workflow.
What Is vcpkg.json?
vcpkg.json is the dependency manifest file for your project. It tells vcpkg which libraries your project needs.
A simple example looks like this:
{
"name": "my-game-project",
"version-string": "0.1.0",
"dependencies": [
"raylib",
"chipmunk"
]
}
This file says: this project is named my-game-project, its current version is 0.1.0, and it depends on raylib and chipmunk.
When vcpkg sees this file, it knows what to install. The benefit is that your dependencies are stored directly inside your project. If another developer clones the project, they can see exactly which libraries are needed.
Why vcpkg.json Is Better Than Manual Installation
Manual dependency setup is fragile. Maybe the project works on your machine because you installed a library six months ago, but then it fails on another computer because the include path is missing or the wrong binary version is linked.
A manifest file fixes that problem because dependencies become part of the project definition.
With vcpkg.json:
- Your project dependencies are visible.
- The setup is easier to reproduce.
- You can add or remove libraries in one place.
- Team members do not need to guess which packages are required.
- CI and build servers can install the same dependencies automatically.
This is the same basic idea behind package.json in JavaScript or Cargo.toml in Rust. It makes your project easier to rebuild from scratch.
What Happens When You Run vcpkg install?
When you run:
vcpkg install
vcpkg reads the vcpkg.json file, checks the dependency list, downloads the required libraries, builds them if needed, and places them into a local installed directory.
In manifest mode, this usually creates or uses a folder such as:
vcpkg_installed
Inside that folder, vcpkg stores the headers, libraries, CMake config files, and platform-specific build outputs needed by your project.
The important point: your C++ code does not directly talk to vcpkg. Your build system does. That is where CMake enters the workflow.
What Is CMake?
CMake is not a compiler. This is one of the biggest beginner misunderstandings.
CMake does not compile your C++ code directly. Instead, it generates build files for other tools. Depending on your platform and configuration, CMake may generate:
- Visual Studio project files
- Ninja build files
- Makefiles
- Xcode project files
Think of CMake as the project build planner. It reads your build instructions, figures out which source files exist, which libraries are needed, which compiler settings apply, and then prepares the build system that will actually compile the code.
What Is CMakeLists.txt?
CMakeLists.txt is the main build script for a CMake project. It describes your project structure.
A simple version might look like this:
cmake_minimum_required(VERSION 3.21)
project(MyGameProject LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(raylib CONFIG REQUIRED)
find_package(chipmunk CONFIG REQUIRED)
add_executable(MyGameProject
main.cpp
)
target_link_libraries(MyGameProject
PRIVATE
raylib
chipmunk
)
This file tells CMake several important things:
- The minimum CMake version required
- The project name
- The programming languages used
- The C++ standard to use
- Which external packages are required
- Which source files create the executable
- Which libraries must be linked to the executable
How find_package Works
The line:
find_package(raylib CONFIG REQUIRED)
tells CMake to look for Raylib’s package configuration files. These config files explain how Raylib should be included and linked.
But here is the key detail: CMake needs to know where to search for those package configuration files. By default, it may not know where vcpkg installed Raylib. That is why we need the vcpkg toolchain file.
What Is a CMake Toolchain File?
A toolchain file tells CMake how to configure the build environment. In the vcpkg workflow, the toolchain file connects CMake to vcpkg’s installed packages.
The vcpkg toolchain file is usually located somewhere like:
path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
When CMake is configured with this toolchain file, CMake understands how to find the libraries installed by vcpkg.
Without the toolchain file, this may fail:
find_package(raylib CONFIG REQUIRED)
With the toolchain file properly configured, CMake can find Raylib and link it correctly.
What Is CMakePresets.json?
CMakePresets.json is a configuration file that stores common CMake setup options. Instead of typing a long command every time, you define presets once and reuse them.
A basic preset might look like this:
{
"version": 3,
"configurePresets": [
{
"name": "debug",
"displayName": "Debug Build",
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake"
}
}
],
"buildPresets": [
{
"name": "debug",
"configurePreset": "debug"
}
]
}
This file defines:
- The build generator, such as Ninja
- The output build directory
- The build type, such as Debug
- The vcpkg toolchain path
- Named configure and build presets
Once this exists, your IDE or terminal can use the preset instead of manually passing every setting.
Why CMakePresets.json Matters
CMake can be configured through terminal commands, but those commands can get long and annoying.
For example, without presets, you might need something like:
cmake -S . -B out/build/debug -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=C:/dev/vcpkg/scripts/buildsystems/vcpkg.cmake
That command is ugly. Worse, it is easy to mistype.
With CMakePresets.json, you can store that setup and run:
cmake --preset debug
Then build with:
cmake --build --preset debug
That is cleaner, repeatable, and easier for teams.
How the Whole Workflow Connects
Here is the complete flow:
- You declare dependencies in
vcpkg.json. - vcpkg installs those dependencies.
CMakePresets.jsontells CMake to use the vcpkg toolchain file.- CMake reads
CMakeLists.txt. find_packagelocates packages installed by vcpkg.target_link_librarieslinks those libraries to your executable.- Your C++ source code can include and use those libraries.
The clean version:
vcpkg.json = what libraries do we need?
vcpkg = download and prepare those libraries
CMakePresets.json = how should CMake configure the project?
CMakeLists.txt = what should be built and linked?
C++ source files = the actual program logic
Example: Raylib and Chipmunk in One Project
Let’s say you are building a small C++ game prototype. You want Raylib for rendering and input, and Chipmunk for physics.
Your vcpkg.json could look like this:
{
"name": "raylib-chipmunk-game",
"version-string": "0.1.0",
"dependencies": [
"raylib",
"chipmunk"
]
}
Your CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.21)
project(RaylibChipmunkGame LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(raylib CONFIG REQUIRED)
find_package(chipmunk CONFIG REQUIRED)
add_executable(RaylibChipmunkGame
main.cpp
)
target_link_libraries(RaylibChipmunkGame
PRIVATE
raylib
chipmunk
)
Then your code can include what it needs:
#include <raylib.h>
#include <chipmunk/chipmunk.h>
int main()
{
InitWindow(800, 600, "Raylib + Chipmunk");
SetTargetFPS(60);
while (!WindowShouldClose())
{
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("CMake + vcpkg is working", 20, 20, 20, BLACK);
EndDrawing();
}
CloseWindow();
return 0;
}
The important part is that your code does not need hardcoded include directories or manual library paths. CMake and vcpkg handle that connection.
What Each File Is Responsible For
| File or Tool | Main Responsibility | Example Question It Answers |
|---|---|---|
| vcpkg | Package manager | How do we download and install Raylib? |
| vcpkg.json | Dependency manifest | Which libraries does this project require? |
| CMake | Build system generator | How should build files be generated? |
| CMakeLists.txt | Project build definition | Which source files and libraries make the executable? |
| CMakePresets.json | Reusable configuration | Which generator, build folder, and toolchain should be used? |
| Compiler | Actual compilation | How is C++ converted into machine code? |
Why JSON Appears in This Workflow
JSON is used here because it is simple, structured, and easy for tools to read. Both vcpkg.json and CMakePresets.json are configuration files, not C++ code.
They describe project metadata and settings:
vcpkg.jsondescribes dependencies.CMakePresets.jsondescribes build configuration.
JSON is not building your code. It is giving instructions to tools that manage the build workflow.
Common Beginner Confusion
Is vcpkg the same as CMake?
No. vcpkg manages dependencies. CMake generates build files. They work together, but they do different jobs.
Is CMake a compiler?
No. CMake generates build instructions. The compiler is still MSVC, Clang, or GCC.
Does vcpkg compile my project?
No. vcpkg may build external libraries, but your project is built through CMake and your compiler.
Why do I need a toolchain file?
The vcpkg toolchain file tells CMake how to find and use packages installed by vcpkg.
Do I need CMakePresets.json?
Technically no, but it makes your workflow cleaner and more repeatable. For serious projects, it is worth using.
Classic Mode vs Manifest Mode in vcpkg
vcpkg can be used in two common ways: classic mode and manifest mode.
Classic Mode
You manually install packages globally into a vcpkg installation:
vcpkg install raylib
This is simple, but the dependency list is not stored directly in your project unless you document it manually.
Manifest Mode
Your project includes a vcpkg.json file. vcpkg reads it and installs what the project needs.
Manifest mode is usually better for real projects because the dependencies travel with the repository.
Recommended Project Structure
A simple C++ project using CMake and vcpkg could look like this:
MyGameProject/
├── CMakeLists.txt
├── CMakePresets.json
├── vcpkg.json
├── src/
│ └── main.cpp
├── include/
│ └── MyGameProject/
│ └── Game.h
└── out/
└── build/
└── debug/
Keep source files in src, headers in include, and build output in a separate directory such as out/build. Do not mix generated build files with your source files.
Best Practices for CMake and vcpkg
- Use
vcpkg.jsonfor project dependencies. - Use
CMakePresets.jsonto store repeatable build configuration. - Keep
CMakeLists.txtclean and target-based. - Prefer
target_link_librariesover global linker settings. - Do not hardcode random include paths unless absolutely necessary.
- Use one build folder per configuration, such as Debug and Release.
- Do not commit build output folders to Git.
- Make sure your team uses the same presets to reduce setup problems.
The goal is not to make CMake complicated. The goal is to make the project reproducible.
Common Mistakes to Avoid
Putting target_link_libraries Before add_executable
CMake needs the target to exist before you link libraries to it. Usually, create the executable first, then link libraries.
Forgetting the vcpkg Toolchain File
If CMake cannot find packages installed by vcpkg, the toolchain file is often missing or wrong.
Using the Wrong Package Name
The dependency name in vcpkg.json must match the package name in the vcpkg catalog.
Confusing Debug and Release Builds
Debug and Release may use different binaries and output folders. Presets help keep them separate.
Manually Copying Libraries Into the Project
If you are using vcpkg, avoid manually copying library files around. That defeats the purpose of using a package manager.
How This Helps Game Developers
For game developers, this workflow is especially useful because game projects often depend on many external libraries:
- Raylib for simple rendering and prototyping
- SDL for windowing and input
- Box2D or Chipmunk for physics
- fmt for formatting strings
- glm for math
- imgui for debug tools and editor panels
- nlohmann-json for JSON parsing
Without dependency management, every new library becomes a setup problem. With vcpkg and CMake, adding a library becomes much more controlled.
Real Workflow Example
A practical workflow may look like this:
- Create a new project folder.
- Add
main.cpp. - Create
CMakeLists.txt. - Create
vcpkg.jsonand list dependencies. - Create
CMakePresets.jsonand point it to the vcpkg toolchain. - Run
cmake --preset debug. - Run
cmake --build --preset debug. - Run the executable.
Once the setup works, adding more libraries becomes much easier. You update vcpkg.json, update CMakeLists.txt, configure again, and build.
Final Mental Model
If all of this still feels heavy, remember this:
vcpkg.json says what you need.
vcpkg downloads it.
CMakePresets.json says how to configure.
CMakeLists.txt says what to build.
CMake generates build files.
The compiler builds the final program.
That is the whole system.
Conclusion
CMake, vcpkg, and JSON files are not random extra complexity. They solve different problems in the C++ workflow.
vcpkg gives you dependency management. vcpkg.json makes those dependencies explicit. CMake defines your build. CMakeLists.txt describes your targets and links. CMakePresets.json makes configuration repeatable. The toolchain file connects CMake to vcpkg.
Once you understand that separation, C++ project setup becomes much less mysterious. It still has more friction than modern managed ecosystems, but it becomes predictable. And for serious C++ work, predictable matters more than magic.
Watch the full explanation: How CMake, vcpkg, and JSON Work Together
Useful resources: vcpkg Package Catalog, CMake Documentation, Raylib, Chipmunk Physics, and rambod.net.
Frequently Asked Questions
What is vcpkg used for in C++?
vcpkg is used to install and manage C and C++ libraries. It helps avoid manual dependency setup and works well with CMake projects.
What does vcpkg.json do?
vcpkg.json lists the dependencies your project needs. vcpkg reads this file and installs those packages for the project.
What does CMake do?
CMake generates build files for tools like Ninja, Visual Studio, Make, or Xcode. It does not directly compile the code itself.
What is CMakeLists.txt?
CMakeLists.txt is the main CMake build script. It defines your project, source files, targets, packages, and linked libraries.
What is CMakePresets.json?
CMakePresets.json stores reusable CMake configuration settings such as generator, build directory, build type, and toolchain path.
Why does CMake need the vcpkg toolchain file?
The vcpkg toolchain file tells CMake where and how to find libraries installed by vcpkg.
Can I use this workflow with CLion?
Yes. CLion has strong CMake support and can use CMake presets and vcpkg integration for modern C++ projects.
Can I use this workflow for game development?
Yes. This workflow is useful for C++ game development with libraries like Raylib, SDL, Chipmunk, Box2D, imgui, and other native libraries.
Related Tutorials
More lessons connected by category, tags, engine version, or implementation type.
Recommended resource
Recommended for this tutorial
Useful tools selected for this workflow topic.