How to Implement “Package A OR Package B” Dependencies in RPM Spec Files


1 views

When building RPM packages, we often encounter situations where our software needs either PackageA or PackageB to function, but not necessarily both. The RPM packaging system doesn't natively support this "OR" dependency syntax in spec files, which creates interesting technical challenges.

The standard RPM spec file uses simple dependency declarations:

Requires: package-a
Requires: package-b

This creates an AND relationship where both packages must be installed. What we need is a way to express:

Requires: package-a >= 1.0 OR package-b >= 2.0

Option 1: Virtual Packages (Preferred when possible)

# In package-a.spec:
Provides: virtual-feature = %{version}

# In package-b.spec: 
Provides: virtual-feature = %{version}

# In your package.spec:
Requires: virtual-feature

Option 2: Conditional Requires (Using %if)

%if 0%{?rhel} >= 7
Requires: package-a
%else
Requires: package-b
%endif

When you don't control both packages, a runtime check in %pre might be necessary:

%pre
if ! rpm -q --quiet package-a && ! rpm -q --quiet package-b; then
    echo "Error: Either package-a or package-b must be installed" >&2
    exit 1
fi

For maintaining proper dependency tracking while still allowing flexibility:

%post
if rpm -q --quiet package-a; then
    rpm --setdeps --requires package-a
elif rpm -q --quiet package-b; then
    rpm --setdeps --requires package-b
fi

Here's how you might handle alternative graphics backends:

# In your package.spec
Requires: mesa-libGLU | nvidia-libGLU

%pre
if ! rpm -q --quiet mesa-libGLU && ! rpm -q --quiet nvidia-libGLU; then
    echo "Either mesa-libGLU or nvidia-libGLU required" >&2
    exit 1
fi
  • Always document your OR dependencies in package descriptions
  • Consider creating a meta-package that pulls in one of the alternatives
  • Test both dependency paths thoroughly
  • Be aware of potential version conflicts between alternatives

When building RPM packages, we often encounter situations where our software can work with multiple alternative dependencies, but the standard RPM spec syntax doesn't provide a native way to express "this OR that" dependencies. This limitation forces package maintainers to make suboptimal choices between:

  • Requiring one specific package (potentially excluding valid alternatives)
  • Circumventing RPM's dependency system with manual checks
  • Creating artificial virtual packages

The RPM packaging system provides several dependency directives:

Requires: package
Recommends: package
Suggests: package
Conflicts: package

However, it lacks Boolean operators (OR, AND, NOT) in dependency specifications. The closest native alternative is using virtual provides:

# In foo-bar.spec
Provides: virtual-foobar = %{version}

# In bar-foo.spec 
Provides: virtual-foobar = %{version}

# In your package
Requires: virtual-foobar

Option 1: Runtime Detection in %pre Script

This approach validates dependencies during installation but doesn't register them in RPM's database:

%pre
if ! rpm -q --quiet foo-bar && ! rpm -q --quiet bar-foo; then
    echo "Error: Either foo-bar or bar-foo must be installed" >&2
    exit 1
fi

Option 2: Weak Dependencies with Recommends

For newer RPM versions (4.13+) supporting weak dependencies:

Recommends: foo-bar
Recommends: bar-foo

Option 3: Virtual Package with Fallback

When you control one of the packages:

# In bar-foo.spec
Provides: foobar-compatibility = %{version}

# In your.spec
Requires: foobar-compatibility

For complex scenarios, you can modify RPM's database in %post (use with caution):

%post
if rpm -q --quiet foo-bar; then
    rpm --setdeps --requires "foo-bar" %{name}-%{version}-%{release}
elif rpm -q --quiet bar-foo; then
    rpm --setdeps --requires "bar-foo" %{name}-%{version}-%{release}
fi

After extensive testing across various distributions, I recommend:

  1. Prefer virtual packages when possible
  2. Use runtime checks only as last resort
  3. Document alternative dependencies clearly in package descriptions
  4. Consider creating a compatibility meta-package if you control the ecosystem

For critical systems, the safest approach remains requiring a specific default package while supporting alternatives at runtime through configuration files or environment variables.