This HOWTO last updated: 2008-12-03
Building packages with LBUILD
See an updated (August 2009) version of this article for an updated version of lbuild!
This howto concentrates on the lbuild package in my own repository, which contains patches for multi-user capable building. Minimum required version is lbuild-0.1_git200711191714-10.jen3.noarch.rpm (released 2008-12-03). No guarantee that lbuild packages not from me work.
Let's start with an overview of the paths that are used by default:
~/lbuild-output-* |
"output repository", where RPM packages that were just built are stored |
~/lbuild-root.* |
build environment (chroot) |
/etc/lbuild/dists_common |
system-wide build environment settings for all distribution releases |
/etc/lbuild/dists/ |
system-wide build environment settings for specific distribution releases |
/usr/lib/lbuild/configs/ |
system-wide rpm settings for specific distribution releases |
~/lbuild-config/dists_common |
user-specific build environment settings for all distribution releases |
~/lbuild-config/dist-* |
user-specific build environment settings for specific distribution release |
~/lbuild-config/*.conf |
user-specific rpm settings (ONLY macros supported at this time!) for specific distribution releases. |
As you will notice, the user-specific configuration directory carries both build environment and rpm setting files. An example how all of this comes together when you want to define a new release are described in a later section.
In /etc/lbuild/dists_common you can define the
path to the user-specific configuration files, by default it is set to
$hme/lbuild-config, which is what is described above.
Identity
You should define an identity that is written to each RPM
package so that people can identify packages more easily. Edit
~/lbuild-config/defaults.conf and add the following line, of
course replacing it with your real name and an address that bug reports can be
sent to:
macros:
%packager My Name <my-email@address.com>
%vendor My Name
You can also define %vendor, but that is only
useful for groups or companies. NOTE: %packager,
%vendor, %distribution, Packager:,
Vendor: and Distribution: SHOULD NEVER be
defined in a specfile.
Repositories
Now it is time to define the repositories that should be used
during build. Of course you will need base packages like aaa_base,
glibc and so on! In case you do not have the luxury to access an
FTP server over NFS, you will have to find other means to make binary packages
required for building available to lbuild, among which there is the DVD, or
downloading them. lbuild supports yast2, repomd and rpmdir (no metadata at all)
repository types.
In /etc/lbuild/dists/11.0, you will find the
system-wide defaults for 11.0 packages (i.e. packages that you want to
build for 11.0). They are:
add_sources="suse110u suse110"
url_suse110u="file:/ftp/suse/update/11.0"
url_suse110="file:/ftp/pub/opensuse/distribution/11.0/repo/oss"
You probably need to adjust the paths. http: or
ftp: is not supported, but you could use something like davfs or
ftpfs, but note that it would repeatedly transfer data when the chroot is
prepared.
The priority of the sources is from left to right, and lbuild-output is implicitly added with the highest priority — so that just-built (binary) packages always take precedence (when initializing the chroot) over those from other sources. Such makes it possible, for example, to build an older kernel and all the KMPs to it without having to muck around with priorities. This however also means that you should always be aware of what is still lurking in lbuild-output and that you eventually move it out.
There must be NO .patch.rpm or
.delta.rpm files in the source trees, because they are not
supported by cpio, which lbuild uses for doing the first stage setup of the
chroot.
If NFS is not an option for you, I suggest this shell script as a starting point. It
uses rsync, so you are always up-to-date. For example, if you ran that script
from within /home/lbuild-base, then the path you would have to
specify in /etc/lbuild/dists/11.0 would have to be
/home/lbuild-base/suse110 (if using the yast2 metadata) or
/home/lbuild-base/suse110/suse (if using the repomd metadata) or
or or — it depends on where the “common root” for metadata is. In Fedora for
example, this common root is the directory in which the directory “repodata”
is present. Please use yast metadata whenever possible.
Building a package from specfile
Since setting up the build environment (chroot), root
privileges are required. As such, lbuild must be started as root. To
support multiple build users, we need to know who the real user is. When
sudo is used, it sets the SUDO_USER environment variable
which lbuild will use to put the files into the proper directories and
not mix users' packages. su can unfortunately not be used because it
does not set any such environment variable. (That however does not mean
that sudo is better than su—sudo always carries a security
risk.)
Once you have sudo properly configured, run the build process. There are multiple ways to do this; we will see the latter method later again.
sudo lbuild-11.0 iptables.spec
sudo lbuild --dist=11.0-i386 --repo ""
iptables.spec
When the build went well, the new files are in your output
repository. Note that --repo "" does indeed take an empty
argument (""), and --repo must come as the last option of
all options.
Building a package from src.rpm
lbuild-11.0 foo.src.rpm
Adding a new distribution to build for - Example
Let's be unfaithful and take the opportunity to demonstrate
how to build for another distribution or release. We begin by adding a new file
at either /etc/lbuild/dists/fedora7 or
~/lbuild-config/dist-fedora7 with the following content:
repository="$hme/lbuild-output-fedora7"
url_repository="file:$repository"
add_sources="fedora7"
url_fedora7="file:/F/linux/fedora/linux/releases/7/Everything/i386/os"
You may want to add the symlinks fedora7-i386 and
fedora7-x86_64 (or for user-specific configuration:
dist-fedora7-i386 and dist-fedora7-x86_64) which
point to the fedora7 file. This becomes important when building
for multiple targets that share the same configuration but do need
different chroot directories. (The name of the chroot directory is derived from
the name, you will see use of --dist below.)
Next comes /usr/lib/lbuild/configs/fedora7.conf.
This file must exist. (I have not worked on LBUILD that much yet to provide a
user-specific "override-all" mode.) As we will soon see, this file is unlikely
to remain empty.
Before doing that however, you will want to define a
"Distribution" tag that will appear on all of the RPM packages generated for
Fedora7. Put the following into either
/usr/lib/lbuild/configs/fedora7.conf or
~/lbuild-config/fedora7.conf:
Macros:
%distribution Red-Hat (FC-7) (%_target_cpu)
(Strange as it seems, while the project changed their name from "Fedora Core" to "Fedora", they still use the "FC" keyword instead of "F". I did not make FC-7 up, this is how it is listed in the original Fedora7 RPM packages.)
Basically, this is all the boilerplate. That alone won't allow
building, though. You need a list of packages that need to be preinstalled into
the chroot to actually provide the basic utilities (bash, rpmbuild, and so on).
This is distribution/release-specific and you have to find out unless someone
already wrote it. (A fedora7.conf is provided with my variant of
the lbuild package, should you be interested.) Said list(s) is/are then to be
added to /usr/lib/lbuild/configs/fedora7.conf -- there is
currently no way to put it into the user-specific location! Here is an excerpt
of how it might look:
Preinstall: acl attr bash bzip2 bzip2-libs chkconfig coreutils db4
Preinstall: diffutils filesystem glibc grep libacl libattr
Preinstall: libgcc m4 ncurses pam
Preinstall: popt shadow-utils readline rpm rpm-libs sed tar zlib
Preinstall: beecrypt elfutils-libelf libselinux libsepol libstdc++ sqlite
And this is how you would start the build process then:
sudo lbuild --dist=fedora7-i386 --target=i586 --repo ""
someprogram.spec
The use of --target=i586 is specific to the x86
version of Fedora7 and serves to create i586 optimized RPMs instead of the
i386.rpm FC-7 default.
Multi-arch building
To actually cross-build for architectures, you should not use
--target=, but the generic kernel personality wrapper. This is
because by using --target only, `uname` would still
return x86_64. This affects some RPM builds, for example
kernel-source, whose helper binaries will be ELF-64 while the RPM
is marked as i586 (= not good). The proper way is to use the linux32
(or linux64) personality changers:
linux32 lbuild-11.0 iptables.spec