I suggest to start with the simplest scenario possible:
Rebuild of the running kernel
This would allow for simple patching, where the configuration does not need to be changed. And it would be a test for build readiness.
Of course, it already includes some challenges:
1. Fetching the kernel source
There are three ways: kernel_org, APT source, or git
I assume that kernel_org sources do not contain the specific support for building suitable Ubuntu packages, so this is not recommended for a start and an emergency measure if there is no other way to get the build done.
APT source is quite nice, because network load and disk space requirement are low. Of course, it would be nice to get some fixes uploaded, but there can be a more advanced git guide which perfectly adds the knowledge missing to do that.
After having slow progress with the APT source, I tried git, and it has occupied 3.6 GB of disk space! I had to create a branch to be able to track my changes, which is common, but maybe too much hassle for a start. Although my machine and internet connection are not so slow, it was a test of patience to clone the repository. An outdated guide tells several 100 MB as a requirement.
2. Install all prerequisites as preparation for the build
My actual list for Ubuntu 6.2.0-26.26~22.04.1-generic 6.2.13 on jammy/amd64 contains:
libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev debhelper binutils-dev python-is-python3 libiberty-dev pahole libreadline-dev llvm ubuntu-dev-tools libdw-dev systemtap-sdt-dev libunwind-dev libslang2-dev libzstd-dev libcap-dev libbabeltrace-ctf-dev openjdk-8-jdk libtraceevent-dev
and for Rust some more:
rustc cargo llvm-15 lld-15 clang-15 wasi-libc bindgen librust-core-foundation-dev rust-src
It would be nice to have a metapackage to install them all. Maybe it exists already. I admit that I have not built Ubuntu kernels for quite some time, and the outdated guides are contradictory and confusing. The Ubuntu kernel could provide the prerequisites, because it depends on the version. Even providing dependencies upstream would be possible, specified by the components which require it, and the distribution just would need to do the mapping from <name,version> to package. Of course, it could add distribution-specific dependencies.
3. Apply the actual configuration residing in /boot/$(uname -r)
The expectation is that the whole config is accepted in the build, and that there are no differences anymore. Let me show the progress after several hours of tweaking:
$ scripts/diffconfig /boot/config-6.2.0-26-generic .config
-GPIO_AAEON m
-LEDS_AAEON m
-MFD_AAEON m
-SENSORS_AAEON m
-UBUNTU_ODM_DRIVERS y
CC_VERSION_TEXT "x86_64-linux-gnu-gcc-11 (Ubuntu 11.3.0-1ubuntu1~22.04.1) 11.3.0" -> "gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
GCC_VERSION 110300 -> 110400
PAHOLE_VERSION 122 -> 125
+PAHOLE_HAS_LANG_EXCLUDE y
+RUST n
Having a static package configuration older than a fully updated system cannot be expected by the casual user, for security reasons alone. On build servers, it is another matter of course. If there would be an easy way to create a VM for that, it would help, but only for those who already use VMs (BIOS settings, guest OS installation and extra space required) and with preferably high automation.
The casual user usually does not need a specific kernel version for a start, the version of the running kernel would be the smallest version acceptable. One could be suggested which matches the system nicely. I understand that this might be wishful thinking.
A static baseline only used for the kernel build could be kept in the repository and installed by the metapackage for installing build prerequisites. I have seen the GCC_VERSION difference, but maybe this change is not affecting anything.
Usually, for testing the configuration can be stripped to the hardware available, which would make it easier by far to have an accepted configuration with no important differences. In my case, I could not do it, because the Presonus 1810, NOT 1810c, audio interface (194f:0106) makes my system freeze (Firefox not responding, …). Although the USB device is not supported by kernels upto the most recent one, 6.5rc6, it is not ignored. Quite the contrary.
4. Build steps
We all remember probably how it was in ancient times. If I remember correctly:
$ cp -a /boot/config-$(uname -r) .config
$ make oldconfig
$ make
$ make modules
$ make install
Most guides avoid the Ubuntu procedure and recommend to get sources from kernel.org. Debian packages can be created somehow anyway, surprisingly.
Many guides tell the following procedure:
$ debian/rules clean
$ debian/rules binary
When the configuration shall be applied, diversity starts.
I did two things:
4a. adapt header in debian.master/config/annotations:
ARCH: amd64
FLAVOUR: amd64-generic
And because I found a sister directory, debian.hwe-6.2/, with the same annotations header, I have changed it as well. I do not understand the difference between these two directories in relation to the build.
4b. set a suffix in debian.master/changelog (first line)
I appended +presonus1810 to mark the specific kernel.
A bit awkward to configure things like that, editing a changelog file at the beginning.
Usually a changelog has documentation purposes only, for development history sorted in chronological order.
4c. Build procedure
Although I did not want to change the configuration, somehow check-config always complains about differences.
First try:
$ cp /boot/config-6.2.0-26-generic .config
$ ./debian/scripts/misc/annotations --arch amd64 --flavour generic --import .config
$ LANG=C fakeroot debian/rules clean
No change in config, so I left out the following step.
#$ LANG=C fakeroot debian/rules updateconfigs
$ LANG=C fakeroot debian/rules binary
Second try:
$ ./debian/scripts/misc/annotations --arch amd64 --flavour generic --export
$ LANG=C fakeroot debian/rules clean
No change in config, so I left out the following step.
#$ LANG=C fakeroot debian/rules updateconfigs
$ LANG=C fakeroot debian/rules binary
Third try:
$ git clone git://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/jammy
$ cd jammy
$ git checkout -b Ubuntu-hwe-6.2-6.2.0-26.26_22.04.1-presonus1810 Ubuntu-hwe-6.2-6.2.0-26.26_22.04.1
$ patch -p1 <../presonus_1810.patch
$ git commit -a -m "Replace device id for Presonus 1810c by id for older 1810 model"
$ patch -p1 <../build.patch
$ git commit -a -m "Preparation for build:
- add variant -presonus1810
- reduce archs to build to amd64"
Necessary?
$ chmod a+x debian/rules
$ chmod a+x debian/scripts/*
$ chmod a+x debian/scripts/misc/*
$ LANG=C fakeroot debian/rules clean
$ LANG=C fakeroot debian/rules binary
Is LANG=C
necessary? Somehow strange that a locale setting is assumed to affect a kernel build.
Fourth try:
Like third try, but with steps from another guide:
LANG=C fakeroot debian/rules clean
LANG=C fakeroot debian/rules editconfigs do_enforce_all=false
LANG=C fakeroot debian/rules editconfigs do_enforce_all=false
LANG=C fakeroot debian/rules do_enforce_all=false binary
and answering ‘n’ for editconfigs
both times
One guide mentions that still there is an enforcement done by annotations, and it recommends to do the following:
echo '' >debian.master/config/annotations
...
Fifth try:
Returning to APT source because there does not seem to be a difference concerning the build.
$ make olddefconfig
#
# using defaults found in /boot/config-6.2.0-26-generic
#
#
# configuration written to .config
#
Note: target olddefconfig is quite comfortable. I am glad to know about it now.
$ LANG=C fakeroot debian/rules clean
$ LANG=C fakeroot debian/rules binary
The question is, in which way the configuration from /boot/config-$(uname -r)
is applied. I had problems with the annotations script probably because it read the default configuration. This could be detected. I would even go so far as to suggest that if the user does not configure the kernel, the default Ubuntu configuration is applied, and it is mentioned that it is done of course.
I am not a fan of the check-config
steps so far because usually a maintainer does not change the configuration without a very good reason, and with git a personalized commit message for such a change is required. But checking for a non-configured kernel is a help for beginners because of the outdated and incomplete guides out there. Because of all the automation sometimes steps are left out which are still vital for a build.
Unfortunately, I am stuck in the process:
make[1]: Leaving directory '/[...]/debian/build/tools-perarch/tools/perf'
mv /[...]/debian/build/tools-perarch/tools/bpf/bpftool/vmlinux /[...]/debian/build/tools-perarch/vmlinux
mv: cannot stat '/[...]/debian/build/tools-perarch/tools/bpf/bpftool/vmlinux': No such file or directory
make: *** [debian/rules.d/2-binary-arch.mk:749: /[...]/debian/stamps/stamp-build-perarch] Error 1
Not the first problem with bpftool, unfortunately.
I have looked for the log file of the build, and could not find it, having grepped the whole directory with
$ find . -type f -exec fgrep -Il bpftool/vmlinux {} \;
$
What is shown is a top-level view only:
CC pmu-events/pmu-events.o
LD util/perf-in.o
LD perf-in.o
LD pmu-events/pmu-events-in.o
LINK perf
I wonder how to enable a full build log. In the early days I used the straightforward:
$ make 2>&1 | tee build.log
[...]
Maybe it is not helpful to have it and just a waste of space, just I have thought about it because I am stuck. mv cannot move a file, but I have not seen an error message before that and could not even see what happened.
I have written a script restore.sh
which uses rsync to remove all changes and applies the two patches to let me try the build again. But I know that git can help with it as well.
This is my personal experience so far, kernel rebuild not a quickie at all after a prolonged break.