Patching packages

Related articles
Creating packages
This article covers how to create and how to apply patches to packages in the
Arch build system
(ABS).
A
patch
describes a set of line changes for one or multiple files. Patches are typically used to automate the changing of source code.
Creating patches
Note
If you only need to change one or two lines, you might want to use
sed
instead.
The
diff
tool compares files line by line. If you save its output you have a patch, e.g.
diff --unified --recursive --text foo bar > foobar.patch
(which can be shortened to
diff -ura
). If you pass directories
diff
will compare the files they contain.
Delete the
src
directory if you have already built the package.
Run
makepkg --nobuild
/
makepkg -o
which will download and extract the source files, specified in
PKGBUILD
, but not build them. If the system you are making the patch on does not have the required dependencies, you may have to run
makepkg --nobuild --nodeps
/
makepkg -od
instead.
Create two copies of the extracted directory in the
src
directory, one as a pristine copy and one for your altered version. We will call them
package.orig
and
package.new
.
Make your changes in the
package.new
directory.
Run
diff -ura package.orig package.new --color
and check if the patch looks good.
Run
diff -ura package.orig package.new > package.patch
to create the patch.
Change into the initial
package.orig
directory from which you made copies and apply the patch using
patch --strip=1 --input=../package.patch
(which can be shortened to
patch -p1 -i ../package.patch
). Verify that the patch is working by building and installing the modified package with
makepkg --noextract --install
/
makepkg -ei
.
Note
You can also create patches with
Git
using
git diff
or
git format-patch
[1]
.
See
diff(1)
and
git-diff(1)
for more info.
Tip
Most git hosting platforms (such as GitHub or GitLab) allow to generate patches for a specific commit or a specific merge/pull request by appending
.patch
to their URL. For GitHub, consider also adding a
?full_index=1
parameter at the end of the URL to avoid checksum mismatches due to future changes to the object hash length.
Applying patches
This section outlines how to apply patches you created or downloaded from the Internet from within a
PKGBUILD
's
prepare()
function. Follow these steps:
Add an entry to the
source
array of the
PKGBUILD
for the patch file, separated from the original source url by a space. If the file is available online, you can provide the full URL and it will automatically be downloaded and placed in the
src
directory. If it is a patch you created yourself, or is otherwise not available, you should place the patch file in the same directory as the
PKGBUILD
file, and just add the name of the file to the source array so that it is copied into the
src
directory. If you redistribute the
PKGBUILD
, you should, of course, include the patch with the
PKGBUILD
.
Then use
makepkg -g >> PKGBUILD
or
updpkgsums
(from
pacman-contrib
) to update the
sha512sums
array. Or manually add an entry to the
sha512sums
array; you can generate the sum of your patch using
sha512sum
tool.
Create the
prepare()
function in the
PKGBUILD
if one is not already present.
The first step is to change into the directory that needs to be patched (in the
prepare()
function, not on your terminal! You want to automate the process of applying the patch).  You can do this with something like
cd $pkgname-$pkgver
.
$pkgname-$pkgver
is often the name of a directory created by untarring a downloaded source file, but not in all cases.
Now you simply need to apply the patch from within this directory. This is very simply done by adding
patch -p1 -i
pkgname
.patch
to your
prepare()
function, changing
pkgname
.patch
to the name of the file containing the diff (the file that was automatically copied into your
src
directory because it was in the
source
array of the
PKGBUILD
file).
An example prepare-function:
PKGBUILD
prepare() {
    cd $pkgname-$pkgver
    patch -Np1 -i ../eject.patch
}
Alternatively, you can use the
--directory
/
-d
flag of
patch
without having to cd first. The example above would then become:
PKGBUILD
prepare() {
    patch -d $pkgname-$pkgver -Np1 -i ../eject.patch
}
Run
makepkg
from the terminal now. If all goes well, the patch will be automatically applied, and your new package will contain whatever changes were included in the patch. If not, you may have to experiment with the
--strip
/
-p
option of patch. While experimenting, you might find
--dry-run
,
--reverse
or
--verbose
options usable. Read
patch(1)
for more information.
Basically it works as follows. If the diff file was created to apply patches to files in
myversion/
, the diff files will be applied to
myversion/file
. You are running it from within the
yourversion/
directory (because you would cd into that directory in the
PKGBUILD
), so when patch applies the file, you want it to apply it to the file
file
, taking off the
myversion/
part.
-p1
does this, by removing one directory from the path. However, if the developer patched in
myfiles/myversion
, you need to remove two directories, so you use
-p2
.
If you do not apply a
-p
option, it will take off all directory structure. This is OK if all the files are in the base directory, but if the patch was created on
myversion/
and one of the edited files was
myversion/src/file
, and you run the patch without a
-p
option from within
yourversion
, it will try to patch a file named
yourversion/file
.
Most developers create patches from the parent directory of the directory that is being patched, so
-p1
will usually be right.
Using quilt
A simpler way to create patches is using
quilt
which provides better support for managing many patches, such as applying patches, refreshing patches, and reverting patched files to original state.
quilt
is used on
Debian
to manage their patches. See
Using Quilt
for basic information about basic quilt usage to generate, apply patches, and reverting patched files.
See also
http://www.kegel.com/academy/opensource.html
— Useful information on patching files