“It works on my machine!” – The packager’s nightmare
If you’ve ever packaged an RPM on Fedora, this scenario will definitely feel familiar. You write a .spec file, run rpmbuild, and everything comes out perfectly. However, when you take that .rpm file to a new server or send it to a client, the system constantly reports missing libraries. Worse yet, the package installs but crashes immediately upon running due to version conflicts.
As a dev who has used Fedora as a primary machine for over two years, I understand this trap. A personal machine is often a “battlefield” cluttered with various devel libraries, plugins, and extra build tools. When you build directly on the host machine, rpmbuild automatically “picks up” those available libraries. You forget to declare them in BuildRequires, and the result is a “parasitic” package.
Why is the Local environment always a “traitor”?
The problem lies in Environment Pollution. An operating system used daily is never the standard for packaging for three main reasons.
- Redundant libraries: Dependencies from other projects accidentally satisfy the build conditions of the current package. For example, you might have
openssl-develleft over from an old project, so when you build a new app, it doesn’t error out even if you forgot to list it in the spec. - Configuration junk: Environment variables or config files in /etc have been customized too much by you.
- Overlapping versions: You might be using a specific
glibcversion or a custom library that you don’t even remember installing.
To make a package run everywhere, it needs an absolutely “clean” environment. Only what you explicitly declare should be allowed to exist there.
Comparing environment isolation solutions
Before choosing the right tool, I went through various methods:
- Virtual Machines (VM): Installing a fresh Fedora on VirtualBox every time I build. This is extremely clean but very heavy. Waiting for the OS to boot and setting up the environment takes at least 15-20 minutes each time.
- Containers (Podman/Docker): Significantly faster than a VM. However, managing user permissions, mount points, and simulating different architectures (like building for RHEL on Fedora) is still quite cumbersome.
- Using Mock: This is the gold standard for Fedora maintainers. Mock creates a minimal
chrootenvironment, automatically downloads dependencies, and cleans up everything immediately after finishing.
Mock – The lifesaver for professional Packagers
After 6 months of using Mock to package internal tools, I’ve found it to be the most professional workflow. Mock not only builds cleanly but also supports cross-version builds. You can be using Fedora 40 but still build for Fedora 39 or AlmaLinux 9 with a single command.
1. Quick Installation and Configuration
On Fedora, Mock is available in the official repositories. Just run the following command:
sudo dnf install mock
To use Mock without constantly using sudo, add your user to the mock group:
sudo usermod -a -G mock $USER
newgrp mock
The newgrp command applies the permissions immediately. If it still doesn’t work, simply log out and log back in.
2. Creating a Source RPM (SRPM)
Mock doesn’t build directly from a .spec file. It requires a .src.rpm file as input. Create it using the command:
rpmbuild -bs my-package.spec
This file is usually located in the ~/rpmbuild/SRPMS/ directory.
3. Building with Mock
Now it’s time for Mock to show its power. Suppose you want to build for Fedora 40 on the x86_64 architecture, run:
mock -r fedora-40-x86_64 --rebuild ~/rpmbuild/SRPMS/my-package-1.0-1.fc40.src.rpm
Mock’s automated process includes:
- Creating a new chroot directory and downloading core packages (bash, dnf, coreutils).
- Analyzing the spec file to determine the
BuildRequireslist. - Automatically installing those dependencies into the isolated environment.
- Proceeding to compile, package, and export the finished RPM files.
4. Checking Logs and Debugging
The build results will be located at /var/lib/mock/fedora-40-x86_64/result/. You should pay attention to two important log files:
- build.log: Where the compilation process is recorded. If there’s a code error, check here.
- root.log: Records the dependency installation process. If Mock cannot find a library you requested, this file will tell you why.
Optimization Tip: Triple Your Build Speed
The downside of Mock is the time spent downloading packages and extracting the chroot. To overcome this, I always use tmpfs to build in RAM instead of the hard drive. This helps reduce the build time for an average package from 5 minutes to less than 2 minutes.
Use the following flag to enable tmpfs:
mock -r fedora-40-x86_64 --plugin-option=tmpfs:max_size=4G --rebuild my-package.src.rpm
Additionally, if you frequently build for other distros like CentOS Stream or RHEL (via EPEL), Mock provides excellent support. Just change the value after the -r flag (e.g., epel-9-x86_64), and you have a standard RHEL environment right on your Fedora machine.
Conclusion
Using Mock is not just about following standards; it’s about protecting yourself. It helps you completely eliminate silly errors caused by your personal environment. If you plan to submit applications to COPR or contribute to the Fedora software repositories, Mock is an essential skill. Don’t let your local environment deceive you ever again!

