Next: Guix System Image API, Previous: 특정한 TTY로 자동-로그인, Up: 시스템 설정 [Contents][Index]
Guix is, at its core, a source based distribution with substitutes (see Substitutes in GNU Guix Reference Manual), and as such building packages from their source code is an expected part of regular package installations and upgrades. Given this starting point, it makes sense that efforts are made to reduce the amount of time spent compiling packages, and recent changes and upgrades to the building and distribution of substitutes continues to be a topic of discussion within Guix.
The kernel, while not requiring an overabundance of RAM to build, does take a rather long time on an average machine. The official kernel configuration, as is the case with many GNU/Linux distributions, errs on the side of inclusiveness, and this is really what causes the build to take such a long time when the kernel is built from source.
The Linux kernel, however, can also just be described as a regular old package, and as such can be customized just like any other package. The procedure is a little bit different, although this is primarily due to the nature of how the package definition is written.
The linux-libre
kernel package definition is actually a procedure
which creates a package.
(define* (make-linux-libre* version gnu-revision source supported-systems
#:key
(extra-version #f)
;; A function that takes an arch and a variant.
;; See kernel-config for an example.
(configuration-file #f)
(defconfig "defconfig")
(extra-options (default-extra-linux-options version)))
...)
The current linux-libre
package is for the 5.15.x series, and is
declared like this:
(define-public linux-libre-5.15
(make-linux-libre* linux-libre-5.15-version
linux-libre-5.15-gnu-revision
linux-libre-5.15-source
'("x86_64-linux" "i686-linux" "armhf-linux"
"aarch64-linux" "riscv64-linux")
#:configuration-file kernel-config))
Any keys which are not assigned values inherit their default value from the
make-linux-libre
definition. When comparing the two snippets above,
notice the code comment that refers to #:configuration-file
. Because
of this, it is not actually easy to include a custom kernel configuration
from the definition, but don’t worry, there are other ways to work with what
we do have.
There are two ways to create a kernel with a custom kernel configuration.
The first is to provide a standard .config file during the build
process by including an actual .config file as a native input to our
custom kernel. The following is a snippet from the custom 'configure
phase of the make-linux-libre
package definition:
(let ((build (assoc-ref %standard-phases 'build))
(config (assoc-ref (or native-inputs inputs) "kconfig")))
;; Use a custom kernel configuration file or a default
;; configuration file.
(if config
(begin
(copy-file config ".config")
(chmod ".config" #o666))
(invoke "make" ,defconfig)))
Below is a sample kernel package. The linux-libre
package is nothing
special and can be inherited from and have its fields overridden like any
other package:
(define-public linux-libre/E2140
(package
(inherit linux-libre)
(native-inputs
`(("kconfig" ,(local-file "E2140.config"))
,@(alist-delete "kconfig"
(package-native-inputs linux-libre))))))
In the same directory as the file defining linux-libre-E2140
is a
file named E2140.config, which is an actual kernel configuration
file. The defconfig
keyword of make-linux-libre
is left blank
here, so the only kernel configuration in the package is the one which was
included in the native-inputs
field.
The second way to create a custom kernel is to pass a new value to the
extra-options
keyword of the make-linux-libre
procedure. The
extra-options
keyword works with another function defined right below
it:
(define (default-extra-linux-options version) `(;; https://lists.gnu.org/archive/html/guix-devel/2014-04/msg00039.html ("CONFIG_DEVPTS_MULTIPLE_INSTANCES" . #true) ;; Modules required for initrd: ("CONFIG_NET_9P" . m) ("CONFIG_NET_9P_VIRTIO" . m) ("CONFIG_VIRTIO_BLK" . m) ("CONFIG_VIRTIO_NET" . m) ("CONFIG_VIRTIO_PCI" . m) ("CONFIG_VIRTIO_BALLOON" . m) ("CONFIG_VIRTIO_MMIO" . m) ("CONFIG_FUSE_FS" . m) ("CONFIG_CIFS" . m) ("CONFIG_9P_FS" . m))) (define (config->string options) (string-join (map (match-lambda ((option . 'm) (string-append option "=m")) ((option . #true) (string-append option "=y")) ((option . #false) (string-append option "=n"))) options) "\n"))
And in the custom configure script from the ‘make-linux-libre‘ package:
;; Appending works even when the option wasn't in the ;; file. The last one prevails if duplicated. (let ((port (open-file ".config" "a")) (extra-configuration ,(config->string extra-options))) (display extra-configuration port) (close-port port)) (invoke "make" "oldconfig")
So by not providing a configuration-file the .config starts blank, and then we write into it the collection of flags that we want. Here’s another custom kernel:
(define %macbook41-full-config (append %macbook41-config-options %file-systems %efi-support %emulation ((@@ (gnu packages linux) default-extra-linux-options) version))) (define-public linux-libre-macbook41 ;; XXX: Access the internal 'make-linux-libre*' procedure, which is ;; private and unexported, and is liable to change in the future. ((@@ (gnu packages linux) make-linux-libre*) (@@ (gnu packages linux) linux-libre-version) (@@ (gnu packages linux) linux-libre-gnu-revision) (@@ (gnu packages linux) linux-libre-source) '("x86_64-linux") #:extra-version "macbook41" #:extra-options %macbook41-config-options))
In the above example %file-systems
is a collection of flags enabling
different file system support, %efi-support
enables EFI support and
%emulation
enables a x86_64-linux machine to act in 32-bit mode
also. The default-extra-linux-options
procedure is the one defined
above, which had to be used to avoid loosing the default configuration
options of the extra-options
keyword.
This all sounds like it should be doable, but how does one even know which
modules are required for a particular system? Two places that can be helpful
in trying to answer this question is the
Gentoo Handbook and the
documentation from the kernel itself. From the kernel documentation, it
seems that make localmodconfig
is the command we want.
In order to actually run make localmodconfig
we first need to get and
unpack the kernel source code:
tar xf $(guix build linux-libre --source)
Once inside the directory containing the source code run touch
.config
to create an initial, empty .config to start with.
make localmodconfig
works by seeing what you already have in
.config and letting you know what you’re missing. If the file is
blank then you’re missing everything. The next step is to run:
guix shell -D linux-libre -- make localmodconfig
and note the output. Do note that the .config file is still empty. The output generally contains two types of warnings. The first start with "WARNING" and can actually be ignored in our case. The second read:
module pcspkr did not have configs CONFIG_INPUT_PCSPKR
For each of these lines, copy the CONFIG_XXXX_XXXX
portion into the
.config in the directory, and append =m
, so in the end it
looks like this:
CONFIG_INPUT_PCSPKR=m CONFIG_VIRTIO=m
After copying all the configuration options, run make localmodconfig
again to make sure that you don’t have any output starting with “module”.
After all of these machine specific modules there are a couple more left
that are also needed. CONFIG_MODULES
is necessary so that you can
build and load modules separately and not have everything built into the
kernel. CONFIG_BLK_DEV_SD
is required for reading from hard drives.
It is possible that there are other modules which you will need.
This post does not aim to be a guide to configuring your own kernel however, so if you do decide to build a custom kernel you’ll have to seek out other guides to create a kernel which is just right for your needs.
The second way to setup the kernel configuration makes more use of Guix’s features and allows you to share configuration segments between different kernels. For example, all machines using EFI to boot have a number of EFI configuration flags that they need. It is likely that all the kernels will share a list of file systems to support. By using variables it is easier to see at a glance what features are enabled and to make sure you don’t have features in one kernel but missing in another.
Left undiscussed however, is Guix’s initrd and its customization. It is likely that you’ll need to modify the initrd on a machine using a custom kernel, since certain modules which are expected to be built may not be available for inclusion into the initrd.
Next: Guix System Image API, Previous: 특정한 TTY로 자동-로그인, Up: 시스템 설정 [Contents][Index]