-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfunctions
executable file
·615 lines (502 loc) · 16.7 KB
/
functions
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
#!/usr/bin/env bash
#
# SPDX-License-Identifier: MIT
# Copyright (C) 2023 Utsav Balar
# Copyright (C) 2023 Vicharak Computers LLP
#
# Core functions for the Vicharak kernel build script
#
# Source common utility functions from the "vicharak/utils" script.
# This script must be in the same directory as the "vicharak" script
# shellcheck disable=SC1090
source "${SCRIPT_DIR}"/utils
# Create an extlinux configuration file based on device-specific parameters.
function create_extlinux_config() {
local extlinux_dir=${1}
echo \
"label Vicharak ${DEVICE_NAME} kernel" >"${extlinux_dir}"/extlinux.conf
# shellcheck disable=SC2129
echo -e \
"\tkernel /Image-${KERNEL_VERSION}" >>"${extlinux_dir}"/extlinux.conf
echo -e "\tfdt /${DEVICE_DTB_FILE}.dtb" >>"${extlinux_dir}"/extlinux.conf
echo -e "\tappend earlycon=uart8250,mmio32,0xff1a0000 swiotlb=65536 coherent_pool=1m earlyprintk console=ttyS2,1500000n8 rw root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9 rootfstype=ext4 init=/sbin/init rootwait audit=0 splash" >>"${extlinux_dir}"/extlinux.conf
}
# Check if the boot image file exists and if its size is less than 30MB.
# If so, exit with an error message; otherwise, print a success message.
function check_image_build() {
if [[ -f "${FILENAME}" ]] &&
[[ "$(stat -c%s "${FILENAME}")" -lt $((30 * 1024 * 1024)) ]]; then
exit_with_error "Boot image size is less than 30MB"
else
print "----------------------------------------------------------------"
print "Build successful!"
print "----------------------------------------------------------------"
fi
}
# Pack the kernel image and device tree binary (dtb) file into a boot image
# using extlinux as the default bootloader method for kernel loading on ARM64
# devices. Also, copy other required files.
# mtools package is used for copying files into the boot image
function pack_image() {
delete_file "${FILENAME}"
if ! is_set "${DEVICE_KERNEL_IMAGE_FILE_SIZE}"; then
DEVICE_KERNEL_IMAGE_FILE_SIZE=50
fi
mkfs.fat \
-n "boot" -C "${FILENAME}" $((DEVICE_KERNEL_IMAGE_FILE_SIZE * 1024))
extlinux_dir=$(mktemp -d)
create_extlinux_config "${extlinux_dir}"
cd "${OUT_DIR}" || exit
if ! command -v mcopy &>/dev/null; then
exit_with_error "mtools not found!, install mtools to continue"
fi
mmd -i "${FILENAME}" ::/extlinux
mcopy -i "${FILENAME}" -s \
"${extlinux_dir}/extlinux.conf" ::/extlinux/extlinux.conf
mcopy -i "${FILENAME}" -s \
"${DEVICE_KERNEL_IMAGE_FILE}" ::/Image-"${KERNEL_VERSION}"
if [ -f "${KERNEL_DIR}"/logo.bmp ]; then
mcopy -i "${FILENAME}" -s "${KERNEL_DIR}"/logo.bmp ::
fi
if [ -f "${KERNEL_DIR}"/logo_kernel.bmp ]; then
mcopy -i "${FILENAME}" -s "${KERNEL_DIR}"/logo_kernel.bmp ::
fi
if [[ -d "${DEVICE_DTB_DIR}"/overlays ]]; then
mmd -i "${FILENAME}" ::/overlays
for dtbo in "${DEVICE_DTB_DIR}"/overlays/*; do
mcopy -i "${FILENAME}" -s "${dtbo}" ::/overlays
done
fi
if [ ! -f "${DEVICE_DTB_DIR}"/"${DEVICE_DTB_FILE}".dtb ]; then
exit_with_error "Device tree binary: ${DEVICE_DTB_FILE}.dtb not found!"
fi
mcopy -i "${FILENAME}" -s "${DEVICE_DTB_DIR}"/"${DEVICE_DTB_FILE}".dtb ::
delete_dir "${extlinux_dir}"
check_image_build
cd "${KERNEL_DIR}" || exit
}
# Clean up previous build files and directories to prepare for a fresh build.
# these includes dtb, bootimage, Image, extlinux and modules
function cleanup() {
source_toolchain
delete_file "${FILENAME}"
delete_file "${DEVICE_KERNEL_IMAGE_FILE}"
delete_file "${DEVICE_DTB_FILE}"
delete_dir "${OUT_DIR}"/extlinux
delete_dir "${OUT_DIR}"/modules_"${DEVICE_NAME}"
# shellcheck disable=SC2086
make ${kernel_args} clean && make ${kernel_args} mrproper
}
# Check the version of the GNU C Library (GLIBC) and determine if it meets
# the required version. This is required to use latest GCC and Clang compilers
# because the newer GCC requires >= 2.34 glibc
function new_system_glibc() {
local glibc_version
glibc_version=$(ldd --version | awk '/ldd/{print $NF}' | sed 's/\.//g')
# check if GLIBC version is greater than 2.33
if [[ "${glibc_version}" -gt 233 ]]; then
return 0
fi
return 1
}
# Helper function to download and extract GCC or Clang toolchains
# Args:
# $1: Toolchain name (e.g., "GCC" or "Clang")
# $2: Toolchain version (e.g., "10.0.0" or "12")
# $3: Repository source ("github" or "gitlab")
# $4: Repository owner
# $5: Repository name
# $6: Destination directory
function download_toolchain() {
local tc_name="$1"
local tc_version="$2"
local repo_source="$3"
local repo_owner="$4"
local repo_name="$5"
local dest_dir="$6"
if [[ ! -d "${dest_dir}" ]]; then
mkdir -p "${dest_dir}"
fi
local tc_file="${dest_dir}/${tc_name}-${tc_version}.tar.gz"
if [[ -d "${dest_dir}" && -f "${tc_file}" ]]; then
print "${tc_name} ${tc_version} already downloaded."
else
print "Downloading ${tc_name} ${tc_version}..."
local download_url
local git_url
git_url="https://gitlab.com/${repo_owner}/${repo_name}"
if [[ "${repo_source}" == "github" ]]; then
download_url="${git_url}/archive/${tc_version}.tar.gz"
elif [[ "${repo_source}" == "gitlab" ]]; then
download_url="${git_url}/-/archive/${tc_version}/${repo_name}-${tc_version}.tar.gz"
else
exit_with_error "Invalid repository source: ${repo_source}"
fi
wget -O "${tc_file}" \
"${download_url}" -q --show-progress --progress=bar:force 2>&1
# shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
exit_with_error "Failed to download ${tc_name} ${tc_version}."
fi
print "Downloaded ${tc_name} ${tc_version} successfully."
print "Extracting ${tc_name} ${tc_version}..."
tar -xzf "${tc_file}" -C "${dest_dir}"
# shellcheck disable=SC2181
if [[ $? -ne 0 ]]; then
exit_with_error "Failed to extract ${tc_name} ${tc_version}."
fi
mv "${dest_dir}"/"${repo_name}"-"${tc_version}"/* "${dest_dir}"
delete_file "${tc_file}"
delete_dir "${dest_dir}"/"${repo_name}"-"${tc_version}"
print "Extracted ${tc_name} ${tc_version} successfully."
fi
}
# Download and set up a standalone clang toolchain from a specified source.
function get_clang_toolchain() {
if [[ -z "${1}" ]]; then
exit_with_error "Failed to get clang toolchain"
fi
local clang_version
clang_version=${1}
if ! is_set "${clang_version}"; then
exit_with_error "Clang version Not set!"
fi
if [[ ! -d "${CLANG_DIR}" ]]; then
download_toolchain "Clang-${clang_version}" "${clang_version}" \
"gitlab" "ThankYouMario" "android_prebuilts_clang-standalone" \
"${CLANG_DIR}"
else
local local_clang_version
if [[ -f "${CLANG_DIR}"/AndroidVersion.txt ]]; then
local_clang_version=$(
sed '2,$d' "${CLANG_DIR}"/AndroidVersion.txt | cut -d '.' -f 1
)
fi
if [[ ${local_clang_version} -ne ${clang_version} ]] ||
[[ -z "${local_clang_version}" ]]; then
delete_dir "${CLANG_DIR}"
get_clang_toolchain "${clang_version}"
fi
fi
}
# Set up environment variables for building with Clang,
# including the path to the toolchain.
function build_clang() {
local available_clang_versions=()
local clang_version
if is_set "${DEVICE_CLANG_VERSION}"; then
if [[ ! ${DEVICE_CLANG_VERSION} =~ ^[0-9]+$ ]]; then
exit_with_error "Invalid clang version: ${DEVICE_CLANG_VERSION}"
fi
if [[ ${DEVICE_CLANG_VERSION} -lt ${DEFAULT_CLANG_VERSION} ]]; then
exit_with_error \
"Invalid clang version, must be >= ${DEFAULT_CLANG_VERSION}"
fi
clang_version=${DEVICE_CLANG_VERSION}
else
clang_version=${DEFAULT_CLANG_VERSION}
fi
available_clang_versions=(12 13 14 15 16 17)
if [[ ! " ${available_clang_versions[*]} " =~ ${clang_version} ]]; then
exit_with_error "Invalid clang version: ${clang_version}"
fi
# check if clang is installed
if command -v clang &>/dev/null; then
local system_clang_version
system_clang_version=$(
clang --version | head -n1 | awk '{print $3}' | cut -d'.' -f1
)
if [[ -z "${system_clang_version}" ]]; then
exit_with_error "Failed to get clang version"
fi
if [[ "${system_clang_version}" =~ ^[0-9]+$ ]]; then
if [[ ${system_clang_version} -lt ${DEFAULT_CLANG_VERSION} ]]; then
get_clang_toolchain "${clang_version}"
fi
fi
else
# No clang toolchain found! download it
get_clang_toolchain "${clang_version}"
fi
# set up environment variables, so standalone clang can be used
if [ -d "${CLANG_DIR}" ]; then
print "----------------------------------------------------------------"
print "Using standalone clang toolchain: ${clang_version}"
print "----------------------------------------------------------------"
PATH="${CLANG_DIR}"/bin:${PATH}
LD_LIBRARY_PATH="${CLANG_DIR}"/lib:${LD_LIBRARY_PATH}
export PATH
fi
if ! is_set "${CROSS_COMPILE}" && [[ "${DEVICE_ARCH}" == "arm64" ]]; then
export CROSS_COMPILE=aarch64-linux-gnu-
fi
kernel_args="ARCH=${DEVICE_ARCH} \
O=${OUT_DIR} \
LLVM=1 \
LLVM_IAS=1 \
-j$(nproc --all)"
export kernel_args
}
# Set up environment variables for building with GCC,
# including the path to the toolchain.
function build_gcc() {
# Check if GLIBC version is greater than 2.33
if new_system_glibc; then
if [[ ! -d "${GCC64_DIR}" ]]; then
if [[ "${DEVICE_ARCH}" == "arm64" ]]; then
download_toolchain "Baremetal GCC ${DEVICE_ARCH}" \
"gcc-master" "github" "mvaisakh" \
"mvaisakh/gcc-${DEVICE_ARCH}" "${GCC64_DIR}"
export PATH="${GCC64_DIR}"/bin:${PATH}
export CROSS_COMPILE=aarch64-elf-
fi
fi
if [[ ! -d "${GCC32_DIR}" ]]; then
if [[ "${DEVICE_ARCH}" == "arm64" ]]; then
download_toolchain "Baremetal GCC ARM32" \
"gcc-master" "github" "mvaisakh" "mvaisakh/gcc-arm" \
"${GCC32_DIR}"
export PATH="${GCC32_DIR}"/bin:${PATH}
export CROSS_COMPILE_COMPAT=arm-eabi-
fi
fi
if ! is_set ${CROSS_COMPILE} && [[ "${DEVICE_ARCH}" == "arm64" ]]; then
export CROSS_COMPILE=aarch64-linux-gnu-
fi
kernel_args="ARCH=${DEVICE_ARCH} \
O=${OUT_DIR} \
-j$(nproc --all)"
else
print "----------------------------------------------------------------"
print "Using System GCC"
print "----------------------------------------------------------------"
if ! is_set ${CROSS_COMPILE} &&
command -v aarch64-linux-gnu-gcc &>/dev/null &&
[[ "${DEVICE_ARCH}" == "arm64" ]]; then
export CROSS_COMPILE=aarch64-linux-gnu-
fi
if command -v gcc-arm-linux-gnueabi &>/dev/null &&
[[ "${DEVICE_ARCH}" == "arm64" ]]; then
export CROSS_COMPILE_COMPAT=arm-linux-gnueabi-
fi
kernel_args="ARCH=${DEVICE_ARCH} \
O=${OUT_DIR} \
-j$(nproc --all)"
fi
export kernel_args
}
# Create the kernel configuration (defconfig) based on the performance options
# and merge it with the config fragment if specified.
function build_config() {
# shellcheck disable=SC2086
make ${kernel_args} "${DEVICE_DEFCONFIG}"
local arch
if [[ "${DEVICE_ARCH}" == "x86_64" ]]; then
arch="x86"
else
arch="${DEVICE_ARCH}"
fi
local cfg_fragment
cfg_fragment="${KERNEL_DIR}/arch/${arch}/configs/${DEVICE_CONFIG_FRAGMENT}"
if [[ ! -f "${cfg_fragment}" ]]; then
print "----------------------------------------------------------------"
print "${DEVICE_CONFIG_FRAGMENT} File not found!"
print "----------------------------------------------------------------"
else
cat "${cfg_fragment}" >>"${OUT_DIR}"/.config
fi
if is_enabled "${PERF_BUILD}"; then
if [ -f "${KERNEL_DIR}/arch/${arch}/configs/performance.config" ]; then
cat \
"${KERNEL_DIR}"/arch/"${arch}"/configs/performance.config \
>>"${OUT_DIR}"/.config
else
exit_with_error "Performance config not found!"
fi
fi
}
# Build kernel modules and create a GZIP compressed archive of the modules.
function build_modules() {
source_toolchain
if [[ ! -f "${OUT_DIR}"/.config ]]; then
build_config
fi
# shellcheck disable=SC2086
make ${kernel_args} \
modules_install INSTALL_MOD_PATH="${OUT_DIR}"/modules_"${DEVICE_NAME}"
tar -czf "${OUT_DIR}"/modules_"${DEVICE_NAME}".tar.gz \
-C "${OUT_DIR}"/modules_"${DEVICE_NAME}" .
}
# Build a Debian package for the kernel
function build_kerneldeb() {
source_toolchain
if [[ ! -f "${OUT_DIR}"/.config ]]; then
build_config
fi
build_kernel_deb_package
}
# Build a Debian package for the kernel with the specified parameters.
function build_kernel_deb_package() {
local build_id
local deb_files
local build_device_name
build_device_name=$(echo "${DEVICE_NAME}" | cut -d'_' -f2)
build_id="$(date +%Y%m%d)-${build_device_name}"
# shellcheck disable=SC2086
make ${kernel_args} bindeb-pkg \
KDEB_PKGVERSION="${build_id}" \
KDEB_COMPRESS="xz" \
RK_KERNEL_DTS="${DEVICE_DTB_FILE}" \
LOCALVERSION="-${build_device_name}"
deb_files=$(find "${KERNEL_DIR}" -maxdepth 1 -name "linux-*")
if is_set "${deb_files}"; then
for deb_file in ${deb_files}; do
mv "${deb_file}" "${OUT_DIR}"/
done
else
exit_with_error "Deb package build failed!"
fi
}
# Build device tree blobs (dtbs) for the kernel.
function build_dtbs() {
source_toolchain
if [[ ! -f "${OUT_DIR}"/.config ]]; then
build_config
fi
# shellcheck disable=SC2086
make dtbs ${kernel_args}
}
# Determine and set up the selected toolchain (Clang or GCC) for building the
# kernel.
function source_toolchain() {
if is_enabled "${CLANG_BUILD}"; then
print "----------------------------------------------------------------"
print "Building with Clang"
print "----------------------------------------------------------------"
build_clang
else
print "----------------------------------------------------------------"
print "Building with GCC"
print "----------------------------------------------------------------"
build_gcc
fi
}
# Build the kernel image and
# optionally modules, kernel deb package, or pack it into a boot image.
function build_kernel() {
source_toolchain
build_config
# shellcheck disable=SC2086
make ${kernel_args}
if [ -n "${DEVICE_DTB_FILE}" ]; then
# shellcheck disable=SC2086
make ${kernel_args} dtbs
fi
if is_enabled "${MODULES_BUILD}"; then
build_modules
fi
if is_enabled "${DEB_BUILD}"; then
build_kernel_deb_package
fi
if is_enabled "${PACK_KERNEL_BUILD}"; then
pack_image
fi
}
# Update the kernel configuration (defconfig) with savedefconfig.
function update_defconfig() {
source_toolchain
if [[ ! -f "${OUT_DIR}"/.config ]]; then
build_config
fi
# shellcheck disable=SC2086
make ${kernel_args} "${DEVICE_DEFCONFIG}"
# shellcheck disable=SC2086
make ${kernel_args} savedefconfig
local arch
if [[ "${DEVICE_ARCH}" == "x86_64" ]]; then
arch="x86"
else
arch="${DEVICE_ARCH}"
fi
mv "${OUT_DIR}"/defconfig \
"${KERNEL_DIR}"/arch/"${arch}"/configs/"${DEVICE_DEFCONFIG}"
print "----------------------------------------------------------------"
print "Updated ${DEVICE_DEFCONFIG} with savedefconfig"
print "----------------------------------------------------------------"
}
# Print information about the selected device and build configuration.
function print_info() {
# shellcheck disable=SC1090,SC1091
if [[ -f "${SCRIPT_DIR}/.device.mk" ]]; then
source "${SCRIPT_DIR}/.device.mk"
else
lunch_device
fi
print "----------------------------------------------------------------"
print "Device Information"
print "----------------------------------------------------------------"
if ! is_set "${DEVICE_DEFCONFIG}"; then
DEVICE_MAKEFILE="${DEVICE_NAME}.mk"
fi
print "Device Makefile: ${DEVICE_MAKEFILE}"
print "Device Name: ${DEVICE_NAME}"
print "Device Defconfig: ${DEVICE_DEFCONFIG}"
if is_set "${DEVICE_CONFIG_FRAGMENT}"; then
print "Device Config Fragment: ${DEVICE_CONFIG_FRAGMENT}"
fi
if is_set "${DEVICE_DTB_FILE}"; then
print "Device DTB: ${DEVICE_DTB_FILE}"
fi
if is_enabled "${CLANG_BUILD}"; then
print "Device Compiler: Clang"
else
print "Device Compiler: GCC"
fi
if is_enabled "${PERF_BUILD}"; then
print "Device Config: Performance config"
fi
if is_enabled "${MODULES_BUILD}"; then
print "Build kernel modules: Yes"
else
print "Build Kernel Modules: No"
fi
if is_enabled "${DEB_BUILD}"; then
print "Build Debian package: Yes"
else
print "Build Debian package: No"
fi
usage
}
# Allow the user to select a device configuration file interactively.
function set_device_config() {
print "----------------------------------------------------------------"
pushd "${SCRIPT_DIR}" || exit 1
printf "\e[1;32m"
select device in *.mk; do
DEVICE_MAKEFILE="${device}"
break
done
popd || exit 1
printf "\e[0m"
print "----------------------------------------------------------------"
}
# Check if a device configuration file exists; if not,
# prompt the user to set one.
function check_lunch_device() {
if [[ ! -f "${SCRIPT_DIR}/.device.mk" ]]; then
lunch_device
fi
}
# Prompt the user to select a device configuration file and set it as the
# active configuration.
function lunch_device() {
delete_file "${SCRIPT_DIR}/.device.mk"
set_device_config
ln -sf "${SCRIPT_DIR}/${DEVICE_MAKEFILE}" "${SCRIPT_DIR}/.device.mk"
# shellcheck disable=SC1090,SC1091
source "${SCRIPT_DIR}/.device.mk"
if ! is_set "${DEVICE_DEFCONFIG}"; then
exit_with_error "Device defconfig not set!"
fi
}
# End of script