Summary
spec-remove-subpackage deletes the entire %package / %description / %files block of the targeted subpackage but does not preserve %define (or %global) macros that live inside that block when they are referenced from sections that survive removal (%install, %build, %check, etc.). The macro is silently dropped, the referencing section keeps the now-undefined %{macro} references, and the build fails far away -- for instance with Installed (but unpackaged) files found: on the payload that the surviving section was supposed to clean up.
Repro
Component: qemu on the 4.0 branch of microsoft/azurelinux.
Upstream qemu.spec (Fedora rawhide, commit f2cb21ff470d94a6dfd2a2e6ef9effeaa3aead1f) defines %{testsdir} inside the %package tests block:
%package tests
Summary: tests for the %{name} package
Requires: %{name} = %{evr}
%define testsdir %{_libdir}/%{name}/tests-src
%description tests
The %{name}-tests rpm contains tests ...
%{testsdir} is then referenced from %install, which is not guarded by any "tests enabled" conditional — the upstream %install unconditionally creates %{buildroot}%{testsdir}/... and copies the test fixtures there:
%install
...
mkdir -p %{buildroot}%{testsdir}/python
mkdir -p %{buildroot}%{testsdir}/tests
mkdir -p %{buildroot}%{testsdir}/tests/qemu-iotests
mkdir -p %{buildroot}%{testsdir}/scripts/qmp
cp -R %{qemu_kvm_build}/python/qemu %{buildroot}%{testsdir}/python
cp -R %{qemu_kvm_build}/scripts/qmp/* %{buildroot}%{testsdir}/scripts/qmp
install -p -m 0755 tests/Makefile.include %{buildroot}%{testsdir}/tests/
...
Apply this overlay:
[[components.qemu.overlays]]
description = "Remove qemu-tests subpackage"
type = "spec-remove-subpackage"
package = "tests"
Render with azldev comp render -p qemu and inspect specs/q/qemu/qemu.spec.
azldev version reproduced against:
azldev version v0.1.1-0.20260521162032-fc8fadad257d
Expected
spec-remove-subpackage detects that %define / %global statements inside the removed subpackage are referenced from sections that survive removal, and preserves them (for example, by hoisting them to just before the removed section).
(The same logic should apply symmetrically to spec-remove-section when targeting a %package section that contains macro definitions referenced elsewhere.)
Actual
%package tests, %description tests, and %files tests are correctly removed — but the %define testsdir line vanishes along with the block. Every %install reference to %{testsdir} survives unchanged. RPM expansion then produces commands like mkdir -p /.../buildroot%{testsdir}/python literally (the unexpanded %{testsdir} token is appended to the buildroot path), so the real /usr/lib/qemu/tests-src/... payload is written under one nonsensical path and any follow-up cleanup overlay trying to rm -rf %{buildroot}%{testsdir} cannot find it. The build trips Installed (but unpackaged) files found: on the leftover payload.
Today this has to be worked around with an explicit spec-search-replace overlay that hoists the %define near the top of the spec, e.g.:
{ description = "Hoist %define testsdir to top of spec",
type = "spec-search-replace",
regex = '^%global enable_werror 0$',
replacement = "%global enable_werror 0\n%define testsdir %{_libdir}/%{name}/tests-src" },
Side note (not part of this bug)
While reproducing the above, spec-remove-section (used for the surrounding audio backends in the same component) was observed to leave empty %if … %endif wrappers around subpackages whose entire body was removed — e.g. %if %{have_dbus_display} followed immediately by %endif after audio-dbus is gone. This is functionally inert (rpmspec -P parses the spec fine and the build succeeds), so it is not a separate bug — just flagging in case the cleanup pass that addresses the %define case can also collapse fully-empty conditional wrappers.
Summary
spec-remove-subpackagedeletes the entire%package/%description/%filesblock of the targeted subpackage but does not preserve%define(or%global) macros that live inside that block when they are referenced from sections that survive removal (%install,%build,%check, etc.). The macro is silently dropped, the referencing section keeps the now-undefined%{macro}references, and the build fails far away -- for instance withInstalled (but unpackaged) files found:on the payload that the surviving section was supposed to clean up.Repro
Component:
qemuon the4.0branch ofmicrosoft/azurelinux.Upstream
qemu.spec(Fedora rawhide, commitf2cb21ff470d94a6dfd2a2e6ef9effeaa3aead1f) defines%{testsdir}inside the%package testsblock:%{testsdir}is then referenced from%install, which is not guarded by any "tests enabled" conditional — the upstream%installunconditionally creates%{buildroot}%{testsdir}/...and copies the test fixtures there:Apply this overlay:
Render with
azldev comp render -p qemuand inspectspecs/q/qemu/qemu.spec.azldevversion reproduced against:Expected
spec-remove-subpackagedetects that%define/%globalstatements inside the removed subpackage are referenced from sections that survive removal, and preserves them (for example, by hoisting them to just before the removed section).(The same logic should apply symmetrically to
spec-remove-sectionwhen targeting a%packagesection that contains macro definitions referenced elsewhere.)Actual
%package tests,%description tests, and%files testsare correctly removed — but the%define testsdirline vanishes along with the block. Every%installreference to%{testsdir}survives unchanged. RPM expansion then produces commands likemkdir -p /.../buildroot%{testsdir}/pythonliterally (the unexpanded%{testsdir}token is appended to the buildroot path), so the real/usr/lib/qemu/tests-src/...payload is written under one nonsensical path and any follow-up cleanup overlay trying torm -rf %{buildroot}%{testsdir}cannot find it. The build tripsInstalled (but unpackaged) files found:on the leftover payload.Today this has to be worked around with an explicit
spec-search-replaceoverlay that hoists the%definenear the top of the spec, e.g.:Side note (not part of this bug)
While reproducing the above,
spec-remove-section(used for the surrounding audio backends in the same component) was observed to leave empty%if … %endifwrappers around subpackages whose entire body was removed — e.g.%if %{have_dbus_display}followed immediately by%endifafteraudio-dbusis gone. This is functionally inert (rpmspec -Pparses the spec fine and the build succeeds), so it is not a separate bug — just flagging in case the cleanup pass that addresses the%definecase can also collapse fully-empty conditional wrappers.