When building RPM packages as a non-root user, creating symlinks in system directories like /usr/bin
presents a common pain point. The error message "Permission denied" occurs because rpmbuild
doesn't have write permissions to these protected paths during the build process.
The key is to create symlinks within your build root ($RPM_BUILD_ROOT
) rather than attempting to modify the live filesystem. Here's the correct way to implement this in your spec file:
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
# Create directory structure in build root
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
# Create symlinks that will be installed to /usr/bin
ln -sf /opt/bupc2.8/bin/upcc ${RPM_BUILD_ROOT}%{_bindir}/upcc
ln -sf /opt/bupc2.8/bin/upcrun ${RPM_BUILD_ROOT}%{_bindir}/upcrun
# Additional symlinks here...
When implementing this solution, keep these technical details in mind:
- Always use RPM macros like
%{_bindir}
rather than hardcoding paths - Ensure your
%files
section includes all created symlinks - The symlinks will be properly created during package installation by root
- Consider using alternatives system for competing commands
Here's how the complete solution integrates with your existing spec file:
%files
%defattr(-,root,root)
/opt/bupc2.8
%config /opt/bupc2.8/etc
# Include all symlinks that should appear in /usr/bin
%{_bindir}/upcc
%{_bindir}/upcc_multi
%{_bindir}/upcc_multi.pl
%{_bindir}/upcdecl
%{_bindir}/upcrun
%{_bindir}/upc_trace
# Include man page symlinks
%{_mandir}/man1/upcc.1
%{_mandir}/man1/upcdecl.1
%{_mandir}/man1/upcrun.1
%{_mandir}/man1/upc_trace.1
After building your RPM, verify the contents using:
rpm -qlp yourpackage.rpm
This should show all your symlinks listed under /usr/bin
, confirming they'll be properly installed.
When building RPM packages as a non-root user, one common hurdle is creating symlinks in system directories like /usr/bin
. The permission denied errors occur because rpmbuild
runs with your user privileges, which typically don't have write access to these protected locations.
The solution lies in properly utilizing $RPM_BUILD_ROOT
during package creation. Here's how your spec file should handle symlinks:
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
# Create directory structure under build root
mkdir -p ${RPM_BUILD_ROOT}%{_bindir}
mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/man1
# Create relative symlinks within build root
ln -sf ../opt/bupc2.8/bin/upcc ${RPM_BUILD_ROOT}%{_bindir}/upcc
ln -sf ../opt/bupc2.8/bin/upcrun ${RPM_BUILD_ROOT}%{_bindir}/upcrun
When implementing symlinks in your RPM:
- Use relative paths (
../opt/...
) rather than absolute paths for better portability - Ensure the target paths exist in your
%files
section - Include both the symlinks and their targets in your package manifest
Here's an improved version of your spec file with proper symlink handling:
%files
%defattr(-,root,root)
/opt/bupc2.8
%{_bindir}/upcc
%{_bindir}/upcrun
# For man pages
%{_mandir}/man1/upcc.1.gz
%{_mandir}/man1/upcrun.1.gz
If you encounter issues:
- Inspect the build root contents:
find $RPM_BUILD_ROOT
- Verify symlink targets exist in the build environment
- Check file permissions in the final RPM with
rpm -qlv yourpackage
For more complex scenarios, you can create symlinks during installation:
%post
ln -sf /opt/bupc2.8/bin/upcc /usr/bin/upcc 2>/dev/null || :
%postun
rm -f /usr/bin/upcc 2>/dev/null || :
Remember this approach requires the package to be installed with root privileges.