tl;dr The RemovePathPostfixes: rpm tag supports building separate packages with different versions of the same files.

Sometimes it's appropriate to generate multiple alternate packages from an RPM build, which conflict due to containing different versions of the same files. The most likely way to support that would be to allow the %files section for each sub-package to allow selecting a particular build root path. There is an open ticket for that feature, and it has been mooted for a long time.

My particular need for this was to produce a multicall binary (like busybox) version of coreutils, from the standard Fedora coreutils package, which would allow users needing reduced disk space to install the coreutils-single package, rather than the standard coreutils one.

Building multiple versions

In my case the separate builds were configurable with autoconf, so I could use its standard VPATH functionality to run ./configure && make from separate directories, producing separate builds. This is also a useful case to apply autoconf caching functionality, so most configure time tasks are only run once. The %build script used is essentially:
for type in separate single; do
  mkdir $type && \
  (cd $type && ln -s ../configure && \
  test $type = 'single' && configure_single='--enable-single-binary'
  %configure $configure_single \
             --cache-file=../config.cache &&
  make all %{?_smp_mflags})
done

Packaging the separate builds

My initial pass at this, used separate paths in each package, and created symlinks in the %post script of the coreutils-single package, from the standard coreutils binary locations, to the separate stubs. This was a good solution but had the caveat that file provides weren't provided for /usr/bin/ls etc. in the coreutils-single package, since it was using separate paths for those stubs.

Then I was pointed to the new RemovePathPostfixes functionality added in RPM 4.13 which essentially allows renaming files in the build root by stripping suffixes from their names. In my case I would install for example both /usr/bin/ls and /usr/bin/ls.single to the $RPM_BUILD_ROOT, and then when the coreutils-single rpm is being constructed the ".single" suffix would be stripped, leaving the same (conflicting) name used between the packages.

To install ".single" versions alongside the standard utilities in the build root I used this %install script:
for type in separate single; do
  install=install
  if test $type = 'single'; then
    subdir=%{_libexecdir}/%{name}; install=install-exec
  fi
  (cd $type && make DESTDIR=$RPM_BUILD_ROOT/$subdir $install)

  # chroot was in /usr/sbin :
  mkdir -p $RPM_BUILD_ROOT/$subdir/{%{_bindir},%{_sbindir}}
  mv $RPM_BUILD_ROOT/$subdir/{%_bindir,%_sbindir}/chroot

  # Move multicall variants to *.single.
  # RemovePathPostfixes will strip that later.
  if test $type = 'single'; then
    for dir in %{_bindir} %{_sbindir} %{_libexecdir}/%{name}; do
      for bin in $RPM_BUILD_ROOT/%{_libexecdir}/%{name}/$dir/*; do
        basebin=$(basename $bin)
        mv $bin $RPM_BUILD_ROOT/$dir/$basebin.single
      done
    done
  fi
done
Then the %files sections would reference the appropriate files, with rpm applying the auto suffix renaming due to RemovePathPostfixes: .single being set on the coreutils-single sub-package.
%files
%defattr(-,root,root,-)
%exclude %{_bindir}/*.single
%{_bindir}/*
%{_sbindir}/chroot
%{_libexecdir}/coreutils/*.so

%files single
%defattr(-,root,root,-)
%{_bindir}/*.single
%{_sbindir}/chroot.single
%{_libexecdir}/coreutils/*.so.single

Problems

In the setup above the "coreutils-single" and "coreutils" packages have the same dependencies. However if this is not the case you may run into an issue with auto dependency generation in rpm. This is because that generator inspects the file names _after_ the suffix removal phase. I.E. the shared libs etc. detected are from different files in the buildroot than will end up in the rpm.

I was able to work around this issue in my package, by setting %global _use_internal_dependency_generator 0, and in my custom require script, keying on a file specific to the sub-package with RemovePathPostfixes, and adding back the suffixes, before passing to the original %{_rpmconfigdir}/find-requires

Notes

For completeness, I'll describe the resulting changes to the Fedora coreutils package using the above technique and an additional package split.

The original coreutils (14.2MB) is now split to, coreutils (5.5MB), coreutils-single (1.2MB) and an optional coreutils-common (8.7MB)

coreutils and coreutils-single are mutually exclusive. coreutils requires coreutils-common, though it can be forcefully removed if desired, and only docs and translations are degraded. coreutils-single also has reduced dependencies by removing dependencies on libgmp and libcrypto, which as well as reducing disk space, will avoid the startup overhead of all tools associated with dynamically linking these libs.

I.E. there are 4 possible setups now: To illustrate the advantage of open source I was also able to push small improvements to coreutils and rpm related to the above.
© Nov 20 2015