xref: /OK3568_Linux_fs/build.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#!/bin/bash
2
3if [ -z "$BASH_SOURCE" ]; then
4	echo "Not in bash, switching to it..."
5	case "${@:-shell}" in
6		shell) ./build.sh shell ;;
7		*)
8			./build.sh $@
9			bash
10			;;
11	esac
12fi
13
14usage()
15{
16	echo "Usage: $(basename $BASH_SOURCE) [OPTIONS]"
17	echo "Available options:"
18
19	run_build_hooks usage
20
21	# Global options
22	echo -e "cleanall                          \tcleanup"
23	echo -e "post-rootfs <rootfs dir>          \ttrigger post-rootfs hook scripts"
24	echo -e "shell                             \tsetup a shell for developing"
25	echo -e "help                              \tusage"
26	echo ""
27	echo "Default option is 'allsave'."
28
29	rm -f "$INITIAL_ENV"
30	exit 0
31}
32
33err_handler()
34{
35	ret=${1:-$?}
36	[ "$ret" -eq 0 ] && return
37
38	echo "ERROR: Running $BASH_SOURCE - ${2:-${FUNCNAME[1]}} failed!"
39	echo "ERROR: exit code $ret from line ${BASH_LINENO[0]}:"
40	echo "    ${3:-$BASH_COMMAND}"
41	echo "ERROR: call stack:"
42	for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do
43		SOURCE="${BASH_SOURCE[$i]}"
44		LINE=${BASH_LINENO[$(( $i - 1 ))]}
45		echo "    $(basename "$SOURCE"): ${FUNCNAME[$i]}($LINE)"
46	done
47	exit $ret
48}
49
50# Export global functions
51set -a
52
53finish_build()
54{
55	echo -e "\e[35mRunning $(basename "${BASH_SOURCE[1]}") - ${@:-${FUNCNAME[1]}} succeeded.\e[0m"
56	cd "$SDK_DIR"
57}
58
59load_config()
60{
61	[ -r "$RK_CONFIG" ] || return 0
62
63	for var in $@; do
64		export $(grep "^$var=" "$RK_CONFIG" | \
65			tr -d '"' || true) &>/dev/null
66	done
67}
68
69check_config()
70{
71	unset missing
72	for var in $@; do
73		eval [ \$$var ] && continue
74
75		missing="$missing $var"
76	done
77
78	[ -z "$missing" ] && return 0
79
80	echo "Skipping $(basename "${BASH_SOURCE[1]}") - ${FUNCNAME[1]} for missing configs: $missing."
81	return 1
82}
83
84kernel_version_real()
85{
86	[ -d kernel ] || return 0
87
88	VERSION_KEYS="VERSION PATCHLEVEL"
89	VERSION=""
90
91	for k in $VERSION_KEYS; do
92		v=$(grep "^$k = " kernel/Makefile | cut -d' ' -f3)
93		VERSION=${VERSION:+${VERSION}.}$v
94	done
95	echo $VERSION
96}
97
98kernel_version()
99{
100	[ -d kernel ] || return 0
101
102	KERNEL_DIR="$(basename "$(realpath kernel)")"
103	case "$KERNEL_DIR" in
104		kernel-*)
105			echo ${KERNEL_DIR#kernel-}
106			return 0
107			;;
108	esac
109
110	kernel_version_real
111}
112
113start_log()
114{
115	LOG_FILE="$RK_LOG_DIR/${2:-$1_$(date +%F_%H-%M-%S)}.log"
116	ln -rsf "$LOG_FILE" "$RK_LOG_DIR/$1.log"
117	echo "# $(date +"%F %T")" >> "$LOG_FILE"
118	echo "$LOG_FILE"
119}
120
121get_toolchain()
122{
123	TOOLCHAIN_ARCH="${1/arm64/aarch64}"
124
125	MACHINE=$(uname -m)
126	if [ "$MACHINE" = x86_64 ]; then
127		TOOLCHAIN_VENDOR="${2:-none}"
128		TOOLCHAIN_OS="${3:-linux}"
129
130		# RV1126 uses custom toolchain
131		if [ "$RK_CHIP_FAMILY" = "rv1126_rv1109" ]; then
132			TOOLCHAIN_VENDOR=rockchip
133		fi
134
135		TOOLCHAIN_DIR="$(realpath prebuilts/gcc/*/$TOOLCHAIN_ARCH)"
136		GCC="$(find "$TOOLCHAIN_DIR" \
137			-name "*$TOOLCHAIN_VENDOR-$TOOLCHAIN_OS-*-gcc" | \
138			head -n 1)"
139		if [ ! -x "$GCC" ]; then
140			echo "No prebuilt GCC toolchain!"
141			exit 1
142		fi
143	elif [ "$TOLLCHAIN_ARCH" = aarch64 -a "$MACHINE" != aarch64 ]; then
144		GCC=aarch64-linux-gnu-gcc
145	elif [ "$TOLLCHAIN_ARCH" = arm -a "$MACHINE" != armv7l ]; then
146		GCC=arm-linux-gnueabihf-gcc
147	else
148		GCC=gcc
149	fi
150
151	echo "${GCC%gcc}"
152}
153
154# For developing shell only
155
156rroot()
157{
158	cd "$SDK_DIR"
159}
160
161rout()
162{
163	cd "$RK_OUTDIR"
164}
165
166rcommon()
167{
168	cd "$COMMON_DIR"
169}
170
171rscript()
172{
173	cd "$SCRIPTS_DIR"
174}
175
176rchip()
177{
178	cd "$(realpath "$CHIP_DIR")"
179}
180
181set +a
182# End of global functions
183
184run_hooks()
185{
186	DIR="$1"
187	shift
188
189	for dir in "$CHIP_DIR/$(basename "$DIR")/" "$DIR"; do
190		[ -d "$dir" ] || continue
191
192		for hook in $(find "$dir" -maxdepth 1 -name "*.sh" | sort); do
193			"$hook" $@ && continue
194			HOOK_RET=$?
195			err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$hook $*"
196			exit $HOOK_RET
197		done
198	done
199}
200
201run_build_hooks()
202{
203	# Don't log these hooks
204	case "$1" in
205		init | pre-build | make-* | usage | support-cmds)
206			run_hooks "$RK_BUILD_HOOK_DIR" $@ || true
207			return 0
208			;;
209	esac
210
211	LOG_FILE="$(start_log "$1")"
212
213	echo -e "# run hook: $@\n" >> "$LOG_FILE"
214	run_hooks "$RK_BUILD_HOOK_DIR" $@ 2>&1 | tee -a "$LOG_FILE"
215	HOOK_RET=${PIPESTATUS[0]}
216	if [ $HOOK_RET -ne 0 ]; then
217		err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$@"
218		exit $HOOK_RET
219	fi
220}
221
222run_post_hooks()
223{
224	LOG_FILE="$(start_log post-rootfs)"
225
226	echo -e "# run hook: $@\n" >> "$LOG_FILE"
227	run_hooks "$RK_POST_HOOK_DIR" $@ 2>&1 | tee -a "$LOG_FILE"
228	HOOK_RET=${PIPESTATUS[0]}
229	if [ $HOOK_RET -ne 0 ]; then
230		err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$@"
231		exit $HOOK_RET
232	fi
233}
234
235option_check()
236{
237	CMDS="$1"
238	shift
239
240	for opt in $@; do
241		for cmd in $CMDS; do
242			# NOTE: There might be patterns in commands
243			echo "${opt%%:*}" | grep -q "^$cmd$" || continue
244			return 0
245		done
246	done
247
248	return 1
249}
250
251main()
252{
253	[ -z "$DEBUG" ] || set -x
254
255	trap 'err_handler' ERR
256	set -eE
257
258	# Save intial envionments
259	unset INITIAL_SESSION
260	INITIAL_ENV=$(mktemp -u)
261	if [ -z "$RK_SESSION" ]; then
262		INITIAL_SESSION=1
263		env > "$INITIAL_ENV"
264	fi
265
266	export LC_ALL=C
267
268	export SCRIPTS_DIR="$(dirname "$(realpath "$BASH_SOURCE")")"
269	export COMMON_DIR="$(realpath "$SCRIPTS_DIR/..")"
270	export SDK_DIR="$(realpath "$COMMON_DIR/../../..")"
271	export DEVICE_DIR="$SDK_DIR/device/rockchip"
272	export CHIPS_DIR="$DEVICE_DIR/.chips"
273	export CHIP_DIR="$DEVICE_DIR/.chip"
274
275	export RK_DATA_DIR="$COMMON_DIR/data"
276	export RK_TOOL_DIR="$COMMON_DIR/tools"
277	export RK_IMAGE_DIR="$COMMON_DIR/images"
278	export RK_KBUILD_DIR="$COMMON_DIR/linux-kbuild"
279	export RK_CONFIG_IN="$COMMON_DIR/configs/Config.in"
280
281	export RK_BUILD_HOOK_DIR="$COMMON_DIR/build-hooks"
282	export BUILD_HELPER="$RK_BUILD_HOOK_DIR/build-helper"
283	export RK_POST_HOOK_DIR="$COMMON_DIR/post-hooks"
284	export POST_HELPER="$RK_POST_HOOK_DIR/post-helper"
285
286	export PARTITION_HELPER="$SCRIPTS_DIR/partition-helper"
287
288	export RK_SESSION="${RK_SESSION:-$(date +%F_%H-%M-%S)}"
289
290	export RK_OUTDIR="$SDK_DIR/output"
291	export RK_SESSION_DIR="$RK_OUTDIR/sessions"
292	export RK_LOG_BASE_DIR="$RK_OUTDIR/log"
293	export RK_LOG_DIR="$RK_SESSION_DIR/$RK_SESSION"
294	export RK_INITIAL_ENV="$RK_LOG_DIR/initial.env"
295	export RK_CUSTOM_ENV="$RK_LOG_DIR/custom.env"
296	export RK_FINAL_ENV="$RK_LOG_DIR/final.env"
297	export RK_ROCKDEV_DIR="$SDK_DIR/rockdev"
298	export RK_FIRMWARE_DIR="$RK_OUTDIR/firmware"
299	export RK_SECURITY_FIRMWARE_DIR="$RK_OUTDIR/security-firmware"
300	export RK_CONFIG="$RK_OUTDIR/.config"
301	export RK_DEFCONFIG_LINK="$RK_OUTDIR/defconfig"
302
303	# For Makefile
304	case "$@" in
305		make-targets | make-usage)
306			run_build_hooks "$@"
307			rm -f "$INITIAL_ENV"
308			exit 0 ;;
309	esac
310
311	# Prepare firmware dirs
312	mkdir -p "$RK_FIRMWARE_DIR" "$RK_SECURITY_FIRMWARE_DIR"
313
314	cd "$SDK_DIR"
315	[ -f README.md ] || ln -rsf "$COMMON_DIR/README.md" .
316
317	# TODO: Remove it in the repo manifest.xml
318	rm -f envsetup.sh
319
320	OPTIONS="${@:-allsave}"
321
322	# Options checking
323	CMDS="$(run_build_hooks support-cmds all | xargs)"
324	for opt in $OPTIONS; do
325		case "$opt" in
326			help | h | -h | --help | usage | \?) usage ;;
327			shell | cleanall)
328				# Check single options
329				if [ "$opt" = "$OPTIONS" ]; then
330					break
331				fi
332
333				echo "ERROR: $opt cannot combine with other options!"
334				;;
335			post-rootfs)
336				if [ "$opt" = "$1" -a -d "$2" ]; then
337					# Hide other args from build stages
338					OPTIONS=$opt
339					break
340				fi
341
342				echo "ERROR: $opt should be the first option followed by rootfs dir!"
343				;;
344			*)
345				# Make sure that all options are handled
346				if option_check "$CMDS" $opt; then
347					continue
348				fi
349
350				echo "ERROR: Unhandled option: $opt"
351				;;
352		esac
353
354		usage
355	done
356
357	# Prepare log dirs
358	if [ ! -d "$RK_LOG_DIR" ]; then
359		rm -rf "$RK_LOG_BASE_DIR" "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
360		mkdir -p "$RK_LOG_DIR"
361		ln -rsf "$RK_SESSION_DIR" "$RK_LOG_BASE_DIR"
362		ln -rsf "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
363		echo -e "\e[33mLog saved at $RK_LOG_DIR\e[0m"
364		echo
365	fi
366
367	# Drop old logs
368	cd "$RK_LOG_BASE_DIR"
369	rm -rf $(ls -t | sed '1,10d')
370	cd "$SDK_DIR"
371
372	# Save initial envionments
373	if [ "$INITIAL_SESSION" ]; then
374		rm -f "$RK_INITIAL_ENV"
375		mv "$INITIAL_ENV" "$RK_INITIAL_ENV"
376		ln -rsf "$RK_INITIAL_ENV" "$RK_OUTDIR/"
377	fi
378
379	# Init stage (preparing SDK configs, etc.)
380	run_build_hooks init $OPTIONS
381	rm -f "$RK_OUTDIR/.tmpconfig*"
382
383	# No need to go further
384	CMDS="$(run_build_hooks support-cmds pre-build build \
385		post-build | xargs) shell cleanall post-rootfs"
386	option_check "$CMDS" $OPTIONS || return 0
387
388	# Force exporting config environments
389	set -a
390
391	# Load config environments
392	source "$RK_CONFIG"
393	cp "$RK_CONFIG" "$RK_LOG_DIR"
394
395	if [ -z "$INITIAL_SESSION" ]; then
396		# Inherit session environments
397		sed -n 's/^\(RK_.*=\)\(.*\)/\1"\2"/p' "$RK_FINAL_ENV" > \
398			"$INITIAL_ENV"
399		source "$INITIAL_ENV"
400		rm -f "$INITIAL_ENV"
401	else
402		# Detect and save custom environments
403
404		# Find custom environments
405		rm -f "$RK_CUSTOM_ENV"
406		for cfg in $(grep "^RK_" "$RK_INITIAL_ENV" || true); do
407			env | grep -q "^${cfg//\"/}$" || \
408				echo "$cfg" >> "$RK_CUSTOM_ENV"
409		done
410
411		# Allow custom environments overriding
412		if [ -e "$RK_CUSTOM_ENV" ]; then
413			ln -rsf "$RK_CUSTOM_ENV" "$RK_OUTDIR/"
414
415			echo -e "\e[31mWARN: Found custom environments: \e[0m"
416			cat "$RK_CUSTOM_ENV"
417
418			echo -e "\e[31mAssuming that is expected, please clear them if otherwise.\e[0m"
419			read -t 10 -p "Press enter to continue."
420			source "$RK_CUSTOM_ENV"
421
422			if grep -q "^RK_KERNEL_VERSION=" "$RK_CUSTOM_ENV"; then
423				echo -e "\e[31mCustom RK_KERNEL_VERSION ignored!\e[0m"
424				load_config RK_KERNEL_VERSION
425			fi
426
427			if grep -q "^RK_ROOTFS_SYSTEM=" "$RK_CUSTOM_ENV"; then
428				echo -e "\e[31mCustom RK_ROOTFS_SYSTEM ignored!\e[0m"
429				load_config RK_ROOTFS_SYSTEM
430			fi
431		fi
432	fi
433
434	source "$PARTITION_HELPER"
435	rk_partition_init
436
437	set +a
438
439	export PYTHON3=/usr/bin/python3
440
441	if [ "$RK_KERNEL_CFG" ]; then
442		export RK_KERNEL_TOOLCHAIN="$(get_toolchain "$RK_KERNEL_ARCH")"
443
444		CPUS=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)
445		export KMAKE="make -C "$SDK_DIR/kernel/" -j$(( $CPUS + 1 )) \
446			CROSS_COMPILE=$RK_KERNEL_TOOLCHAIN ARCH=$RK_KERNEL_ARCH"
447
448		export RK_KERNEL_VERSION_REAL=$(kernel_version_real)
449	fi
450
451	# Handle special commands
452	case "$OPTIONS" in
453		shell)
454			echo -e "\e[35mDoing this is dangerous and for developing only.\e[0m"
455			# No error handling in develop shell.
456			set +e; trap ERR
457			/bin/bash
458			echo -e "\e[35mExit from $BASH_SOURCE shell.\e[0m"
459			exit 0 ;;
460		cleanall)
461			run_build_hooks clean
462			rm -rf "$RK_OUTDIR" "$SDK_DIR/rockdev"
463			finish_build cleanall
464			exit 0 ;;
465		post-rootfs)
466			shift
467			run_post_hooks $@
468			finish_build post-rootfs
469			exit 0 ;;
470	esac
471
472	# Save final environments
473	rm -f "$RK_FINAL_ENV"
474	env > "$RK_FINAL_ENV"
475	ln -rsf "$RK_FINAL_ENV" "$RK_OUTDIR/"
476
477	# Log configs
478	echo
479	echo "=========================================="
480	echo "          Final configs"
481	echo "=========================================="
482	env | grep -E "^RK_.*=.+" | grep -vE "PARTITION_[0-9]" | \
483		grep -vE "=\"\"$|_DEFAULT=y" | \
484		grep -vE "^RK_CONFIG|_BASE_CFG=|_LINK=|DIR=|_ENV=|_NAME=" | sort
485	echo
486
487	# Pre-build stage (submodule configuring, etc.)
488	run_build_hooks pre-build $OPTIONS
489
490	# No need to go further
491	CMDS="$(run_build_hooks support-cmds build post-build | xargs)"
492	option_check "$CMDS" $OPTIONS || return 0
493
494	# Build stage (building, etc.)
495	run_build_hooks build $OPTIONS
496
497	# No need to go further
498	CMDS="$(run_build_hooks support-cmds post-build | xargs)"
499	option_check "$CMDS" $OPTIONS || return 0
500
501	# Post-build stage (firmware packing, etc.)
502	run_build_hooks post-build $OPTIONS
503}
504
505if [ "$0" != "$BASH_SOURCE" ]; then
506	# Sourced, executing it directly
507	"$BASH_SOURCE" ${@:-shell}
508elif [ "$0" == "$BASH_SOURCE" ]; then
509	# Executed directly
510	main $@
511fi
512