How to create a Linux RPM package?

Hi, I follow this article : https://www.redhat.com/sysadmin/create-rpm-package

I have the source file and necessary files. I have the developer environment , necessary tools are available.
Is there anything that I miss ? Why can’t I compile a simple .c file if I have every details ?
How do you do guys ? Thank you for your help in advance.

The reason why I cannot attach details about unsuccessful compile because the computer doesn’t have network card , I’ve just inserted an USB NIC but rt2x00 module doesn’t work.

That’s why I would like to compile the driver.

This is the source : linux/drivers/net/wireless/ralink/rt2x00 at master · torvalds/linux · GitHub

I would like to build an .rpm package from rt73usb.c
Kernel Headers and external header files are available.

I don’t know why it doesn’t work.

I would encourage viewing the following pages:

https://rpm-packaging-guide.github.io/
https://docs.fedoraproject.org/en-US/packaging-guidelines/

Copying a source code file is not enough. You will need to compile it in the spec file with the correct build requirements and correct commands/macros. As we do not see your spec file, it’s hard for us to guess what you have attempted.

If you continue to have issues, you can potentially request a driver built at My View - ELRepo Bugs

1 Like

I try to attach the .spec file and outcome of the build from stdout .

build.log

Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.VxlTqR
+ umask 022
+ cd /home/user/rpmbuild/BUILD
+ cd /home/user/rpmbuild/BUILD
+ rm -rf rt73usb-0.0.1
+ /usr/bin/tar -xof /home/user/rpmbuild/SOURCES/rt73usb-0.0.1.tar.gz
+ cd rt73usb-0.0.1
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ echo 'override rt73usb * weak-updates/rt73usb'
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.ef38CT
+ umask 022
+ cd /home/user/rpmbuild/BUILD
+ cd rt73usb-0.0.1
+ /usr/bin/make -C /usr/src/kernels/4.18.0-372.9.1.el8.x86_64 modules M=/home/user/rpmbuild/BUILD/rt73usb-0.0.1
make: Entering directory '/usr/src/kernels/4.18.0-372.9.1.el8.x86_64'
  CC [M]  /home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.o
/home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.c:2306:22: error: initialization of 'void (*)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, u32)' {aka 'void (*)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, unsigned int)'} from incompatible pointer type 'void (*)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, u64)' {aka 'void (*)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, long long unsigned int)'} [-Werror=incompatible-pointer-types]
  .bss_info_changed = rt2x00mac_bss_info_changed,
                      ^~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.c:2306:22: note: (near initialization for 'rt73usb_mac80211_ops.bss_info_changed')
/home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.c:2307:14: error: initialization of 'int (*)(struct ieee80211_hw *, struct ieee80211_vif *, u16,  const struct ieee80211_tx_queue_params *)' {aka 'int (*)(struct ieee80211_hw *, struct ieee80211_vif *, short unsigned int,  const struct ieee80211_tx_queue_params *)'} from incompatible pointer type 'int (*)(struct ieee80211_hw *, struct ieee80211_vif *, unsigned int,  u16,  const struct ieee80211_tx_queue_params *)' {aka 'int (*)(struct ieee80211_hw *, struct ieee80211_vif *, unsigned int,  short unsigned int,  const struct ieee80211_tx_queue_params *)'} [-Werror=incompatible-pointer-types]
  .conf_tx  = rt73usb_conf_tx,
              ^~~~~~~~~~~~~~~
/home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.c:2307:14: note: (near initialization for 'rt73usb_mac80211_ops.conf_tx')
cc1: some warnings being treated as errors
make[1]: *** [scripts/Makefile.build:322: /home/user/rpmbuild/BUILD/rt73usb-0.0.1/rt73usb.o] Error 1
make: *** [Makefile:1577: _module_/home/user/rpmbuild/BUILD/rt73usb-0.0.1] Error 2
make: Leaving directory '/usr/src/kernels/4.18.0-372.9.1.el8.x86_64'
error: Bad exit status from /var/tmp/rpm-tmp.ef38CT (%build)


RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.ef38CT (%build)

rt73usb.spec

# Define the kmod package name here.
%define kmod_name		rt73usb

# If kmod_kernel_version isn't defined on the rpmbuild line, define it here.
%{!?kmod_kernel_version: %define kmod_kernel_version 4.18.0-372.9.1.el8}

%{!?dist: %define dist .el8}

Name:		kmod-%{kmod_name}
Version:	0.0.1
Release:	1%{?dist}
Summary:	%{kmod_name} kernel module(s)
Group:		System Environment/Kernel
License:	GPLv2
URL:		http://www.kernel.org/
BuildArch:	x86_64
# Sources
Source0:	%{kmod_name}-%{version}.tar.gz
Source5:	GPL-v2.0.txt

# Fix for the SB-signing issue caused by a bug in /usr/lib/rpm/brp-strip
# https://bugzilla.redhat.com/show_bug.cgi?id=1967291

%define __spec_install_post	/usr/lib/rpm/check-buildroot \
				/usr/lib/rpm/redhat/brp-ldconfig \
				/usr/lib/rpm/brp-compress \
				/usr/lib/rpm/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump \
				/usr/lib/rpm/brp-strip-static-archive /usr/bin/strip \
				/usr/lib/rpm/brp-python-bytecompile "" 1 \
				/usr/lib/rpm/brp-python-hardlink \
				PYTHON3="/usr/libexec/platform-python" /usr/lib/rpm/redhat/brp-mangle-shebangs

# Source code patches

%define findpat %( echo "%""P" )
%define __find_requires /usr/lib/rpm/redhat/find-requires.ksyms
%define __find_provides /usr/lib/rpm/redhat/find-provides.ksyms %{kmod_name} %{?epoch:%{epoch}:}%{version}-%{release}
%define dup_state_dir %{_localstatedir}/lib/rpm-state/kmod-dups
%define kver_state_dir %{dup_state_dir}/kver
%define kver_state_file %{kver_state_dir}/%{kmod_kernel_version}.%{_arch}
%define dup_module_list %{dup_state_dir}/rpm-kmod-%{kmod_name}-modules
%define debug_package %{nil}

%global _use_internal_dependency_generator 0
%global kernel_source() %{_usrsrc}/kernels/%{kmod_kernel_version}.%{_arch}

BuildRoot:	%(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)

ExclusiveArch:	x86_64

BuildRequires:	elfutils-libelf-devel
BuildRequires:	kernel-devel = %{kmod_kernel_version}
BuildRequires:	kernel-abi-whitelists
BuildRequires:	kernel-rpm-macros
BuildRequires:	redhat-rpm-config

Provides:	kernel-modules >= %{kmod_kernel_version}.%{_arch}
Provides:	kmod-%{kmod_name} = %{?epoch:%{epoch}:}%{version}-%{release}

Requires(post):	%{_sbindir}/weak-modules
Requires(postun):	%{_sbindir}/weak-modules
Requires:	kernel >= %{kmod_kernel_version}

%description
This package provides the %{kmod_name} kernel module(s).
It is built to depend upon the specific ABI provided by a range of releases
of the same variant of the Linux kernel and not on any one specific build.

%prep
%setup -q -n %{kmod_name}-%{version}
echo "override %{kmod_name} * weak-updates/%{kmod_name}" > kmod-%{kmod_name}.conf

# Apply patch(es)
# % patch0 -p1

%build
%{__make} -C %{kernel_source} %{?_smp_mflags} modules M=$PWD

whitelist="/lib/modules/kabi-current/kabi_whitelist_%{_target_cpu}"
for modules in $( find . -name "*.ko" -type f -printf "%{findpat}\n" | sed 's|\.ko$||' | sort -u ) ; do
	# update greylist
	nm -u ./$modules.ko | sed 's/.*U //' |  sed 's/^\.//' | sort -u | while read -r symbol; do
		grep -q "^\s*$symbol\$" $whitelist || echo "$symbol" >> ./greylist
	done
done
sort -u greylist | uniq > greylist.txt

%install
%{__install} -d %{buildroot}/lib/modules/%{kmod_kernel_version}.%{_arch}/extra/%{kmod_name}/
%{__install} %{kmod_name}.ko %{buildroot}/lib/modules/%{kmod_kernel_version}.%{_arch}/extra/%{kmod_name}/
%{__install} -d %{buildroot}%{_sysconfdir}/depmod.d/
%{__install} -m 0644 kmod-%{kmod_name}.conf %{buildroot}%{_sysconfdir}/depmod.d/
%{__install} -d %{buildroot}%{_defaultdocdir}/kmod-%{kmod_name}-%{version}/
%{__install} -m 0644 %{SOURCE5} %{buildroot}%{_defaultdocdir}/kmod-%{kmod_name}-%{version}/
%{__install} -m 0644 greylist.txt %{buildroot}%{_defaultdocdir}/kmod-%{kmod_name}-%{version}/

# strip the modules(s)
find %{buildroot} -name \*.ko -type f | xargs --no-run-if-empty %{__strip} --strip-debug

# Sign the modules(s)
%if %{?_with_modsign:1}%{!?_with_modsign:0}
# If the module signing keys are not defined, define them here.
%{!?privkey: %define privkey %{_sysconfdir}/pki/SECURE-BOOT-KEY.priv}
%{!?pubkey: %define pubkey %{_sysconfdir}/pki/SECURE-BOOT-KEY.der}
for module in $(find %{buildroot} -type f -name \*.ko);
do %{_usrsrc}/kernels/%{kmod_kernel_version}.%{_arch}/scripts/sign-file \
sha256 %{privkey} %{pubkey} $module;
done
%endif

%clean
%{__rm} -rf %{buildroot}

%post
modules=( $(find /lib/modules/%{kmod_kernel_version}.x86_64/extra/%{kmod_name} | grep '\.ko$') )
printf '%s\n' "${modules[@]}" | %{_sbindir}/weak-modules --add-modules --no-initramfs

mkdir -p "%{kver_state_dir}"
touch "%{kver_state_file}"

exit 0

%posttrans
# We have to re-implement part of weak-modules here because it doesn't allow
# calling initramfs regeneration separately
if [ -f "%{kver_state_file}" ]; then
	kver_base="%{kmod_kernel_version}"
	kvers=$(ls -d "/lib/modules/${kver_base%%.*}"*)

	for k_dir in $kvers; do
		k="${k_dir#/lib/modules/}"

		tmp_initramfs="/boot/initramfs-$k.tmp"
		dst_initramfs="/boot/initramfs-$k.img"

		# The same check as in weak-modules: we assume that the kernel present
		# if the symvers file exists.
		if [ -e "$k_dir/symvers.gz" ]; then
			/usr/bin/dracut -f "$tmp_initramfs" "$k" || exit 1
			cmp -s "$tmp_initramfs" "$dst_initramfs"
			if [ "$?" = 1 ]; then
				mv "$tmp_initramfs" "$dst_initramfs"
			else
				rm -f "$tmp_initramfs"
			fi
		fi
	done

	rm -f "%{kver_state_file}"
	rmdir "%{kver_state_dir}" 2> /dev/null
fi

rmdir "%{dup_state_dir}" 2> /dev/null

exit 0

%preun
if rpm -q --filetriggers kmod 2> /dev/null| grep -q "Trigger for weak-modules call on kmod removal"; then
	mkdir -p "%{kver_state_dir}"
	touch "%{kver_state_file}"
fi

mkdir -p "%{dup_state_dir}"
rpm -ql kmod-%{kmod_name}-%{version}-%{release}.%{_arch} | grep '\.ko$' > "%{dup_module_list}"

%postun
if rpm -q --filetriggers kmod 2> /dev/null| grep -q "Trigger for weak-modules call on kmod removal"; then
	initramfs_opt="--no-initramfs"
else
	initramfs_opt=""
fi

modules=( $(cat "%{dup_module_list}") )
rm -f "%{dup_module_list}"
printf '%s\n' "${modules[@]}" | %{_sbindir}/weak-modules --remove-modules $initramfs_opt

rmdir "%{dup_state_dir}" 2> /dev/null

exit 0

%files
%defattr(644,root,root,755)
/lib/modules/%{kmod_kernel_version}.%{_arch}/
%config /etc/depmod.d/kmod-%{kmod_name}.conf
%doc /usr/share/doc/kmod-%{kmod_name}-%{version}/

%changelog
* Wed Oct 12 2022 0.0-1
- Initial el8 build of the kmod package.
- Source code from RHEL 8.6 kernel

Photo about the current state:

Instead of Linus’ source tree, get the source from RHEL/Rocky’s kernel and try building from there. I think it will succeed.

Thank you again for your help. Before I start to browse the net explain me one thing please .
If I enter the make menuconfig I can find the necessary modul in my current kernel (4.18.0-…)

ralink-kernel

Why I cannot find it the source of the modul ? How it is possible than the kernel is able to compile it ?
I don’t get it. Thank you for your answer.

Ok. Great. I understand.
I simple downloaded this .src and got the source of the my kernel : http://mirror.szerverem.hu/rocky/8.6/BaseOS/source/tree/Packages/k/kernel-4.18.0-372.9.1.el8.src.rpm

After rpm2cpio I was able to browse the files. I have found the source of the NIC and you were right (again) build was successful by using the certain sources.

Thank y’all for your kind help. :clap:t3:

A shortcut here, instead of rpm2cpio, install the src.rpm: rpm -Uvh kernel-4.18.0-372.9.1.el8.src.rpm and this will extract the contents of the RPM to ~/rpmbuild/SOURCES and ~/rpmbuild/SPECS/

1 Like