Ladies and gentlemen. Turns out there were a few bugs in the existing rpmbuild packaging pipeline.

On 6th of June, I decided to test out the existing rpmbuild packaging on my freshly installed Fedora 44 system. I cd’d into rtems-deployment directory. I ran ./waf rpmspec to generate spec files from the provided template i.e pkg/rpm.spec.in. Waf successfully generated those in the out/ directory. After generating spec files, I decided to build for the amd/amd-kria-k26 board. The command to build a rpm package from spec file is:

rpmbuild -bb out/amd/amd-kria-k26.spec

The build usually takes around 30 minutes on my hardware so I decided to grab a cup of coffee while my machine was compiling all the different packages.

I returned after a while only to see:

make[4]: Entering directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build/isl/doc'
make[4]: Nothing to be done for 'all'.
make[4]: Leaving directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build/isl/doc'
make[3]: Leaving directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build/isl'
make[2]: Leaving directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build/isl'
make[1]: Leaving directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build'
make: *** [Makefile:1064: all] Error 2
make: Leaving directory '/home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/build'
shell cmd failed: /bin/sh -ex  /home/me/GSOC_Work/rtems-deployment/build/aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1/do-build
error: building aarch64-rtems7-gcc-15.2.0-newlib-a7c61498-x86_64-linux-gnu-1

The build failed for some reason.

I decided to investigate the said log file to find out the reason. I found the main source of error:

../../../gcc-15.2.0/libcpp/expr.cc:882:35: error: format not a string literal and no format arguments [-Werror=format-security]
  882 |             cpp_warning_with_line (pfile, CPP_W_LONG_LONG, virtual_location,
      |             ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  883 |                                    0, message);
      |                                    ~~~~~~~~~~~
../../../gcc-15.2.0/libcpp/expr.cc:885:38: error: format not a string literal and no format arguments [-Werror=format-security]
  885 |             cpp_pedwarning_with_line (pfile, CPP_W_LONG_LONG,
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
  886 |                                       virtual_location, 0, message);
      |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../../gcc-15.2.0/libcpp/expr.cc:896:33: error: format not a string literal and no format arguments [-Werror=format-security]
  896 |           cpp_warning_with_line (pfile, CPP_W_SIZE_T_LITERALS,
      |           ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  897 |                                  virtual_location, 0, message);
      |                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Turns out there were some warnings being treated as errors which in turn failed the whole compilation process.

That was somewhat unexpected to me. During the proposal period I had definitely built the tar archive for this board, and it worked at the time. What could possibly cause it to fail now? I tried building it using waf; like I built it during proposal period. With the command ./waf --target=amd/amd-kria-k26. Again I left it to compile and returned after 30 minutes. A good reading session of “A Knight of Seven Kingdoms” helped a lot :) To my surprise this time it built the archive successfully. That was a bit odd. I tried to extract how rsb was being called both times, arguments it ran with, etc.

I checked the waf log for the command line and I found this:

Command Line: /home/me/Code/RTEMS/src/rsb/source-builder/sb-set-builder --prefix=/opt/rtems/7 \
                --bset-tar-file --trace --log=out/amd/amd-kria-k26.txt \
                --no-install amd/amd-kria-k26

I checked the error log to see the command line and guess what it was the SAME! How could that possibly be right? The same command line yielding two very different results!

My first instinct was to contact my friendly neighbourhood (6700 miles away btw) mentor Chris. After informing him about this anamoly, I created a topic on users forum.

I suspected something was changing the build environment. After Chris confirmed he felt the same, I started to dig more into it.

The first hint was -Werror=format-security. I ran a fuzzy search on the waf build log using the best editor in the world neovim (sorry VSCode). I found no occurrence of it. Something was injecting this flag into build environment to use.

I also tried invoking rsb with same command line from debian rule file as well and it yielded same errors.

Clearly both the build environments were being infected with extraneous build flags.

A quick documentation probing revealed that rpmbuild injects flags via environment variables in the build environment. These flags are set by the distribution, which was Fedora in my case.

Running rpmbuild --eval '%{optflags}' revealed all the default build Optional flags injected by rpmbuild.

-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang
-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  -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables 
-fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer

There it was!

My first instinct was to clear RPM_OPT_FLAGS which resulted into the build process failing with errors related to -fPIE. Clearly clearing just RPM_OPT_FLAGS wasn’t enough. Or maybe I cleared some important flag?

My next step was to just remove the flag affecting the build i.e -Werror=format-security.

I decided to strip it by:

%build
export RPM_OPT_FLAGS=$(echo "$RPM_OPT_FLAGS" | sed -e 's/-Werror=format-security //')

Surely that would solve the issue, right? RIGHT?

No! The compilation did move forward but again was interrupted at another step.

Turns out there was another flag which was causing issues. RPMBuild’s was pushing build flags too hard. RSB first builds the cross compiler which runs on the host machine. The cross compiler then builds programs which would run on the target board. RPMBuild set CC=gcc and CXX=g++ which confused RSB and forced it to use host’s compiler for compiling another architecture’s code with the flags meant for cross-compiled GCC. -march=x86-64 and -mtune=generic were also enabled by rpmbuild.

This lead to the following errors:

cc1: error: unrecognized command-line option ‘-mno-outline-atomics’
cc1: error: unrecognized command-line option ‘-mfix-cortex-a53-835769’
cc1: error: unrecognized command-line option ‘-mfix-cortex-a53-843419’
cc1: error: bad value ‘cortex-a53’ for ‘-mtune=’ switch
cc1: note: valid arguments to ‘-mtune=’ switch are: nocona core2 nehalem corei7 westmere sandybridge corei7-avx ivybridge core-avx-i haswell core-avx2 broadwell skylake skylake-avx512 cannonlake icelake-client rocketlake icelake-server cascadelake tigerlake cooperlake sapphirerapids emeraldrapids alderlake raptorlake meteorlake graniterapids graniterapids-d arrowlake arrowlake-s lunarlake pantherlake diamondrapids wildcatlake novalake bonnell atom silvermont slm goldmont goldmont-plus tremont gracemont sierraforest grandridge clearwaterforest intel x86-64 eden-x2 nano nano-1000 nano-2000 nano-3000 nano-x2 eden-x4 nano-x4 lujiazui yongfeng shijidadao k8 k8-sse3 opteron opteron-sse3 athlon64 athlon64-sse3 athlon-fx amdfam10 barcelona bdver1 bdver2 bdver3 bdver4 znver1 znver2 znver3 znver4 znver5 znver6 btver1 btver2 generic native

The obvious next step was to clear the CC and CXX flags as well. And so I did. However even after doing that some of the code meant for target board’s architecture was being compiled with the march=x86-64 flag.

After consulting with Chris, I tried to unset all the related build environment variables. Chris also suggested reviewing the output of rpmbuild --showrc. This revealed an important macro _auto_set_build_flags. A quick search on internet revealed that this flag control whether or not rpmbuild injects Distro-default build flags into the environment. Combined this with unsetting all the build flags before invoking rsb actually solved the issue.

...
%global _auto_set_build_flags 0
...
%build
unset CC
unset CXX
unset CFLAGS
unset CXXFLAGS
unset CPPFLAGS
unset LDFLAGS
unset RPM_OPT_FLAGS
unset FFLAGS
unset FCFLAGS
unset AR
unset AS
unset LD

# The RSB deployment build command
cd %{rsb_work_path}
%{rsb_set_builder} %{rsb_set_builder_args}
...

This wasn’t the end though. After fixing all the cross-build environment related error, another error occurred.

lto-wrapper: fatal error: write: Disk quota exceeded
compilation terminated.
/usr/bin/ld.bfd: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
make[2]: *** [../../gcc-15.2.0/gcc/cp/Make-lang.in:145: cc1plus] Error 1

Link-time-optimization (lto) defers optimization to linker. When GCC compiles with -flto, it defers optimization to link time. A backend tool called lto-wrapper then analyzes the entire codebase at once and streams several gigabytes of intermediate data to TMPDIR while doing it. On Fedora (and most modern systemd-based distros),

/tmp is mounted on tmpfs which is a RAM-backed filesystem with a kernel-enforced size quota, which in my case was around 6 GB.

❯ quota -s
Disk quotas for user me (uid 1000): 
     Filesystem   space   quota   limit   grace   files   quota   limit   grace
          tmpfs     88K   6275M   6275M               2       0       0        
          tmpfs    888M   6275M   6275M             522       0       0

That quota exists to prevent runaway processes from exhausting host memory.

On some systems though(i.e Debian based) /tmp points to disk-storage.

This issue was easily solved by temporarily changing /tmp dir by modifying TMP, TMPDIR and TEMP variables.

My initial thought was to modify these vars in the spec file itself before calling rsb.

export TMPDIR=%{rsb_work_path}/build/tmp
export TMP=%{rsb_work_path}/build/tmp
export TEMP=%{rsb_work_path}/build/tmp

But Chris suggested this should be left to the host system admin; and warning the users about this potential issue via documentation would suffice.

Regardless of the method, pointing /tmp to disk-storage solved the issue.

The code compiled successfully and it was able to build the tar package and in turn the RPM package. Here is the build log.

RPM Package

Here is the entire users forum thread.