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