Why does rpmbuild perf.spec fail

The Linux Kernel git repo has a spec file that builds the Kernel RPM. However, it does not build perf or any of the other userland tools. I want to build a perf RPM using the same code as is used to build the Kernel RPM.

Here are my debugging notes.

When building perf from the command line, one changes to the Linux kernel directory and, after having configured and built the kernel, you can “simply” type make -C tools/perf. It will compile in place. There area few variations of this, such as changing to the directory first, or calling the wrapped makefile in the tools/perf directory, Makefile.perf, to get more control over the build process.

However, merely attempting to do this from a stripped down RPM spec file does not work. Instead, it fails with:

  LINK    /root/rpmbuild/BUILD/linux/tools/perf/util/bpf_skel/.tmp/bootstrap/bpftool
/usr/bin/ld: /root/rpmbuild/BUILD/linux/tools/perf/util/bpf_skel/.tmp/bootstrap/main.o: relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol `stderr@@GLIBC_2.17' which may bind externally can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: /root/rpmbuild/BUILD/linux/tools/perf/util/bpf_skel/.tmp/bootstrap/main.o(.text+0x18): unresolvable R_AARCH64_ADR_PREL_PG_HI21 relocation against symbol `stderr@@GLIBC_2.17'
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status

I have tried various things with setting/remove CFLAGS and, while it changes the error, it is not in a way that moves me closer to a solution. For example, if I set the CFLAGS on the make command line like this:

%{make} CFLAGS="" -C tools/perf  -f Makefile.perf

I get this error


fs/fs.c:20:10: fatal error: debug-internal.h: No such file or directory
   20 | #include "debug-internal.h"
      |          ^~~~~~~~~~~~~~~~~~


The same error occurs if I populate the CFLAGS with the value used by the RPM spec file (reported higher up)

CFLAGS='-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -mbranch-protection=standard -fasynchronous-unwind-tables -fstack-clash-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer '
+ export CFLAGS

Going back to the original error, I notice that it looks like generated code: /root/rpmbuild/BUILD/linux/tools/perf/util/bpf_skel/.tmp/bootstrap/main.o

The skel and .tmp makes me think this is generated from a script. The main.o aspect is also strange, as the main for the whole perf binary should be in linux/tools/perf/perf.c.

There is a whole chain to build Berkeley Packet Filers (bpf) tools and link it in to perf. It appears that this is the part that is failing. The main.o file linked above is build from the main.d file, which is just a list of other files.

Looking inside the log of the build from the Fedora Spec file, (which does produce a binary) I see that we end up with the same errors shown above. I do not know how that version of perf is built, since it appears to fail in the build.

After a lot more trial and error, I came up with the following line, which builds perf successfully. It uses the –static version, which should minimize the number of shared objects it requires.

/usr/bin/make LDFLAGS=-static    CFLAGS=  -s -C tools/perf V=1  VO=1   NO_LIBELF=1   WERROR=0 NO_LIBUNWIND=1 HAVE_CPLUS_DEMANGLE=1 NO_GTK2=1 NO_STRLCPY=1 NO_BIONIC=1 NO_LIBTRACEEVENT=1 NO_CORESIGHT=1 NO_SYSCALL_TABLE=1 NO_LIBDW_DWARF_UNWIND=1 NO_LIBUNWIND=1 NO_DWARF=1 NO_JVMTI=1 NO_ZLIB=1 NO_LIBBPF=1 NO_SDT=1 NO_LOCAL_LIBUNWIND=1 NO_LIBUNWIND=1 NO_LIBAUDIT=1 NO_LIBCRYPTO=1 NO_SLANG=1 NO_GTK2=1 NO_LIBPERL=1 NO_LIBPYTHON=1 NO_JEVENTS=1 NO_LZMA=1 NO_LIBZSTD=1 NO_LIBCAP=1 NO_LIBNUMA=1 NO_AUXTRACE=1 perf

With that building successfully, I can start removing the flags that disable libraries. However, if the library is not installed, it will report the absence and just skip it in the build. In order to have a reproducible build, I need to identify the proper set of packages to include and add them as BuildRequires. I think that, in order to document the decisions, I will also keep any NO_* flags for libraries that we explicitly are not including.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.