学习shell之后,实战分析

#!/bin/bash

###############################################################################
#Variables
#查找project目录,以及子目录的所有文档!其中以"GCC/Makefile"结尾的!
export PROJECT_LIST=$(find project | grep "GCC/Makefile$")
#project下边所有的目录
export BOARD_LIST="project/*"
export OUT="$PWD/out"
export FLASHGENERATOR="tools/flashgen/flashgen.pl"
feature_mk=""

platform=$(uname)
# uname 得到 "Linux"
if [[ "$platform" =~ "MINGW" ]]; then  # =~表示包含子串
    export EXTRA_VAR=-j
else
    export EXTRA_VAR=-j`cat /proc/cpuinfo |grep ^processor|wc -l`
fi
###############################################################################
#Functions
show_usage () {
    echo "==============================================================="
    echo "Build Project"
    echo "==============================================================="
    echo "Usage: $0 <board> <project> [bl|clean] <argument>"
    echo ""
    echo "Example:"
    echo "       $0 mt7687_hdk iot_sdk_demo"
    echo "       $0 mt7687_hdk iot_sdk_demo bl      (build with bootloader)"
    echo "       $0 clean                      (clean folder: out)"
    echo "       $0 mt7687_hdk clean           (clean folder: out/mt7687_hdk)"
    echo "       $0 mt7687_hdk iot_sdk_demo clean   (clean folder: out/mt7687_hdk/iot_sdk_demo)"
    echo ""
    echo "Argument:"
    echo "       -f=<feature makefile> or --feature=<feature makefile>"
    echo "           Replace feature.mk with other makefile. For example, "
    echo "           the feature_example.mk is under project folder, -f=feature_example.mk"
    echo "           will replace feature.mk with feature_example.mk."
    echo ""
    echo "       -o=<make option> or --option=<make option>"
    echo "           Assign additional make option. For example, "
    echo "           to compile module sequentially, use -o=-j1."
    echo "           to turn on specific feature in feature makefile, use -o=<feature_name>=y"
    echo "           to assign more than one options, use -o=<option_1> -o=<option_2>."
    echo ""
    echo "==============================================================="
    echo "List Available Example Projects"
    echo "==============================================================="
    echo "Usage: $0 list"
    echo ""
}

show_available_proj () {
    echo "==============================================================="
    echo "Available Build Projects:"
    echo "==============================================================="
    for b in $BOARD_LIST
    do
        project_path=""
        project_name_list=""
        p=$(echo $PROJECT_LIST | tr " " "
" | grep "$b")
        if [ ! -z "$p" ]; then
            echo  "  "`basename $b`
        fi
        for q in $p
        do
            if [ -e "$q" ]; then
                project_path=$(echo $q | sed 's/GCC/Makefile//')
                project_name_list="${project_name_list} $(basename $project_path)" #project_name_list一直在叠加
            fi
        done
        for i in `echo $project_name_list | tr " " "
" | sort`
        do
            echo "  ""  "$i
        done
    done
}

#当输入./build mt2523_hdk headset_ref_design时
use_new_out_folder="FALSE"
target_check () {
    for p in $PROJECT_LIST   # $p是PROJECT_LIST中的一个
    do
        q=$(echo $p | grep "project/$1/")
        if [ ! -z "$q" ]; then
            r=$(echo $q | sed 's/GCC/Makefile//')
            s=`basename $r`
            if [ "$s" == "$2" ]; then
                echo "Build board:$1 project:$2"
                if [ $use_new_out_folder == "FALSE" ]; then
                    OUT=$OUT/$1/$2
                fi
                BUILD=project/$1/$2
                export TARGET_PATH=$(dirname $q)
                return 0
            fi
        fi
    done
    return 1
}

# support MinGW
mingw_check () {
    echo "platform=$platform"
    if [[ "$platform" =~ "MINGW" ]]; then
        pwdpath=$(pwd)
        echo $pwdpath
        if [[ "$pwdpath" =~ "[|]| " ]]; then  # "[|]| "表示有[或]或空格
            echo "Build.sh Exception: The codebase folder name should not have spacing, [ or ]."
            exit 1
        fi
    fi
}

clean_out () {
    rm -rf $1
    echo "rm -rf $1"
}
###############################################################################
#Begin here
if [ "$#" -eq "0" ]; then
    show_usage
    exit 1
fi

# parsing arguments
declare -a argv=($0)
ori_argv=$@
do_make_clean="FALSE"
for i in $@
do
    case $i in
        -o=*|--option=*)
            opt=" ${i#*=}"  # 变量的删除替换!删除从开始到等号之间的东西
            echo "$opt" | grep -q -E " OUT="
            if [[ $? -eq 0 ]]; then  # 上一步匹配到了,返回0
                # grep -o只显示匹配到的部分:OUT=后边,以空格或Tab开头的东东
                # cut -d 分隔符为=
                # tr -d 删掉
                OUT=`echo $opt | grep -o "OUT=[^ |^    ]*" | cut -d '=' -f2 | tr -d ' '`
                if [ -z "$OUT" ]; then
                    echo "Error: -o=OUT= cannot be empty!"
                    show_usage
                    exit 1
                fi
                OUT=$PWD/$OUT  # 更新设置了out目录
                use_new_out_folder="TRUE"
                echo "output folder change to: $OUT"
            fi
            extra_opt+=$opt  #字符串变量的追加,也可以写成 extra_opt=${extra_opt}$opt
            do_make_clean="TRUE"
            shift
            ;;
        -blo=*|--bloption=*)
            opt=" ${i#*=}"
            echo "$opt" | grep -q -E " OUT="
            if [[ $? -eq 0 ]]; then
                echo "Error: Unsupported -o=OUT= in [-blo|-bloption]."
                exit 1
            fi
            bl_extra_opt+=$opt
            do_make_clean="TRUE"
            shift
            ;;
        -f=*|--feature=*)
            feature_mk="${i#*=}"
            shift
            ;;
        list)
            show_available_proj
            exit 0
            ;;
        -*)
            echo "Error: unknown parameter "$i""
            show_usage
            exit 1
            ;;
        *)
            argv+=($i)
            ;;
    esac
done

export PROJ_NAME=${argv[2]}
###############################################################################
# 附带编译Bootloader时执行:       ./build mt2523_hdk headset_ref_design bl
if [ "${argv[3]}" == "bl" ]; then
    if [ "${#argv[@]}" != "4" ]; then
        show_usage
        exit 1
    fi
    target_check ${argv[1]} ${argv[2]}
    if [ "$?" -ne "0" ]; then
        echo "Error: ${argv[1]} ${argv[2]} is not available board & project"
        show_usage
        exit 1
    fi
    if [ $do_make_clean == "TRUE" ]; then
        clean_out $OUT
    fi
    mingw_check
    where_to_find_feature_mk=$TARGET_PATH
    if [ ! -z $feature_mk ]; then
        if [ ! -e "$TARGET_PATH/$feature_mk" ]; then
            echo "Error: cannot find $feature_mk under $TARGET_PATH."
            exit 1
        fi
        EXTRA_VAR+=" FEATURE=$feature_mk"
    else
        # 举例 $TARGET_PATH=project/mt2523_hdk/apps/headset_ref_design/GCC
        # 在Makefile中搜索TARGET_PATH开头    *表示多个空格,也是防止表达式断了     [?:]表示?或:    {0,1}表示0个或1个
        # tail只查看1行
        where_to_find_feature_mk=`grep "^TARGET_PATH *[?:]{0,1}= *" $TARGET_PATH/Makefile | cut -d '=' -f2 | tr -d ' ' | tail -1`
        if [ -z $where_to_find_feature_mk ]; then
            where_to_find_feature_mk=$TARGET_PATH
        fi
        feature_mk=`grep "^FEATURE *[?:]{0,1}= *" $TARGET_PATH/Makefile | cut -d '=' -f2 | tr -d ' ' | tail -1`
        echo "FEATURE=$feature_mk"
    fi
    if [ -e "$OUT/obj/$TARGET_PATH/tmp.mk" ]; then
        # -q仅显示有无差异,不显示结果
        diff -q $where_to_find_feature_mk/$feature_mk $OUT/obj/$TARGET_PATH/tmp.mk
        if [ $? -ne 0 ]; then
            clean_out $OUT
        fi
    fi
    mkdir -p $OUT/obj/$TARGET_PATH
    cp $where_to_find_feature_mk/$feature_mk $OUT/obj/$TARGET_PATH/tmp.mk

    CM4_TARGET_PATH_BAK=$TARGET_PATH
    TARGET_PATH="project/${argv[1]}/apps/bootloader/GCC"

    # 创建log目录
    mkdir -p $OUT/log
    echo "$0 $ori_argv" > $OUT/log/build_time.log
    echo "Start Build: "`date` >> $OUT/log/build_time.log
    echo "Build bootloader..."
    # Check if the source dir is existed
    if [ ! -d "project/${argv[1]}/apps/bootloader" ]; then
        echo "Error: no bootloader source in project/${argv[1]}/apps/bootloader"
        exit 1
    fi

    # 开始编译bootloader
    mkdir -p $OUT
    make -C $TARGET_PATH BUILD_DIR=$OUT/obj/bootloader OUTPATH=$OUT BL_MAIN_PROJECT=${argv[2]} $extra_opt $bl_extra_opt 2>> $OUT/err.log
    BUILD_RESULT=$?
    mkdir -p $OUT/lib
    mv -f $OUT/*.a $OUT/lib/ 2> /dev/null
    mkdir -p $OUT/log
    mv -f $OUT/*.log $OUT/log/ 2> /dev/null
    if [ $BUILD_RESULT -ne 0 ]; then
        echo "Error: bootloader build failed!!"
        echo "BOOTLOADER BUILD : FAIL" >> $OUT/log/build_time.log
        exit 2;
    else
        echo "BOOTLOADER BUILD : PASS" >> $OUT/log/build_time.log
    fi
    echo "Build bootloader...Done"

    # build cm4 firmware  编译M4固件
    echo "Build CM4 Firmware..."
    TARGET_PATH=$CM4_TARGET_PATH_BAK
    mkdir -p $OUT/autogen
    EXTRA_VAR+="$extra_opt"
    #echo "make -C $TARGET_PATH BUILD_DIR=$OUT/obj OUTPATH=$OUT $EXTRA_VAR"
    make -C $TARGET_PATH BUILD_DIR=$OUT/obj OUTPATH=$OUT $EXTRA_VAR 2>> $OUT/err.log
    BUILD_RESULT=$?
    mkdir -p $OUT/lib
    mv -f $OUT/*.a $OUT/lib/ 2> /dev/null
    mkdir -p $OUT/log
    mv -f $OUT/*.log $OUT/log/ 2> /dev/null
    echo "Build CM4 Firmware...Done"
    echo "End Build: "`date` >> $OUT/log/build_time.log
    cat $OUT/log/build.log | grep "MODULE BUILD" >> $OUT/log/build_time.log
    if [ "$BUILD_RESULT" -eq "0" ]; then
        echo "TOTAL BUILD: PASS" >> $OUT/log/build_time.log
    else
        echo "TOTAL BUILD: FAIL" >> $OUT/log/build_time.log
    fi
    echo "=============================================================="
    cat $OUT/log/build_time.log
    exit $BUILD_RESULT
elif [ "${argv[3]}" == "clean" ]; then
    if [ "${#argv[@]}" != "4" ]; then
        show_usage
        exit 1
    fi
    if [ "$use_new_out_folder" == "TRUE" ]; then
        rm -rf $OUT
    else
        rm -rf $OUT/${argv[1]}/${argv[2]}
    fi
elif [ "${argv[2]}" == "clean" ]; then
    if [ "${#argv[@]}" != "3" ]; then
        show_usage
        exit 1
    fi
    if [ "$use_new_out_folder" == "TRUE" ]; then
        rm -rf $OUT
    else
        rm -rf $OUT/${argv[1]}
    fi
elif [ "${argv[1]}" == "clean" ]; then
    if [ "${#argv[@]}" != "2" ]; then
        show_usage
        exit 1
    fi
    rm -rf $OUT
else  
    # 最后这里是只编译M4内核的部分
    if [ "${#argv[@]}" != "3" ]; then
        show_usage
        exit 1
    fi
    target_check ${argv[1]} ${argv[2]}
    if [ "$?" -ne "0" ]; then
        echo "Error: ${argv[1]} ${argv[2]} is not available board & project or module"
        show_usage
        exit 1
    fi
    if [ $do_make_clean == "TRUE" ]; then
        clean_out $OUT
    fi
    mingw_check
    where_to_find_feature_mk=$TARGET_PATH
    if [ ! -z $feature_mk ]; then
        if [ ! -e "$TARGET_PATH/$feature_mk" ]; then
            echo "Error: cannot find $feature_mk under $TARGET_PATH."
            exit 1
        fi
        EXTRA_VAR+=" FEATURE=$feature_mk"
    else
        where_to_find_feature_mk=`grep "^TARGET_PATH *[?:]{0,1}= *" $TARGET_PATH/Makefile | cut -d '=' -f2 | tr -d ' ' | tail -1`
        if [ -z $where_to_find_feature_mk ]; then
            where_to_find_feature_mk=$TARGET_PATH
        fi
        feature_mk=`grep "^FEATURE *[?:]{0,1}= *" $TARGET_PATH/Makefile | cut -d '=' -f2 | tr -d ' ' | tail -1`
        echo "FEATURE=$feature_mk"
    fi
    if [ -e "$OUT/obj/$TARGET_PATH/tmp.mk" ]; then
        diff -q $where_to_find_feature_mk/$feature_mk $OUT/obj/$TARGET_PATH/tmp.mk
        if [ $? -ne 0 ]; then
            clean_out $OUT
        fi
    fi
    mkdir -p $OUT/obj/$TARGET_PATH
    cp $where_to_find_feature_mk/$feature_mk $OUT/obj/$TARGET_PATH/tmp.mk
    mkdir -p $OUT/autogen
    mkdir -p $OUT/log
    echo "$0 $ori_argv" > $OUT/log/build_time.log
    echo "Start Build: "`date` >> $OUT/log/build_time.log
    if [ ! -z $feature_mk ]; then
        EXTRA_VAR+=" FEATURE=$feature_mk"
    fi
    EXTRA_VAR+="$extra_opt"
    #echo "make -C $TARGET_PATH BUILD_DIR=$OUT/obj OUTPATH=$OUT $EXTRA_VAR"
    make -C $TARGET_PATH BUILD_DIR=$OUT/obj OUTPATH=$OUT $EXTRA_VAR 2>> $OUT/err.log
    BUILD_RESULT=$?
    mkdir -p $OUT/lib
    mv -f $OUT/*.a $OUT/lib/ 2> /dev/null
    mv -f $OUT/*.log $OUT/log/ 2> /dev/null
    echo "End Build: "`date` >> $OUT/log/build_time.log
    cat $OUT/log/build.log | grep "MODULE BUILD" >> $OUT/log/build_time.log
    if [ "$BUILD_RESULT" -eq "0" ]; then
        echo "TOTAL BUILD: PASS" >> $OUT/log/build_time.log
    else
        echo "TOTAL BUILD: FAIL" >> $OUT/log/build_time.log
    fi
    echo "=============================================================="
    cat $OUT/log/build_time.log
    exit $BUILD_RESULT
fi

分析过程中,单独摘出来试验某个语句的意思,尤其是正则表达式复杂的时候,做试验更直观一些。

还有shell的调试方法,-x -n -v,要把整个脚本截短一点再调试,不然太庞大了。

纵观下来,最有意思的部分是,获得各个文件文件夹、搜索和截取路径、basename/dirname、处理输入变量。
最后肯定会调用make啦~~~
 
 
 
 
 
 
 
 
 
联我:shen5773384##163.com
原文地址:https://www.cnblogs.com/WMCH/p/8615814.html