Packaging libbpf with vcpkg
by Mike Przybylski
Previously
Managing dependencies with vcpkg
libbpf: the missing package
In the interest of maintainability, I want vcpkg to be bpf-iotrace’s one-stop shop for managing third-party code. Since vcpkg’s default registry doesn’t include libbpf, I will need to package it myself the vcpkg way.
I’ll make an educated guess that the biggest reason libbpf isn’t already in the default vcpkg registry is that its
build procedure diverges pretty sharply from what is typical for a Makefile-based open source project.
Most Makefile-based open source projects use
GNU autotools
to generate a Makefile tailored for the build environment and the target system.
Those projects also typically separate the source and build directories, also known as an out-of-source build.
libbpf doesn’t require this level of complexity
and uses a manually written Makefile
located in the same directory as the library source.
Also, make must be called from the source directory, (an in-source build).
This has the advantage of fewer dependencies and faster build times.
The disadvantage is that
vcpkg_configure_make() and
vcpkg_build_make() aren’t
written to work with a project that is structured this way.
Adapting the libbpf build to be compatible with vcpkg conventions
As I noted in my previous article,
an overlay ports directory is an excellent
place to keep a library while developing and testing because it enables rapid iteration.
So I created the tools/vcpkg-overlays/ports/libbpf and its parents in the bpf-iotrace project and referenced
tools/vcpkg-overlays/ports in
vcpkg-configuration.json.
Then I added the following files to tools/vcpkg-overlays/ports/libbpf:
-
vcpkg.json: The manifest file that describes the port and declares
libbpf’s direct dependency on elfutils libelf. - CMakeLists.txt:
This file wraps the
libbpfbuild system to make it look from the outside like a typical CMake project.vcpkgworks really easily with CMake projects. - portfile.cmake that
fetches and unpacks the specified version of
libbpf, calls vcpkg_cmake_configure(), vcpkg_cmake_build(), and vcpkg_cmake_install() to build and installlibbpf.
vcpkg ports like bzip2 use a
CMakeLists.txt file that completely bypasses the upstream project’s build system.
While this may be a good fit for projects that rarely change, it is not a good fit for libbpf,
which is constantly evolving. It is highly likely that new releases of libbpf would break a CMakeLists.txt
that attempts to bypass the existing Makefile.
This breakage can easily happen if libbpf adds new source files or refactors existing ones.
Keeping those parallel build systems in sync would simply be more trouble than it’s worth.
Fortunately, CMake has a module called
ExternalProject
that allows a CMake project to wrap project builds involving non-CMake build systems.
Even more fortunately, libbpf’s Makefile follows
GNU Makefile conventions
which give me a stable interface to use when wrapping libbpf’s build with ExternalProject_Add().
CMakeLists.txt also translates the “implicit options” vcpkg passes via
vcpkg_cmake_configure()
to Makefile variables and installation paths.
Brushing off the lint
After my first successful build of libbpf, in vcpkg, I noticed the following warnings in CMake’s output:
...
-- Performing post-build validation
warning: The software license must be available at ${CURRENT_PACKAGES_DIR}/share/libbpf/copyright
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}//IdeaProjects/bpf-iotrace/tools/vcpkg/buildtrees/libbpf//LICENSE")
warning: There should be no absolute paths, such as the following, in an installed package:
/IdeaProjects/bpf-iotrace/tools/vcpkg/packages/libbpf_x64-linux
/IdeaProjects/bpf-iotrace/cmake-build-debug/vcpkg_installed
/IdeaProjects/bpf-iotrace/tools/vcpkg/buildtrees/libbpf
/IdeaProjects/bpf-iotrace/tools/vcpkg/downloads
Absolute paths were found in the following files:
/IdeaProjects/bpf-iotrace/tools/vcpkg/packages/libbpf_x64-linux/debug/lib/pkgconfig/libbpf.pc
/IdeaProjects/bpf-iotrace/tools/vcpkg/packages/libbpf_x64-linux/lib/pkgconfig/libbpf.pc
error: Found 2 post-build check problem(s). To submit these ports to curated catalogs, please first correct the portfile: /IdeaProjects/bpf-iotrace/./tools/vcpkg-overlays/ports/libbpf/portfile.cmake
...
Thankfully, vcpkg provides a pair of functions I can call from portfile.cmake to easily resolve these issues:
- vcpkg_install_copyright()
takes a list of paths to license files and legal notices for the upstream project, and places them in
vcpkg’s preferred location. - vcpkg_fixup_pkgconfig()
transforms any absolute paths in a library’s pkg-config
file to relative paths which are preferred by
vcpkg.
Graduating from the overlay directory
Once a library has been packaged successfully, it can be graduated to a public or private registry to facilitate its use in other projects.
Currently, only an empty .gitignore file exists in bpf-iotrace/tools/vcpkg-overlays/ports to make sure the directory
gets created by git clone ....
However, I will still temporarily copy in
any-port-in-a-storm/ports/libbpf when
I want to test changes or fixes my libbpf vcpkg port.