#!/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啦~~~
啊