Introducing rpmbuild#

This document’s audience is engineers evaluating rpmbuild as part of their build tooling. As a sample of my work, it’s an important document because it offers an introduction to an open-source project, allowing the project a wider use.

Key concepts#

  • Docker: Linux containers you can run on your existing infrastructure
  • Pants: A build system that manages dependencies across large codebases
  • RPM: Red Hat Package Manager. A way to package software for distribution on a machine
  • RPM spec file: A configuration file for building a specific RPM

What rpmbuild is#

When creating RPMs, it’s important to have a consistent build environment and reproducible builds. It also can be useful to be able to build RPMs in a virtual environment, so you don’t need a dedicated build machine.

rpmbuild bridges the gap between an RPM spec file and a working RPM when you otherwise don’t have a place to build RPMs. It customizes a pants task for this job. This enables you to check an RPM spec file and pants target into git, enabling reproducible builds.

Why use rpmbuild#

rpmbuild is useful because it allows you more operational control over the RPM build process. With git and pants, you can ensure that a specific RPM was built with a specific version of an RPM spec file. You can manage build artifacts in version control. You also don’t need to maintain a build machine on which to build RPMs. Instead, you can use Docker containers to ensure consistent builds.

How rpmbuild works#

rpmbuild defines a pants task for building RPMs given an RPM spec file and references to the file or files used externally. A pants BUILD file makes these references explicit. The task itself wraps Docker, with several default platforms supported.

Example#

For example, this is an rpm spec added to a pants BUILD file:

rpm_spec(
  name='golang',
  spec='golang.spec',
  remote_sources=[
    'https://storage.googleapis.com/golang/go1.7.3.linux-amd64.tar.gz',
  ],
)

This is an RPM spec file that installs golang:

# Disable the debug package (and the associated requirements finding) because RPM gets
# confused by prebuilt Go binaries.
%global debug_package %{nil}

Summary: Go language
Name: golang
Version: 1.7.3
Release: 1%{?dist}
License: GO
Group: Development/Languages
URL: https://golang.org/

BuildRequires: tar

# Disable RPM's standard automatic dependency detection since the Go binaries are static.
AutoReqProv: no

Source: go%{version}.linux-amd64.tar.gz

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

%description
Go is an open source programming language that makes it easy to build simple, reliable,
and efficient software. 

%prep
# Do not do any standard source unpacking (-T) and make work directory (-c).
%setup -c -T

%build
# No build step since we are just moving files into the RPM_BUILD_ROOT.

%install
rm -rf "%{buildroot}"
mkdir -p "%{buildroot}/usr/local"
tar xzvf "${RPM_SOURCE_DIR}/go%{version}.linux-amd64.tar.gz" -C "%{buildroot}/usr/local"

mkdir -p "%{buildroot}/usr/local/bin"
cd "%{buildroot}/usr/local/bin"
for x in go godoc gofmt ; do
  ln -s "../go/bin/$x" .
done

%files
%defattr(-, root, root, -)
/usr/local/go
/usr/local/bin/go
/usr/local/bin/godoc
/usr/local/bin/gofmt