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:
git submodule add https://github.com/microsoft/vcpkg |
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
:
list(APPEND VCPKG_FEATURE_FLAGS "versions") |
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
:
# https://stackoverflow.com/a/50360945/8242705 |
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:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community>ninja --version |
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.
CI build with cache & artifact uploading
We can use GitHub Actions to run build task on each commit. The key points we need are:
-
Cache vcpkg packages for reuse on next CI run. This will make the CI run much more faster.
# Restore from cache the previously built ports. If cache-miss, download and build vcpkg (aka "bootstrap vcpkg").
- name: Restore from cache and install vcpkg
# Download and build vcpkg, without installing any port. If content is cached already, it is a no-op.
uses: lukka/run-vcpkg@v6
with:
# Just install vcpkg for now, do not install any ports in this step yet.
setupOnly: true
# Location of the vcpkg submodule in the Git repository.
vcpkgDirectory: '${{ github.workspace }}/vcpkg'
# Since the cache must be invalidated when content of the vcpkg.json file changes, let's
# compute its hash and append this to the computed cache's key.
appendedCacheKey: ${{ hashFiles( '**/vcpkg_manifest/vcpkg.json' ) }}
vcpkgTriplet: ${{ matrix.arch }}-windows
# Ensure the vcpkg artifacts are cached, they are generated in the 'CMAKE_BINARY_DIR/vcpkg_installed' directory.
additionalCachedPaths: ${{ env.buildDir }}/vcpkg_installed -
Upload Built package to GitHub Artifact area. This will make your release procedure easier.
- name: Set outputs
id: vars
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Get Time
id: time
uses: nanzm/get-time-action@v1.1
with:
timeZone: 8
format: 'YYYY-MM-DD-HH-mm-ss'
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - uploading artifact (whole zip)
uses: actions/upload-artifact@master
with:
name: ${{ env.name }}-${{ steps.time.outputs.time }}-${{ steps.vars.outputs.sha_short }}-windows-${{ matrix.arch }}.zip
path: build
- name: Win-${{ matrix.arch }} - ${{ matrix.qt_version }} - uploading artifact (only the exe)
uses: actions/upload-artifact@master
with:
name: ${{ env.name }}-${{ steps.time.outputs.time }}-${{ steps.vars.outputs.sha_short }}-windows-${{ matrix.arch }}.exe
path: build/${{ env.name }}.exe
Get the template
The template is on GitHub: https://github.com/upupming/vscode-qt-qml-vcpkg-template/ , if you have any questions and suggestions, please fell free to open an issue, thanks!