RPM Spec Conditional Include Files In RPM

In software field, whoever develops an application with Linux as its base OS will be familiar with RPM and RPM spec. In the modern growing world, it is seen that MNC's support their software products in multiple platforms. Since the code may be platform dependent, engineers are trying to create a common code base to remove the overhead of maintaining two code which is doing almost same operation. Similarly I was looking a way to create a common rpm spec file but with conditional inclusion of files in the rpm, which means, One rpm spec will create rpms but the content of the rpm varies.
To Quote an example, I was having some file which are common in both CNF and VNF, while some other files are only required in either one. So the tedious way was to maintain two spec file with some common code between these two spec. Easy way was to add conditional macro in single spec file.

Pre-Requisite

Basic Knowledge on RPM spec and RPM-build environment

Spec File with Conditional Macro

Approach 1

  • A dummy spec file is created which will package three files from my own private git repo
  • My aim is to deliver either pam or openssl related files to the rpm based on a condition, whereas i want to deliver Readme.md in both cases
  • Below code snippet shows the same.(Step by Step Explanation is given here)
%define ROOT_DIR /root/babugeet

Summary: Linux Data Hub Example Source codes
Name: linux-data-hub
Version: 01
Release: 2022

License: Linux Data Hub
Group: Applications/LDH
URL: https://github.com/babugeet

Vendor : LDH
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}
%prep

%build


%install
rm -rf %{buildroot}

mkdir -p %{buildroot}/opt/pam

# in builddir
%if %{mode} == "openssl"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server
%endif

%if %{mode} == "pam"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam
cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam
%endif

mkdir -p %{buildroot}/opt
cp -a %{ROOT_DIR}/Readme.md /opt/
%post

%clean
rm -rf %{buildroot}

%files
%defattr(500,root,root,-)
/opt/Readme.md
%if %{mode} == "openssl"
%attr(500,root,root) /opt/openssl_server/web-server.js
%attr(500,root,root) /opt/openssl_server/nds_2ca.pcap
%endif
%if %{mode} == "pam"
%attr(500,root,root) /opt/pam/basic_pam.c
%attr(500,root,root) /opt/pam/simple_pam.c
%endif

RPM Build and Verification for Approach1

  • Below code snippet shows the rpm build command. It can be seen that, we are passing the key value pair using the argument --define
[root@n-server babugeet]# rpmbuild --ba Linux/rpm/rpm_condit.spec --define="mode openssl"
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.tLGbEh
+ umask 022
<trimmed>
Processing files: linux-data-hub-01-2022.noarch
Provides: linux-data-hub = 01-2022
Requires(interp): /bin/sh
+ cd /root/rpmbuild/BUILD
+ rm -rf /root/rpmbuild/BUILDROOT/linux-data-hub-01-2022.x86_64
+ exit 0
  • Below snippet shows the verification of the files packaged in the rpm. Since we have given openssl as the value, it can be seen that only openssl files and one common (Read me) file got packaged and not the pam files
[root@n-server babugeet]# rpm -qlp /root/rpmbuild/RPMS/noarch/linux-data-hub-01-2022.noarch.rpm 
/opt/Readme.md
/opt/openssl_server/nds_2ca.pcap
/opt/openssl_server/web-server.js
  • Similarly if we use pam as the value in the argument --define, files present under the pam conditional macro, along with the Readme.md file will be packaged

Step By Step Explanation for Approach1

  • In the %install section, we are using Conditional Macro "if", where we are verifying for a key value pair
  • In our example, key is mode and the value can be either openssl or pam
  • we are copying the files to the build root path based on the condition
%if %{mode} == "openssl"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server
%endif

%if %{mode} == "pam"
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam
cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam
%endif
  • Similary in the %files section, we are using Conditional If to package it in the rpm
%files
%defattr(500,root,root,-)
/opt/Readme.md
%if %{mode} == "openssl"
%attr(500,root,root) /opt/openssl_server/web-server.js
%attr(500,root,root) /opt/openssl_server/nds_2ca.pcap
%endif
%if %{mode} == "pam"
%attr(500,root,root) /opt/pam/basic_pam.c
%attr(500,root,root) /opt/pam/simple_pam.c
%endif

Approach 2

  • Our Requirement is to create conditional file delivery to spec, based on another conditoinal check in the build enviornemnt
  • In Approach1, we passed the condition via rpm build argument --define
  • In Approach2, we will be checking if there is an empty file called openssl or pam in /tmp, based on that files will be packaged
  • Below shows the spec file
%define ROOT_DIR /root/babugeet

Summary: Linux Data Hub Example Source codes
Name: linux-data-hub
Version: 01
Release: 2022


License: Linux Data Hub
Group: Applications/LDH
URL: https://github.com/babugeet

Vendor : LDH
BuildArch: noarch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}
%prep

%build
%define pam %( if [ -f /tmp/pam ]; then echo "1" ; else echo "0"; fi )
%define openssl %( if [ -f /tmp/openssl ]; then echo "1" ; else echo "0"; fi )


%install
rm -rf %{buildroot}


# in builddir
%if %openssl
mkdir -p %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/web-server.js %{buildroot}/opt/openssl_server
cp -a %{ROOT_DIR}/openssl/server/nds_2ca.pcap %{buildroot}/opt/openssl_server
%endif

%if %pam
mkdir -p %{buildroot}/opt/pam
cp -a %{ROOT_DIR}/pam_tutorials/basic_pam.c %{buildroot}/opt/pam
cp -a %{ROOT_DIR}/pam_tutorials/simple_pam.c %{buildroot}/opt/pam
%endif

mkdir -p %{buildroot}/opt/
cp -a %{ROOT_DIR}/Readme.md %{buildroot}/opt

%post


%clean
rm -rf %{buildroot}


%files
%defattr(500,root,root,-)
/opt/Readme.md
%if %openssl
%attr(500,root,root) /opt/openssl_server/web-server.js
%attr(500,root,root) /opt/openssl_server/nds_2ca.pcap
%endif
%if %pam
%attr(500,root,root) /opt/pam/basic_pam.c
%attr(500,root,root) /opt/pam/simple_pam.c
%endif

Explanation for Approach 2

  • From the above spec file, it is self explained that we are defining a variable based on the file availability  on the build environment  under %build section
  • We are doing conditional check on the variables which are defined, based on that rpm build will package the files

RPM Build and Verification for Approach2

  • An empty file /tmp/pam is present in the build machine
  • Below code snippet shows, since only /tmp/pam file was present, only the pam related file along with the common Readme.md file got packaged
[root@n-server babugeet]# ls -l /tmp/pam
-rw-r--r--. 1 root root 0 Nov 1 12:07 /tmp/pam
[root@n-server babugeet]# rpmbuild --ba Linux/rpm/rpm_conditional_.spec 
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.69jzPK
+ umask 022
+ cd /root/rpmbuild/BUILD
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.ao04dk
+ umask 022
+ cd /root/rpmbuild/BUILD
+ exit 0
Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.3Ui7DT
+ umask 022
<trimmed>
+ cd /root/rpmbuild/BUILD
+ rm -rf /root/rpmbuild/BUILDROOT/linux-data-hub-01-2022.x86_64
+ exit 0
[root@n-server babugeet]# rpm -qlp /root/rpmbuild/RPMS/noarch/linux-data-hub-01-2022.noarch.rpm 
/opt/Readme.md
/opt/pam/basic_pam.c
/opt/pam/simple_pam.c

Search on LinuxDataHub

Leave a Comment