The best practice for vcpkg & Qt QML application -- manage C++ libraries with an ease

vcpkg is a C++ Library Manager for Windows, Linux, and MacOS. vcpkg for C++ is the same as npm for node.js. On the Windows platform, for a long time, people have to manually compile various libraries with different parameters. When library A depends on library B, library B must be compiled too. Therefore, the process of building the project is very time-consuming. vcpkg can solve this problem, all dependencies can be installed just use one command vcpkg install.

On Windows, I always prefer to use VSCode instead of Visual Studio, because VSCode is much faster! So, I try to find a best practice to develop C++ applications on VSCode with the help of vcpkg. You can just grab the sample source code here.

Using vcpkg in manifest mode

The documentation says we have two ways to use vcpkg, ony way is global-shared (such as C:\src\vcpkg), one way is per-project-wide. One vcpkg instance per project, aka the manifest mode. I think the latter is the best practice because we can avoid version conflicts for different projects.

In the manifest mode, the vcpkg.json for vcpkg is pretty the same with package.json for npm. We can declare all the dependencies we need, just like this:

In the vcpkg.json above, we want to install sqlite3:x64-windows. Note that currently there some problems with vcpkg’s QML support, so we should install Qt manually.

Once you have created you project and CMakeLists.txt, you can add vcpkg instance using git submodules:

And then you need to add the vcpkg’s toolchain file, the file will care about downloading and build dependencies, copy DLLs, etc. You can add this in you CMakeLists.txt:

In the CMake code above, we enable the versions feature for the dependencies.version>= in vcpkg.json to work properly. And we use the toolchain file of the cloned vcpkg submodule in the current directory if there is no VCPKG_ROOT environment variable define. It means you can define VCPKG_ROOT to force CMake to use the global vcpkg instance.

All you need now is just modifying you CMakeLists.txt with find_package and target_link_libraries, then write you C++ code, and build again to see the results, no more cumbersome work!

VSCode Intelligence

For a small project, you may just use hard-coded include folder for your intelligence to work. According to the c_cpp_properties.json reference docs, you may use this configuration for Qt & STL intelligence to work:

In this way, we have to change this configuration every time if we add a new library in vcpkg.json and CMakeLists.txt, so this is not ideal.

Actually, we can make use of the compileCommands property, and feed VSCode with the include meta-info generated by CMake.

First, we need to enable CMake’s CMAKE_EXPORT_COMPILE_COMMANDS:

Then run CMake configure again, you will get an compile_commands.json file on your build output folder. We can feed it into the VSCode C++ extension. In .vscode/c_cpp_properties.json, just use:

This is all you need to do for the intelligence.

Build & Debug

For faster build time, we can use Ninja generator instead of Visual Studio generator, which is bring to you with VC Tools, you can start an
“x64 Native Tools Command Prompt for VS2019” and type “ninja” to check:

You can just use CMake Tools extension on VSCode, with the following configuration:

Then add the following tasks to .vscode/tasks.json because we want to use windeployqt to deploy qt apps on Windows, and run build task on each debug session:

Finally you just add the debug configuration to .vscode/launch.json:

Now you can press F5 to start debugging your application. And, don’t forget to run windeployqt task on the first successful build.