Wie man einen Kernel kompiliert - auf Fedora

Version 1.0
Author: Falko Timme


Jede Distribution hat besondere Tools, mit denen sie einen benutzerdefinierten Kernel aus den Quellen kompiliert. Diese Anleitung veranschaulicht, wie man einen Kernel auf Fedora-Systemen kompiliert. Sie beschreibt, wie man einen benutzerdefinierten Kernel baut, unter Verwendung der neusten unveränderten Kernelquellen von www.kernel.org (vanilla kernel), damit Du nicht an die Kernel, die von Deiner Distribution bereitgestellt werden, gebunden bist. Weiterhin wird gezeigt, wie man die Kernelquellen patcht, falls Funktionen benötigt werden, die darin nicht enthalten sind.

Ich habe dies auf Fedora Core 6 getestet.

Ich möchte an dieser Stelle darauf hinweisen, dass dies nicht der einzige Weg ist, ein solches System einzurichten. Es gibt viele Möglichkeiten dieses Ziel zu erreichen - dies ist der Weg, den ich gewählt habe. Ich übernehme keine Garantie, dass dies auch bei Dir funktioniert!

1 Vorbemerkung

In dieser Anleitung beschreibe ich zwei Varianten, wie man einen Kernel für Fedora Systeme baut. Die erste Variante ist Fedora-spezifisch. Du erhältst am Ende ein Kernel rpm Paket, das Du installieren oder mit anderen teilen kannst. Die zweite Variante ist für alle Linux Distributionen die gleiche, Du hast am Ende allerdings kein rpm Paket.

Ich werde alle Schritte dieser Anleitung als root Benutzer ausführen. Es ist jedoch möglich, die meisten Befehle als nicht-privilegierter Benutzer auszuführen (z.B. Benutzer tom). Einige Befehle, wie yum oder rpm verlangen trotzdem Root-Privilegien, Du solltest tom (oder was auch immer Dein Benutzername ist) also /etc/sudoers hinzufügen indem Du Folgendes ausführst

visudo

Füge diese Zeile hinzu:
tom  ALL=(ALL) ALL
Wenn Du also einen Befehl ausführst, der Root-Privilegien erfordert, wie zum Beispiel

yum install fedora-rpmdevtools unifdef

wird Dir das der Befehl mitteilen und Du musst stattdessen Folgendes ausführen

sudo yum install fedora-rpmdevtools unifdef

Denke daran: Du kannst sudo vergessen, wenn Du alle Befehle als root ausführst. Es ist Dir überlassen, was Du bevorzugst.

2 Ein Kernel rpm Paket bauen

Dieses Kapitel zeigt, wie man einen Kernel baut und ein rpm Paket erhält, das man installieren und mit anderen teilen kann.

2.1 Dein rpmbuild Verzeichnis erstellen

Erstelle Dein rpmbuild Verzeichnis wie folgt:

cd ~
cp -a /usr/src/redhat/ rpmbuild
echo '%_topdir %(echo $HOME)/rpmbuild' >> .rpmmacros

Installiere dann die benötigten Pakete um rpm Pakete zu bauen

yum install fedora-rpmdevtools unifdef

und führe dies aus

fedora-buildrpmtree


2.2 Lade ein Fedora Kernel src.rpm runter und installiere es

Als Nächstes laden wir das neuste Kernel src.rpm für unsere Fedora Version runter. Für Fedora Core 6 befinden sich die src.rpm Pakete in http://download.fedora.redhat.com/pub/fedora/linux/core/6/source/SRPMS/, für Fedora Core 5 ist es http://download.fedora.redhat.com/pub/fedora/linux/core/5/source/SRPMS/ usw.

Das neuste Fedora Core 6 Kernel src.rpm ist kernel-2.6.18-1.2798.fc6.src.rpm, also laden wir es runter und installieren es:

cd /usr/src
wget http://download.fedora.redhat.com/pub/fedora/linux/core/6/source/SRPMS/kernel-2.6.18-1.2798.fc6.src.rpm
rpm -ivh kernel-2.6.18-1.2798.fc6.src.rpm

Wenn Du diese Warnungen siehst:

warning: user brewbuilder does not exist - using root
warning: group brewbuilder does not exist - using root

kannst Du sie ignorieren.

Wir haben soeben die Kernelquellen für den 2.6.18 Kernel zusammen mit vielen Fedora Patches und einem Patch für den Kernel 2.6.18.1 installiert. Wenn wir also damit fortfahren würden, einen Kernel aus diesem src.rpm zu bauen, würden wir den Kernel 2.6.18.1 erhalten.

2.3 Den Kernel patchen

Anstelle von Kernel 2.6.18.1 möchte ich Kernel 2.6.18.2 installieren. Das src.rpm, das wir installiert haben, enthielt Kernel 2.6.18 plus einem Patch für Kernel 2.6.18.1. Wir werden diesen Patch nun mit dem Patch für Kernel 2.6.18.2 ersetzen.

cd ~/rpmbuild/SOURCES/
wget http://www.kernel.org/pub/linux/kernel/v2.6/patch-2.6.18.2.bz2

Du könntest außerdem den http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.19-rc5.bz2 Prepatch verwenden, wenn Du Kernel 2.6.19-rc5 haben möchtest. Bitte beachte, dass dies nur für Prepatches funtioniert, d.h. Patches für Kernel, die noch nicht in einer Endversion verfügbar sind, wie zum Beispiel der 2.6.19 Kernel. Du kannst diesen Patch in den 2.6.18 Kernelquellen anbringen, aber nicht in Kernel 2.6.18.1 oder 2.6.18.2, etc. Dies wird auf http://kernel.org/patchtypes/pre.html erklärt:

"Prepatches are the equivalent to alpha releases for Linux; they live in the testing directories in the archives. They should be applied using the patch(1) utility to the source code of the previous full release with a 3-part version number (for example, the 2.6.12-rc4 prepatch should be applied to the 2.6.11 kernel sources, not, for example, 2.6.11.10.)"
Nun müssen wir die kernel-2.6.spec Datei modifizieren, damit sie von unserem neuen Kernel Patch weiß:

cd ~/rpmbuild/SPECS/

vi kernel-2.6.spec

Suche die Zeile

Patch1: patch-2.6.18.1.bz2

und ersetze sie mit dieser:

Patch1: patch-2.6.18.2.bz2

(oder mit dem Patch, den Du zuvor runter geladen hast).

Führe dann dies aus

rpmbuild -bp kernel-2.6.spec

(Wenn Du den Kernel für eine besondere Architektur bauen möchtest, wie zum Beispiel i386, i586, i686, oder x86_64, kannst Du dies wie folgt ausführen:

rpmbuild -bp --target=i686 kernel-2.6.spec

Ich definiere es in diesem Beispiel nicht und erhalte hier einen i386 Kernel. Dein System baut stattdessen vielleicht einen Kernel für eine andere Architektur, wenn Du es nicht definierst, also denke daran, wenn Du weiterhin dieser Anleitung folgst.)

Jetzt kommt der knifflige Part. Das src.rpm hat viele Fedora-spezifische Patches. Einige von ihnen werden mit unserem 2.6.18.2 Patch nicht funktionieren, wenn Du also etwas in der Art in der rpmbuild Ausgabe siehst:

+ echo 'Patch #300 (linux-2.6-ppc-dac960-ipr-clash.patch):'
Patch #300 (linux-2.6-ppc-dac960-ipr-clash.patch):
+ patch -p1 -s
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
1 out of 1 hunk ignored -- saving rejects to file drivers/block/DAC960.c.rej
error: Bad exit status from /var/tmp/rpm-tmp.46287 (%prep)

RPM build errors:
Bad exit status from /var/tmp/rpm-tmp.46287 (%prep)

musst Du kernel-2.6.spec erneut bearbeiten und den Patch #300 auskommentieren:

vi kernel-2.6.spec


[...]
#Patch300: linux-2.6-ppc-dac960-ipr-clash.patch [...] #%patch300 -p1 [...]
Führe dann erneut Deinen rpmbuild Befehl aus, z.B.

rpmbuild -bp kernel-2.6.spec

Du musst das so lange wiederholen, bis es keine Fehlermeldungen mehr gibt, dass Patches nicht angewandt werden konnten.

2.4 Eine Kernelbezeichnung festlegen

Jetzt sollten wir eine Bezeichnung festlegen, mit der wir unseren Kernel später identifizieren können. Daher führen wir dies aus:

cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i386
vi Makefile

Du kannst die Kernel Identifikation in die EXTRAVERSION Zeile setzen. Ich finde, es macht sich auch ganz gut, die Kernel Version mit anzuhängen, also ist etwas in der Art in Ordnung:

EXTRAVERSION = -custom-2.6.18.2


2.5 Den Kernel konfigurieren

Nun führen wir dies aus

make menuconfig

was das Kernel Konfigurationsmenü aufruft. Gehe zu Load an Alternate Configuration File und wähle .config als Konfigurationsdatei:



Durchblättere dann das Kernel Konfigurationsmenü und treffe Deine Wahl. Wenn Du damit fertig bist und Exit wählst, beantworte folgende Frage (Do you wish to save your new kernel configuration?) mit Yes:

2.6 Den Kernel bauen

Nun bauen wir unser Kernel pm Paket indem wir einfach Folgendes ausführen

make rpm

Afterwards you will find a new src.rpm package in the ~/rpmbuild/SRPMS/ directory, e.g. ~/rpmbuild/SRPMS/kernel-2.6.18custom2.6.18.2-1.src.rpm, and the kernel rpm package in ~/rpmbuild/RPMS/i386/ (or ~/rpmbuild/RPMS/i586/, ~/rpmbuild/RPMS/i686/, etc. depending on your architecture), e.g. ~/rpmbuild/RPMS/i386/kernel-2.6.18custom2.6.18.2-1.i386.rpm. As you see your kernel identification has been added to the package name.


2.7 Den neuen Kernel installieren

Gehe nun in das Verzeichnis, in dem Dein neues Kernel rpm Paket erstellt wurde (je nach Deiner Architektur, z.B. ~/rpmbuild/RPMS/i386/) und installiere das rpm Paket:

cd ~/rpmbuild/RPMS/i386
rpm -ivh kernel-2.6.18custom2.6.18.2-1.i386.rpm

(Du kannst nun sogar das rpm Paket zu anderen Fedora Systemen transferieren und es dort auf die gleiche Art installieren, was bedeutet, dass Du den Kernel dort nicht noch einmal kompilieren musst.)

Als Nächstes erstellen wir eine Ramdisk für unseren neuen Kernel, da das System sonst wahrscheinlich unseren neuen Kernel nicht starten wird:

mkinitrd /boot/initrd-2.6.18-custom-2.6.18.2.img 2.6.18-custom-2.6.18.2

Bearbeite dann /boot/grub/menu.lst. Sieh Dir dort Deine vorhandenen (funktionierenden) Kernel Zeilen an und nimm eine von ihnen als Muster für Deine neue Zeile und ersetze den Kernel und die Ramdisk, füge die Zeile dann über allen anderen Zeilen ein.

vi /boot/grub/menu.lst

Zum Beispiel sieht mein menu.lst bevor ich die neue Zeile hinzufüge so aus:
# grub.conf generated by anaconda
# # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00 # initrd /initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Fedora Core (2.6.18-1.2798.fc6) root (hd0,0) kernel /vmlinuz-2.6.18-1.2798.fc6 ro root=/dev/VolGroup00/LogVol00 initrd /initrd-2.6.18-1.2798.fc6.img
und so danach:
# grub.conf generated by anaconda
# # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00 # initrd /initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Fedora Core (2.6.18-custom-2.6.18.2) root (hd0,0) kernel /vmlinuz-2.6.18-custom-2.6.18.2 ro root=/dev/VolGroup00/LogVol00 initrd /initrd-2.6.18-custom-2.6.18.2.img title Fedora Core (2.6.18-1.2798.fc6) root (hd0,0) kernel /vmlinuz-2.6.18-1.2798.fc6 ro root=/dev/VolGroup00/LogVol00 initrd /initrd-2.6.18-1.2798.fc6.img
(Du findest die richtigen vmlinuz und initrd Dateien raus, indem Du dies ausführst

ls -l /boot

)

Sarte das System jetzt neu:

shutdown -r now

Wenn alles klappt, sollte es mit dem neuen Kernel starten. Ob es wirklich Deinen neuen Kernel benutzt, überprüfst Du, indem Du Folgendes ausführst

uname -r

Dies sollte etwas in der Art anzeigen

2.6.18-custom-2.6.18.2

Wenn das System nicht startet, starte es neu und wenn Du dies siehst:


drücke irgendeine Taste um in das GRUB Menü zu gelangen:


Wähle Deinen alten Kernel aus und starte das System. Du kannt nun erneut versuchen, einen funktionstüchtigen Kernel zu kompilieren. Vergiss nicht, die Zeile des defekten Kernels aus /boot/grub/menu.lst zu entfernen:

3 Wie man den Kernel auf traditionelle Art und Weise baut

Dieses Kapitel beschreibt einen anderen Ansatz, der auf jedem Linux System angewandt werden kann. Da daran nichts Fedora-spezifisch ist, erhältst Du am Ende natürlich auch kein Kernel rpm Paket.

3.1 Die Kernelquellen runter laden

Wir laden unseren gewünschten Kernel nach /usr/src. Gehe zu www.kernel.org und wähle den Kernel aus, den Du installieren möchtest, z.B. linux-2.6.18.2.tar.bz2 (hier findest Du alle 2.6 Kernel: http://www.kernel.org/pub/linux/kernel/v2.6/). Dann kannst Du ihn wie folgt nach /usr/src laden:

cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.2.tar.bz2

Dann entpacken wir die Kernelquellen und erstellen einen Symlink linux zum Kernelquellen Verzeichnis:

tar xjf linux-2.6.18.2.tar.bz2
ln -s linux-2.6.18.2 linux
cd /usr/src/linux

3.2 Patches in den Kernelquellen anbringen (optional)

Manchmal benötigst Du Treiber für Hardware, die von dem neuen Kernel nicht standardmäßig unterstützt wird, oder Du benötigst Unterstützung für Virtualisierungstechniken oder eine andere brandneuen Technologie, die beim Kernel noch nicht angekommen ist. In all diesen Fällen musst Du die Kernelquellen patchen (vorausgesetzt es ist ein Patch verfügbar...).

Gehen wir nun davon aus, dass Du den benötigten Patch (ich nenne ihn in diesem Beispiel patch.bz2) nach /usr/src geladen hast. So bringst Du ihn in Deinem Kernelquellen an (Du musst Dich immer noch im /usr/src/linux Verzeichnis befinden):

bzip2 -dc /usr/src/patch.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch.bz2 | patch -p1

Der erste Befehl ist nur ein Test und ändert nichts an Deinen Quellen. Wenn er keine Fehler anzeigt, kannst Du den zweiten Befehl ausführen, der den Patch tatsächlich anbringt. Tu das nicht, wenn der erste Befehl Fehler angezeigt hat!

Du kannst auch Kernel Prepatches in Deinen Kernelquellen anbringen. Wenn Du zum Beispiel eine Funktion brauchst, die nur in Kernel 2.6.19-rc5 verfügbar ist, die gesamten Quellen für diesen Kernel aber noch nicht veröffentlicht wurden. Stattdessen ist ein patch-2.6.19-rc5.bz2 verfügbar. Du kannst diesen Patch in den 2.6.18 Kernelquellen anbringen, aber nicht in Kernel 2.6.18.1 oder 2.6.18.2, etc. Dies wird auf http://kernel.org/patchtypes/pre.html erklärt:

"Prepatches are the equivalent to alpha releases for Linux; they live in the testing directories in the archives. They should be applied using the patch(1) utility to the source code of the previous full release with a 3-part version number (for example, the 2.6.12-rc4 prepatch should be applied to the 2.6.11 kernel sources, not, for example, 2.6.11.10.)"
Wenn Du also einen 2.6.19-rc5 Kernel kompilieren möchtest, musst Du die 2.6.18 Kernelquellen (http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.18.tar.bz2) in Schritt 3.1 anstelle von Kernel 2.6.18.2 runter laden!

So bringst Du den 2.6.19-rc5 Patch in Kernel 2.6.18 an:

cd /usr/src
wget http://www.kernel.org/pub/linux/kernel/v2.6/testing/patch-2.6.19-rc5.bz2
cd /usr/src/linux
bzip2 -dc /usr/src/patch-2.6.19-rc5.bz2 | patch -p1 --dry-run
bzip2 -dc /usr/src/patch-2.6.19-rc5.bz2 | patch -p1

3.3 Den Kernel konfigurieren

Es ist eine gute Idee, die Kofiguration Deines derzeit funktionstüchtigen Kernels als Basis für Deinen neuen Kernel zu verwenden. Daher kopieren wir die vorhandene Konfiguration nach /usr/src/linux:

make mrproper
cp /boot/config-`uname -r` ./.config

Dann führen wir dies aus

make menuconfig

was das Kernel Konfigurationsmenü aufruft. Gehe zu Load an Alternate Configuration File und wähle .config (das die Konfiguration Deines derzeit funktionstüchtigen Kernels enthält) als Konfigurationsdatei aus:



Durchblättere dann das Kernel Konfigurationsmenü und treffe Deine Wahl. Wenn Du damit fertig bist und Exit wählst, beantworte folgende Frage (Do you wish to save your new kernel configuration?) mit Yes:

3.4 Den Kernel bauen und installieren

Um den Kernel bauen und installieren zu können, führe diese drei Befehle aus:

make all
make modules_install
make install

Sei nun geduldig, die Kompilierung des Kernels kann einige Stunden dauern, je nach Kernelkonfiguration und Prozessorgeschwindigkeit. Der letzte Befehl erstellt außerdem automatisch eine Ramdisk und konfiguriert /boot/grub/menu.lst für Dich.

Bearbeite nun /boot/grub/menu.lst. Du müsstest eine Zeile für Deinen neuen Kernel zu Beginn der Liste finden. Um jedoch sicher zu stellen, dass der neue Kernel und nicht der alte gestartet wird, musst Du den Wert von default auf 0 setzen.

vi /boot/grub/menu.lst

Mein menu.lst sieht wie folgt aus:
# grub.conf generated by anaconda
# # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00 # initrd /initrd-version.img #boot=/dev/sda default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Fedora Core (2.6.18.2) root (hd0,0) kernel /vmlinuz-2.6.18.2 ro root=/dev/VolGroup00/LogVol00 initrd /initrd-2.6.18.2.img title Fedora Core (2.6.18-1.2798.fc6) root (hd0,0) kernel /vmlinuz-2.6.18-1.2798.fc6 ro root=/dev/VolGroup00/LogVol00 initrd /initrd-2.6.18-1.2798.fc6.img
Starte nun das System neu:

shutdown -r now

Wenn alles klappt, sollte der neue Kernel gestartet werden. Ob auch wirklich der neue Kernel verwendet wird, kannst Du überprüfen, indem Du Folgendes ausführst

uname -r

Dies solle etwas in der Art anzeigen

2.6.18.2

Wenn das System nicht startet, starte es neu und wenn Du dies siehst:


drücke irgendeine Taste um ins GRUB Menü zu gelangen:


Wähle Deinen alten Kernel aus und starte das System. Nun kannst Du erneut versuchen, einen funktionierenden Kernel zu kompilieren. Vergiss nicht die Zeile des defekten Kernels aus /boot/grub/menu.lst zu entfernen.

4 Links