How to integrate Vcpkg with Meson Build system

· Francesco · 4 min read · 760 words
Table of Contents

Photo by @theshubhamdhage from Unsplash.com

The worst part about developing on Windows is developing on Windows. Okay, jokes aside, life is generally easier on Linux.

On Linux, package management is typically handled by the OS. You just download the library with the -devel suffix, and in meson.build, you add the dependency() function to link it to your program.

On Windows, however, you often find yourself hunting for sketchy installers, manually wiring up INCLUDE and LIB paths, or dealing with the dreaded “DLL hell”.

So, how do we get Vcpkg (which handles the messy downloading part) to play nice with Meson (which handles our build configuration)? The secret sauce is a native-file.

The Native File

If you haven’t used it, Vcpkg is Microsoft’s C/C++ package manager. To make it talk to Meson, we need a “Native File”.

Think of this file as a bridge. It tells Meson specific details about your machine, like where to find the pkg-config executable. Since Vcpkg actually generates pkg-config files for the libraries it installs, pointing Meson to Vcpkg’s internal pkgconf.exe makes standard dependency() calls work like magic.

Here is the native file content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[constants]
vcpkg_base_path = 'C:/vcpkg/'
vcpkg_base_install_dir = 'C:/vcpkg/installed/'

vcpkg_target_triplet = 'x64-windows'
vcpkg_host_triplet = 'x64-windows'

vcpkg_installed_dir =  vcpkg_base_install_dir + vcpkg_target_triplet + '/'
vcpkg_host_installed_dir = vcpkg_base_install_dir + vcpkg_host_triplet + '/'
vcpkg_toolchain_file =  vcpkg_base_path + 'scripts/toolchains/windows.cmake'

[properties]
cmake_toolchain_file = vcpkg_base_path + 'scripts/buildsystems/vcpkg.cmake'

[binaries]
vcpkg = [ vcpkg_base_path + 'vcpkg.exe']
pkgconfig = [ vcpkg_installed_dir + 'tools/pkgconf/pkgconf.exe']

[cmake]
VCPKG_TARGET_TRIPLET = vcpkg_target_triplet
VCPKG_HOST_TRIPLET = vcpkg_host_triplet
VCPKG_CHAINLOAD_TOOLCHAIN_FILE = vcpkg_base_path + 'scripts/toolchains/windows.cmake'
_VCPKG_INSTALLED_DIR = vcpkg_installed_dir
VCPKG_CRT_LINKAGE = 'dynamic'

[built-in options]
pkg_config_path =  [ vcpkg_installed_dir + 'lib/pkgconfig;' + vcpkg_installed_dir + 'share/pkgconfig']
cmake_prefix_path = [ vcpkg_installed_dir ]

Save it somewhere (I named it meson-vcpkg.txt and placed it in the same folder as the meson.build file).

Important: Modify vcpkg_base_path and vcpkg_base_install_dir inside the file so that they point to your actual Vcpkg installation folder.

Manifest Mode

I used to install packages manually via the command line (e.g., vcpkg install sdl3), but these days I strongly recommend using Manifest Mode. It keeps your project entirely self-contained and guarantees that anyone who clones your repo gets the exact same dependencies without any headaches.

Create a vcpkg.json in your project root:

1
2
3
4
5
6
{
  "name": "meson-vcpkg",
  "version": "1",
  "description": "Testing meson and vcpkg integration together using manifest mode of vcpkg",
  "dependencies": ["sdl3", "libyaml", "pkgconf"]
}

Add your dependencies under “dependencies”. I added SDL3, libyaml, and pkgconf (which is required for the integration to work) as examples.

The Build File

Now, set up your meson.build to consume these packages. Notice how clean it is—no hardcoded paths!

1
2
3
4
5
6
7
8
9
project('meson-vcpkg', 'c', default_options: ['c_std=c11', 'warning_level=3'])

# These dependencies will be found via the native file configuration
sdl3_dep = dependency('sdl3')
libyaml_dep = dependency('yaml-0.1')

deps = [sdl3_dep, libyaml_dep]

executable('deptest', 'main.c', dependencies: [deps])

Building the Project

Finally, configure the build folder. We pass the --native-file argument to tell Meson about our Vcpkg configuration.

1
$ meson setup build --native-file meson-vcpkg.txt

Example output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
The Meson build system
Version: 1.8.0
Source dir: C:\meson-vcpkg
Build dir: C:\meson-vcpkg\build
Build type: native build
Project name: meson-vcpkg
Project version: undefined
C compiler for the host machine: clang (clang 20.1.4 "clang version 20.1.4")
C linker for the host machine: clang link 14.44.35207.1
Host machine cpu family: x86_64
Host machine cpu: x86_64
Found pkg-config: YES (C:/vcpkg/installed/x64-windows/tools/pkgconf/pkgconf.exe) 2.4.3
Run-time dependency sdl3 found: YES 3.2.12
Run-time dependency yaml-0.1 found: YES 0.1
Build targets in project: 1

meson-vcpkg undefined

  User defined options
    Native files: .\meson-vcpkg.txt
    wrap_mode   : nodownload

Found ninja-1.12.1 at "C:\Program Files\Meson\ninja.EXE"

It will automatically invoke Vcpkg to install the dependencies listed in vcpkg.json before the build starts.

Troubleshooting

Missing DLLs

If you’re anything like me, you might run into a wall where your compiled program crashes immediately at startup, complaining about missing .dll files.

This happens because Windows loads dynamic libraries from the executable’s directory or the system PATH. Vcpkg builds dynamic libraries by default, but it doesn’t automatically copy them to your output folder.

Solution: You need to copy all the necessary DLL files into the build folder (where your executable is located).

Demonstration

If you want to see all of this put together in a real project, I’ve set up a working example over on my GitHub repo.