11.3. Патчи при сборке пакетов
При разработке с помощью Gear существует правило не изменять исходники в части git-репозитория, соответствующей авторским исходным текстам. Изменения разработчиков, сопровождающих пакет, надо держать отдельно; один из вариантов — в виде патчей. Этот вариант хорош тем, что явно поддерживается в структуре файла спецификации.
Соберём примитивный пакет, который затем преобразуем с помощью патча:
@user:
hello-upgrade-pkg/prog.c
#include <stdio.h>
char str[] = "Hello, Packager!";
int main(void) {
printf("%s\n", str);
return 0;
}
@user:
hello-upgrade-pkg/Makefile
TRASH = *.o *~ .gear/*~
GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall
hello-upgrade: prog.o
$(CC) $(CFLAGS) $< -o $@
clean:
rm -f $(TRASH)
distclean: clean
rm -f $(GENS)
@user:
hello-upgrade-pkg/.gear/rules
spec: .gear/hello-upgrade.spec
tar.gz: . name=@name@-@version@
@user:
hello-upgrade-pkg/.gear/hello-upgrade.spec
Name: hello-upgrade
Version: 1.0
Release: alt1
Summary: Test pkg with patch
License: GPL-3.0-or-later
Group: Development/Other
Source0: %name-%version.tar.gz
%description
This is a small testing package, builded with patch
%prep
%setup
%build
%make_build
%install
install -D %name %buildroot%_bindir/%name
%files
%_bindir/%name
%changelog
* Sat Aug 02 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial Build
Программа пакета просто печатает сообщение на экран:
@user
[user@VM hello-upgrade-pkg]$ gear-hsh --lazy
<...>
[user@VM hello-upgrade-pkg]$ cp ~/hasher/repo/x86_64/RPMS.hasher/hello-upgrade-1.0-alt1.x86_64.rpm ~/hasher/chroot/.in/
[user@VM hello-upgrade-pkg]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i hello-upgrade-1.0-alt1.x86_64.rpm
<13>Aug 2 15:58:59 rpm: hello-upgrade-1.0-alt1 1754150276 installed
[root@localhost .in]# hello-upgrade
Hello, Packager!
[root@localhost .in]#
Теперь добавим патч с изменениями. Для его создания воспользуемся git diff — встроенной в GIT утилитой определения изменений между коммитами. Её формат совместим с unified diff («лишние» строки с полями, относящимися к коммиту, утилита patch пропустит). Для начала добавим все изменения. Добавим новую функцию, которая будет возвращать сообщение для вывода. Отредактируем исходный код программы и Makefile для сборки:
@user:
hello-upgrade-pkg/fun.c
#include <stdio.h>
#include <stdlib.h>
void return_str(char* str) {
snprintf(str, 30, "Hello, Upgraded Packager!");
}
@user:
hello-upgrade-pkg/fun.h
void return_str(char* str);
@user:
hello-upgrade-pkg/prog.c
#include <stdio.h>
#include <stdlib.h>
#include "fun.h"
int main(void) {
char* result = malloc(30 * sizeof(char));
return_str(result);
printf("%s\n", result);
free(result);
return 0;
}
@user:
hello-upgrade-pkg/Makefile
TRASH = *.o *~ .gear/*~
GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall
hello-upgrade: prog.o fun.o
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f $(TRASH)
distclean: clean
rm -f $(GENS)
Теперь сделаем единый коммит и сохраним в виде патча все изменения (можно было сделать несколько коммитов, тогда при описании изменений рассматривались бы не соседние, а разнесённые в ветке коммиты, однако результат был бы таким же):
@user
[user@VM hello-upgrade-pkg]$ ls
fun.c fun.h Makefile prog.c
[user@VM hello-upgrade-pkg]$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: Makefile
modified: prog.c
Untracked files:
(use "git add <file>..." to include in what will be committed)
fun.c
fun.h
no changes added to commit (use "git add" and/or "git commit -a")
[user@VM hello-upgrade-pkg]$ git add fun.*
[user@VM hello-upgrade-pkg]$ git commit -a -m "Patch commit"
[master 9013147] Patch commit
4 files changed, 14 insertions(+), 4 deletions(-)
create mode 100644 fun.c
create mode 100644 fun.h
[user@VM hello-upgrade-pkg]$ git log --oneline
9013147 (HEAD -> master) Patch commit
fa6269f 1.0-alt1
e30b38f 1.0-alt1
9be6d7f 1.0-alt1
[user@VM hello-upgrade-pkg]$ git diff fa6269f 9013147 --patch --output=hello-upgrade-1.0-alt1.patch
[user@VM hello-upgrade-pkg]$ cat hello-upgrade-1.0-alt1.patch
index 3f543ad..c39cafe 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,8 @@ GENS = hello-upgrade
CC = cc
CFLAGS = -O0 -g -Wall
-hello-upgrade: prog.o
- $(CC) $(CFLAGS) $< -o $@
+hello-upgrade: prog.o fun.o
+ $(CC) $(CFLAGS) $^ -o $@
clean:
rm -f $(TRASH)
diff --git a/fun.c b/fun.c
new file mode 100644
index 0000000..5460923
--- /dev/null
+++ b/fun.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void return_str(char* str) {
+ snprintf(str, 30, "Hello, Upgraded Packager!");
+}
diff --git a/fun.h b/fun.h
new file mode 100644
index 0000000..444a555
--- /dev/null
+++ b/fun.h
@@ -0,0 +1 @@
+void return_str(char* str);
diff --git a/prog.c b/prog.c
index 5c41659..c05ada9 100644
--- a/prog.c
+++ b/prog.c
@@ -1,8 +1,11 @@
#include <stdio.h>
-
-char str[] = "Hello, Packager!";
+#include <stdlib.h>
+#include "fun.h"
int main(void) {
- printf("%s\n", str);
+ char* result = malloc(30 * sizeof(char));
+ return_str(result);
+ printf("%s\n", result);
+ free(result);
return 0;
}
[user@VM hello-upgrade-pkg]$
Теперь откатим репозиторий на коммит до изменений и просто сохраним патч:
@user
[user@VM hello-upgrade-pkg]$ git reset --hard HEAD~
HEAD is now at fa6269f 1.0-alt1
[user@VM hello-upgrade-pkg]$ tree . .gear/
.
├── hello-upgrade-1.0-alt1.patch
├── Makefile
└── prog.c
.gear/
├── hello-upgrade.spec
└── rules
2 directories, 5 files
[user@VM hello-upgrade-pkg]$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello-upgrade-1.0-alt1.patch
nothing added to commit but untracked files present (use "git add" to track)
[user@VM hello-upgrade-pkg]$ git add hello-upgrade-1.0-alt1.patch
[user@VM hello-upgrade-pkg]$ vim .gear/hello-upgrade.spec
[user@VM hello-upgrade-pkg]$ gear-commit -a
[master 157f524] 1.0-alt1
2 files changed, 54 insertions(+)
create mode 100644 hello-upgrade-1.0-alt1.patch
[user@VM hello-upgrade-pkg]$
Добавим описание патча в spec-файл и .gear/rules для его переноса в hasher при сборке. В spec-файле необходимо указать название патча, а также команду применения патча после распаковки исходников (в директиву %prep добавляется специальный макрос %autopatch):
@user:
hello-upgrade-pkg/.gear/hello-upgrade.spec
Name: hello-upgrade
Version: 1.0
Release: alt1
Summary: Test pkg with patch
License: GPL-3.0-or-later
Group: Development/Other
Source0: %name-%version.tar.gz
Patch: %name-%version-%release.patch
%description
This is a small testing package, builded with patch
%prep
%setup
%autopatch -p1
%build
%make_build
%install
install -D %name %buildroot%_bindir/%name
%files
%_bindir/%name
%changelog
* Sat Aug 02 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Initial Build
- Add Patch
При сборке %autopatch раскрывается в последовательное применение патчей, заданных директивами Patch: и Patch№:. Ключ -p1 передаётся каждому запуску утилиты Patch — он означает, что в описании имён файлов внутри патча присутствует один «лишний» каталог. В самом деле, в описании патча, полученного с помощью git diff все изменённые файлы принадлежат псевдодиректориям a/ и b/:
@user
[user@VM hello-upgrade-pkg]$ cat hello-upgrade-1.0-alt1.patch | grep -E "(a/|b/)"
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
diff --git a/fun.c b/fun.c
+++ b/fun.c
diff --git a/fun.h b/fun.h
+++ b/fun.h
diff --git a/prog.c b/prog.c
--- a/prog.c
+++ b/prog.c
[user@VM hello-upgrade-pkg]$
a/ — обозначает «старую» версию файла, b/ — «новую» версию, между которыми производится сравнение. При применении патча эти директории будут проигнорированы утилитой (как раз благодаря флагу -p1), но при этом повышается читаемость самого патча.
Соберём пакет и проверим, что патч применился:
@user
[user@VM hello-upgrade-pkg]$ gear-hsh --lazy
<...>
Executing(%prep): /bin/sh -e /usr/src/tmp/rpm-tmp.84343
+ umask 022
+ /bin/mkdir -p /usr/src/RPM/BUILD
+ cd /usr/src/RPM/BUILD
+ cd /usr/src/RPM/BUILD
+ rm -rf hello-upgrade-1.0
+ echo 'Source #0 (hello-upgrade-1.0.tar.gz):'
Source #0 (hello-upgrade-1.0.tar.gz):
+ /bin/tar -xf -
+ /usr/bin/gzip -dc /usr/src/RPM/SOURCES/hello-upgrade-1.0.tar.gz
+ cd hello-upgrade-1.0
+ /bin/chmod -c -Rf u+rwX,go-w .
+ echo 'Patch #0 (hello-upgrade-1.0-alt1.patch):'
Patch #0 (hello-upgrade-1.0-alt1.patch):
+ /usr/bin/patch -p1
patching file Makefile
patching file fun.c
patching file fun.h
patching file prog.c
+ exit 0
<...>
[user@VM hello-upgrade-pkg]$ cp ~/hasher/repo/x86_64/RPMS.hasher/hello-upgrade-1.0-alt1.x86_64.rpm ~/hasher/chroot/.in/
[user@VM hello-upgrade-pkg]$ hsh-shell --rooter
@rooter
[root@localhost .in]# rpm -i hello-upgrade-1.0-alt1.x86_64.rpm
<13>Aug 3 07:55:29 rpm: hello-upgrade-1.0-alt1 1754206866 installed
[root@localhost .in]# hello-upgrade
Hello, Upgraded Packager!
[root@localhost .in]#