Trying vcpkg
Developing C and C++ projects in a cross-platform manner is not only difficult
because of different system APIs but also because dependencies have to be
tracked, installed and integrated into the build system du jour. While it is
largely a solved problem on Linux thanks to system package managers and de facto
standards such as pkg-config
, the situation on Windows is tricky because both
are missing. Rust and Go easily circumvent this situation by building static
binaries from source using their integrated package managers. In a similar
manner a Microsoft team tries to combine package management and build
integration on Linux, Mac and Windows with their open source vcpkg package
manager.
The main idea is simple: 1) provide a repository with build and dependency descriptions for a wide range of libraries, 2) a CLI tool to actually build said libraries locally and 3) means to make use of these libraries. Each of these points has its pros and cons you can see when trying to build the following C toy example on Linux which depends on the GLib utility library:
#include <glib.h>
int
main (int argc, char *argv[])
{
g_print ("Hello world\n");
return 0;
}
With vcpkg you first have to clone the repository and then build the vcpkg
binary. Easier said than done because the binary requires g++-7 to build. You
then use
vcpkg install glib
to build GLib and all its dependencies which works well but has one big caveat:
Using so-called CONTROL
files, maintainers specify the version of the library
and all their dependencies. Unfortunately, build dependencies are not
versioned but taken from the current state of the repository. This means you can
only pin the version of library A by not upgrading the repository therefore you
are unable to upgrade to a newer version of library B. In the end, vcpkg
is
just like a system package manager and we are nowhere near closer to the Rust
build story.
Now, how do we use our library? Well there’s the first problem. At the moment, the only officially supported way is to write a CMake build script such as this
cmake_minimum_required(VERSION 3.0)
project(hello)
find_path(GLIB_INCLUDE_DIR glib.h)
find_library(GLIB glib REQUIRED)
add_executable(hello hello.c)
target_link_libraries(hello PRIVATE ${GLIB_LIBRARY})
target_include_directories(hello ${GLIB_INCLUDE_DIR})
and passing their toolchain file to the configure process of CMake
cmake <builddir> . -DCMAKE_TOOLCHAIN_FILE=<vcpkgroot>/scripts/buildsystems/vcpkg.cmake
For projects that have native CMake support you can use the find_package
command but as you can see we have to rely on the find_library
and find_path
commands for GLib. Except, it does not work. CMake is unable to find neither
GLib sqlite3
using find_package
as outlined in the documentation. Could we
at least build something by hand? Kind of. All libraries and header files are
installed under <vcpkgroot>/installed/x64-linux
and the various
sub-directories. However, you have to hardcode the paths because pkg-config
files are not installed thus its worse than using system development libraries.
Because of these issues, I would not consider vcpkg
to be an alternative
package and build manager for Linux at the time of writing. There are some good
ideas but spack pretty much does the same for a while now
and they gave way more time thinking into their product. Let’s hope it will get
better.