1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
#!/usr/bin/env bash
# Copyright (C) 2024-Ω Miquel Sabaté Solà <mikisabate@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#####
# Build the Linux Kernel and bundle it into a tarball that can then be used on
# another machine. After you call this script it will:
# 1. Either call `defconfig` or re-use an existing .config as per user request.
# 2. Call `menuconfig` so the user can double check the configuration.
# 3. Build the Kernel.
# 4. Copy into a tarball the resulting image, modules, dtbs, and headers. An
# install.sh script is also bundled in.
#
# After that just send the resulting tarball to the machine where you want to
# install this kernel. In there you just need to untar the given bundle and then
# run the `install.sh` script from within the resulting directory. This will:
# 1. Copy recursively all the files into their proper paths.
# 2. Make an initramfs for the new image.
# 3. Run your $EDITOR to update the /boot/extlinux/extlinux.conf file.
#
# *NOTE*: this script expects the `ARCH` environment variable to be set, and if
# that doesn't match the current architecture, then it will expect to have
# `CROSS_COMPILE` set as well.
# *NOTE*: because of the funny machines I'm testing this in, only Debian was
# tested. Hence, we assume tools such as `update-initramfs` exist instead of
# using `dracut`.
#####
set -e
##
# Initial checks.
# Most of the times, we are safer if we just set the `ARCH` env. variable.
if [ -z "$ARCH" ]; then
echo "kbuild (error): \$ARCH has to be defined."
exit 1
fi
# Is cross compilation the thing we want?
if [ "$ARCH" != "$(uname -m)" ]; then
# Confusingly enough, riscv64 is supposed to be passed as 'riscv' to the
# kernel. Hence, don't take that as being different.
if [ "$(uname -m)" != "riscv64" ] || [ "$ARCH" != "riscv" ]; then
# We are indeed cross compiling. If `CROSS_COMPILE` is not set at this
# point we should raise an error.
if [ -z "$CROSS_COMPILE" ]; then
echo "kbuild (error): \$CROSS_COMPILE has to be defined."
exit 1
fi
fi
fi
# To avoid embarrassing moments, let's make sure that we are in the Linux repo.
if [ ! -f "Kbuild" ]; then
echo "kbuild (error): we are not in the Linux Kernel."
exit 1
fi
##
# .config
if [ ! -f ".config" ]; then
echo "kbuild (info): no '.config' file found"
make defconfig
fi
config_options=("From a default configuration (defconfig)" "From an existing .config file")
echo "kconfig (info): how do you want to configure the build?"
PS3="> "
select _opt in "${config_options[@]}" "Quit"; do
case "$REPLY" in
1)
make defconfig
echo "kbuild (info): running 'menuconfig' to double check."
make menuconfig
break
;;
2)
echo "kbuild (info): running 'menuconfig' to double check."
make menuconfig
break
;;
3)
echo "kbuild (info): bye!"
exit 0
;;
*)
echo "kbuild (info): not an option. Try again..."
continue
;;
esac
done
##
# Build the kernel.
echo "kbuild (info): building the Linux kernel..."
make -j "$(nproc)"
##
# Installing into a local bundle.
name=$(cat include/config/kernel.release)
if [ -z "$INSTALL_PATH" ]; then
INSTALL_PATH="buildroot-$name"
fi
mkdir -p "$INSTALL_PATH/usr/lib/modules/$name"
pushd "$INSTALL_PATH" >/dev/null
ln -s usr/lib lib
popd >/dev/null
make modules_install INSTALL_MOD_PATH="$INSTALL_PATH"
make dtbs_install INSTALL_DTBS_PATH="$INSTALL_PATH/boot/dtbs/$name"
make headers_install INSTALL_HDR_PATH="$INSTALL_PATH/usr"
unlink "$INSTALL_PATH/lib"
cp "arch/$ARCH/boot/Image.gz" "$INSTALL_PATH/boot/vmlinuz-$name"
cp .config "$INSTALL_PATH/boot/config-$name"
##
# Setup install.sh script.
cat <<SCRIPT > "$INSTALL_PATH/install.sh"
#!/usr/bin/env bash
set -ex
if [ "\$EUID" -ne 0 ];then
echo "kbuild (error): run this as root."
exit 1
fi
if [ ! -f /sbin/update-initramfs ] && [ ! -f /usr/bin/dracut ]; then
echo "kbuild (error): you need either 'dracut' or 'update-initramfs'."
exit 1
fi
cp -rv usr /
cp -rv boot /
export PATH=/sbin:\$PATH
if command -v dracut &> /dev/null
then
dracut --kver=$name -f
else
update-initramfs -k $name -u
fi
if [ -z "\$EDITOR" ]; then
EDITOR=vi
fi
\$EDITOR /boot/extlinux/extlinux.conf
SCRIPT
##
# Create tarball.
tar czf "$INSTALL_PATH.tar.gz" "$INSTALL_PATH"
rm -r "$INSTALL_PATH"
echo "kbuild (info): your build is now ready at '$INSTALL_PATH.tar.gz'."
|