Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMake: Add ability to use system-installed libbpf rather than ExternalProject_Add #225

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

ferdnyc
Copy link

@ferdnyc ferdnyc commented Dec 21, 2023

This PR updates the project's top-level CMakeLists.txt to reduce assumptions about the environment in which the project will be built.

bpftool / libbpf

The use of ExternalProject_Add() to download a copy of the libbpf sources and and incorporate them into the procdump build is now held off as a ''backup'' approach to incorporating libbpf, and only used after first checking for a system-installed libbpf to link with. (This check can be overridden by enabling the option PROCDUMP_DISABLE_SYSTEM_LIBBPF when configuring the project, in which case the libbpf specified by ExternalProject_Add() will always be used, as before.)

Dependency on the bpftool program being available on the system, which was previously hidden inside add_custom_command() scripting, is now formalized, and the location of the tool is discovered using the standard CMake find_package() command.

To support both of these features, a CMake Find module, cmake/FindBpf.cmake, is added to the repo. This module supports discovery of both libbpf and bpftool as package COMPONENTS. If discovery of a local libbpf is not disabled (see above), find_package(Bpf COMPONENTS libbpf) will be called in an attempt to locate a usable libbpf to link with. In all cases, find_package(Bpf COMPONENTS bpftool) is separately called to configure the location of bpftool.

libbpf headers and linking

Due to the way an installed libbpf is meant to be consumed, the project code and ExternalProject_Add configuration for libbpf are slightly adjusted to be compatible.

An installed libbpf will register its include directory as ${prefix}/include (e.g. /usr/include), and expects its header files to be included using #include <bpf/header_name.h>. Because this layout is only created when make install is called in the ExternalProject build, the INSTALL_COMMAND argument has been added. After building libbpf, it will be installed (with DESTDIR set to the external project's binary dir), and the library and include files will be consumed from that installed location rather than directly from the build directory. This gets the header files properly stored in a bpf subdirectory of the include dir. The #include lines for libbpf headers in ebpf/procdump_ebpf.h are adjusted to use the bpf/ path prefix.

Using bpftool

In addition to adding discovery logic for bpftool, the code which makes use of it in the project has been reworked to be more explicit.

Previously, an add_custom_command() call used a long, chained command to compile procdump_ebpf.o and to then generate the procdump.ebpf.o and procdump_ebpf.skel.h files from it using bpftool.

Those commands are now broken up into three add_custom_command() calls, each of which is responsible for generating a single output file. The dependencies between those various custom-command targets are all registered so that CMake will properly order the commands, will consider all of the resulting output files to be GENERATED, and will automatically delete them when the project's clean target is built.

Other dependencies

Other library dependencies of procdump are also discovered using standard CMake find_package() commands, rather than blindly linking library names on the assumption that they'll be present on the system linker paths.

  • libz and pthreads are now discovered using find_package(ZLIB) and find_package(Threads), which will use standard Find modules included in the CMake distribution.
  • libelf is now discovered using find_package(Libelf), which will run the cmake/FindLibelf.cmake Find module added in this PR.

System path discovery

The CMake project() command is now extended with LANGUAGES C CXX arguments defining the project languages. And, the standard CMake GNUInstallDirs module is loaded when configuring the build. Both of these changes are made for the same reason: They activate CMake's ability to automatically detect information about the local system performing the build.

For example, when make install is run in the downloaded libbpf external project, the compiled library will be installed into the standard library path inside the DESTDIR. That path may be $DESTDIR/usr/lib/, it may be $DESTDIR/usr/lib64/, it may be something like $DESTDIR/usr/lib/linux-gnu-x86_64/ or $DESTDIR/usr/lib/linux-gnu-i386/. By using $DESTDIR/usr/${CMAKE_INSTALL_LIBDIR} as the path to the library, those details are handled automatically.

(The same features would make it possible to detect 64-bit and big-endian target processors automatically, to streamline the CLRHOSTDEF detection code that's currently hand-coded in CMakeLists.txt. I may submit a separate PR with those changes.)

Conclusion

I believe these changes make the project's build system more robust and more usable to those who wish to build ProcDump for themselves. The ability to link with an installed libbpf on the system rather than downloading external code, in particular, is a requirement of most Linux packaging standards.

I'm happy to answer questions about any of these changes or to make any modifications needed to meet the project's standards.

- The local cmake/FindBpf.cmake module is used to discover an installed
  libbpf, unless the PROCDUMP_DISABLE_SYSTEM_LIBBPF option is enabled
- If system libbpf is disabled or not found, ExternalProject_Add is
  used to retrieve libbpf sources, build, (NEW: and install into
  PROJECT_BUILD_DIR/libbpf)
- `LANGUAGES C CXX` added to project() command (aids CMake discovery
  of parameters like correct library dir name)
- `GNUInstallDirs` CMake module loaded, defines CMAKE_INCLUDE_DIR
  and CMAKE_LIBRARY_DIR correctly relative to install prefix
The repo's CMake Find module for Bpf includes the ability to discover
the location of the `bpftool` executable and provide an executable
target representing its location. Use that in commands to generate
the various procdump_ebpf files.

Also, split out the steps to generate files using bpftool into
separate add_custom_command() invocations, so that dependencies
between files are tracked and each output file will be automatically
tagged as `GENERATED` by CMake (and deleted by the 'clean' target).
@MarioHewardt
Copy link
Collaborator

Thanks for the contribution, much appreciated. I'll go through the PR in the next few days but as a general feedback, I would prefer the default being to build with statically linked libbpf rather than system provided. We rely on certain capabilities of libbpf that aren't available in early versions of libbpf. When we build for a lowest common dominator such as Ubuntu 20.04 it comes with a system provided libbpf (version 0.5.0 I think) which will not work. Defaulting to statically linked should still work fine as one can override and use system provided.

@jcfaracco
Copy link
Contributor

@MarioHewardt your point is fair. Maybe a solution in between is to provide some way to specify where libbpf is "cached". In my case, for example, the builder does not have internet. So, ProcDump fails to compile because git cannot connect.

@MarioHewardt
Copy link
Collaborator

I think your original approach works great (finding existing libbpf on local system), except just flipping the default to build static instead of system provided. Maybe introduce a flag USE_SYS_PROVIDED (or some such) that if defined will use the system provided approach.

@MarioHewardt
Copy link
Collaborator

Hi @jcfaracco - No rush or anything, just checking in if you've had a chance to tweak the PR to switch the defaults?

@kloczek
Copy link

kloczek commented Apr 8, 2024

I just tested this PR and ..

  • I think that it wold be better to change zlib, libelf and libbpf checking dependencies to use pkgconfig instead use custom detections
  • build for me fails on use bpftool
[ 27%] Generating procdump.ebpf.o
/usr/sbin/bpftool gen object procdump.ebpf.o procdump_ebpf.o
libbpf: failed to find BTF info for object 'procdump_ebpf.o'
Error: failed to link 'procdump_ebpf.o': Invalid argument (22)
make[2]: *** [CMakeFiles/procdump_ebpf.dir/build.make:78: procdump.ebpf.o] Error 234
make[2]: *** Deleting file 'procdump.ebpf.o'
make[2]: Leaving directory '/home/tkloczko/rpmbuild/BUILD/ProcDump-for-Linux-3.2.0/x86_64-redhat-linux-gnu'

Eventually when this PR will be merged please it can close #221

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants