See my working application (and additional notes) here:
https://github.com/integralist/simple-rpm
Other information that led to the above repository, can be found below
- http://www.rpm.org/max-rpm/s1-rpm-anywhere-different-build-area.html
- http://www.tldp.org/HOWTO/RPM-HOWTO/build.html
- https://fedoraproject.org/wiki/How_to_create_an_RPM_package
- http://www.thegeekstuff.com/2015/02/rpm-build-package-example/
- https://github.com/darnould/simple-rpm
Macro Name | Name | Location | Purpose |
---|---|---|---|
%_specdir |
Specification directory | ~/rpmbuild/SPECS |
RPM specifications (.spec ) files |
%_sourcedir |
Source directory | ~/rpmbuild/SOURCES |
Pristine source package (e.g. tarballs) and patches |
%_builddir |
Build directory | ~/rpmbuild/BUILD |
Source files are unpacked and compiled in a subdirectory underneath this. |
%_buildrootdir |
Build root directory | ~/rpmbuild/BUILDROOT |
Files are installed under here during the %install stage. |
%_rpmdir |
Binary RPM directory | ~/rpmbuild/RPMS |
Binary RPMs are created and stored under here. |
%_srcrpmdir |
Source RPM directory | ~/rpmbuild/SRPMS |
Source RPMs are created and stored here. |
mkdir -p ~/rpmbuild/{RPMS,SRPMS,BUILD,SOURCES,SPECS,tmp}
cat <<EOF >~/.rpmmacros
%_topdir %(echo $HOME)/rpmbuild
%_tmppath %{_topdir}/tmp
EOF
cd ~/rpmbuild
mkdir foo-1.0
mkdir -p foo-1.0/usr/bin
mkdir -p foo-1.0/etc/foo
install -m 755 foo foo-1.0/usr/bin
install -m 644 foo.conf foo-1.0/etc/foo/
tar -zcvf foo-1.0.tar.gz foo-1.0/
cp foo-1.0.tar.gz SOURCES/
cat <<EOF > SPECS/foo.spec
# Don't try fancy stuff like debuginfo, which is useless on binary-only
# packages. Don't strip binary too
# Be sure buildpolicy set to do nothing
%define __spec_install_post %{nil}
%define debug_package %{nil}
%define __os_install_post %{_dbpath}/brp-compress
Summary: A very simple toy bin rpm package
Name: foo
Version: 1.0
Release: 1
License: GPL+
Group: Development/Tools
SOURCE0 : %{name}-%{version}.tar.gz
URL: http://foo.company.com/
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
%{summary}
%prep
%setup -q
%build
# Empty section.
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}
# in builddir
cp -a * %{buildroot}
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
%config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf
%{_bindir}/*
%changelog
* Thu Apr 24 2009 Elia Pinto <[email protected]> 1.0-1
- First Build
EOF
rpmbuild -ba SPECS/foo.spec
Simple example of what the directory structure looks like and means in practice...
.
├── BUILD
├── RPMS
├── SOURCES
│ ├── http://cache.ruby-lang.org/pub/ruby/ruby-2.1.2.tar.gz
├── SPECS
│ ├── ruby.spec
├── SRPMS
The BUILD folder is where all files go which are created during a build of the package when you create the rpm.
If the package builds correctly then any rpm(s) created will go into the RPMS and SRPMS folders.
The SRPMS directory only contains source rpms.
Spec files are basically instructions on how the rpm is built and they go in the SPECS folder.
The source tar file should go into the SOURCES directory along with any patches.
- Spec file naming convention:
<package_name>-<version_number>-<release_number>.spec
- Spec files reference SOURCEs as
Source0
,Source1
- Spec file uses
%{variable_name}
to dereference values- Variables are case insensitive; e.g.
%{foo}
matchesFoo
variable
- Variables are case insensitive; e.g.
Here are some BBC Cosmos notes on the subject...
RPM
.spec
files provide a lot of power and flexibility but much of this is unnecessary when you're just trying to deploy code to a cloud instance. The documentation below covers a small subset of the features you're likely to need to achieve this.If you're already comfortable writing
.spec
files some of the advice may seem strange. If you want to write good, idiomatic.spec
files for submission to something like the Fedora project or EPEL then this is the wrong guide; otherwise, read on.Basic .spec template
Name
The name of your component. For simplicity it should start and end with a letter or number, and only contain letters, numbers, and dashes.
Version
You can use a plain version number such as
1.2.3
, or you can use RPM macros to partially or completely define the version at build time. The following examples assume you have defined abuildnum
macro with a unique, increasing number, eg by passing something like--define "%buildnum ..."
to the build command.Manually defined version, with an optional build number
Here the version is manually specified (
1.2.3
) and when an optionalbuildnum
macro is defined it will be added to the end following a.
character, eg1.2.3.99
.Automatically defined version, with a manual fallback
Here the version will be the value of the buildnum macro when it is defined, or
0.0.0
when it isn't – perhaps because the build is being tested locally.Requires
Use
Requires: ...
lines to list the packages that need to be installed alongside yours.You can specify multiple requirements on a single line using comma separators, but using a new line for each requirement will produce clearer diffs when it comes to reviewing changes.
In most cases you can just list the names of the
But if you have specific version requirements that may not be met if the wrong repositories have been configured you can add some constraints, eg:
The only supported operators are
>
,>=
,<=
,<
, and=
, and there's no special handling for a requirement like0.10.X
. If needed, this can be simulated with multiple requirements on the same package:Source0
You will typically pass in the files to be packaged via a
.tar.gz
file. The actual filename is irrelevant, but it must exist under theSOURCES/
directory, and everything in the archive should be under one top-level directory. For example, do this:Rather than this:
In the first case everything in the archive will be under a
src/
directory, and in the second there may be multiple files and directories at the top-level.%prep
The
%prep
section unpacks the file named inSource0
using the special%setup
macro. The -n argument provides the name of the top-level directory, so adjustsrc/
as appropriate.The
%build
and%install
sections will start off inside that top-level directory.%install
The
%install
section should be a series of shell commands to populate the temporary%{buildroot}
directory. The goal here is install your unpacked code under%{buildroot}
as if it were the actual root of the filesystem on the target machine.For example, imagine you have a configuration file that should end up under
/etc/myapp/
and a script that should end up under/usr/bin/
. Assuming that both are next to each other in your unpacked source, you might do the following:Note that you should always start by wiping out
%{buildroot}
to ensure you're not accidentally layering your files on top of some existing state.An alternative approach would be to prepare the filesystem structure ahead of time in your source
.tar.gz
file, and then simply copy it all into place in one go, eg:%files
The
%files
section is a list of paths under%{buildroot}
(which you populated in the%install
step) that your package should own, plus information on the user, group, and permissions. You can use simple*
wildcards to match multiple paths at a time.For example, if you've created
%{buildroot}/usr/bin/myscript
you'll want your package to own themyscript
file, but not the parent/usr
or/usr/bin
directories. And if you've created%{buildroot}/etc/myapp/global.conf
you'll want your package to own/etc/myapp
and everything underneath, but not the parent/etc
directory.This might be written as follows:
The
*
wildcard isn't necessary here – you could just write/usr/bin/myscript
– but it can save a lot of typing if you have multiple files in a directory, or you keep renaming things. Note that wildcards are only expanded once, when the RPM is built, so this example is not claiming ownership of everything under/usr/bin/
, just what it finds under%{buildroot}/usr/bin/
at the time.The above only lists the paths owned by the package, without saying anything about the intended user, group, or permissions. These can be controlled with the
%defattr(...)
macro, which takes four arguments specifying the file permission, owning user, owning group, and directory permission for any path listed afterwards until the next%defattr(...)
. Extending the previous example:The first
%defattr
says that anything following should be owned by the root user and root group, and have permissions of0644
if a file or0755
if a directory. So the/etc/myapp
directory will be0755 root:root
, and the/etc/myapp/global.conf
will be0644 root:root
.The second
%defattr
says that anything following should be owned by theroot
user androot
group, and have permissions of0755
if a file and also if a directory. So the/usr/bin/myscript
file will be0755 root:root
.