狗哥秃头路【2】狗哥花了一天注释的tensorflow-on-arm.sh脚本(结尾含有一个正则表达式的解析)

狗哥秃头路【2】狗哥花了一天注释的tensorflow-on-arm.sh脚本

来源

https://github.com/lhelontra/tensorflow-on-arm

注:注释还有不完整和可能错误的部分,会逐渐完善,也欢迎指正。

#!/bin/bash

# build_tensorflow -*- shell-script -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2017 Leonardo Lontra
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

#将一个文件普通名传给传给$1,并判断这个文件是否存在
[ -f "$1" ] && {
  source "$1"#存在的话(返回真)就在shell执行这个文件
} || {       #如果不存在就输出以下语句并退出
  echo -ne "Use: $0 <config>\n\tFor prepare environment only, uses: $0 <config> prepare\n"
  exit 1
}


#realpath 用于获取指定目录或文件的绝对路径
#$(dirname $0)切换到脚本所在的目录

#令DIR指向当前脚本文件所在的绝对路径
DIR="$(realpath $(dirname $0))"
#执行脚本所在目录下的patch.sh
source "${DIR}/patch.sh"

# builtin variables
RED='\033[0;31m'
BLUE='\033[1;36m'
#关闭所有属性
NC='\033[0m'

#如果没有指定版本则默认使用PYTHON3
TF_PYTHON_VERSION=${TF_PYTHON_VERSION:-"3"}
#默认的一些配置
TF_VERSION=${TF_VERSION:-"v1.14.0"}
TF_BUILD_OUTPUT=${TF_BUILD_OUTPUT:-"/tmp/tensorflow_pkg"}
BAZEL_VERSION=${BAZEL_VERSION:-"0.24.1"}
CROSSTOOL_WHEEL_ARCH=${CROSSTOOL_WHEEL_ARCH:-"any"}
TF_GIT_URL=${TF_GIT_URL:-"https://github.com/tensorflow/tensorflow"}
WORKDIR=${WORKDIR:-"$DIR"}
#判断bazel命令是否存在
BAZEL_BIN="$(command -v bazel)"

function set_selected_python_default() {
 #判断当前路径下python能否执行
  PYTHON_BIN_PATH=$(command -v python${TF_PYTHON_VERSION})
  
  default_python=$(command -v python)
  [ -z "$default_python" ] && {
      default_python="$(dirname $PYTHON_BIN_PATH)/python"
  }
  #删除默认
  rm -f $default_python &>/dev/null
  #强制创建软连接
  ln -sf $PYTHON_BIN_PATH $default_python &>/dev/null
}

#报错信息函数
function log_failure_msg() {
	echo -ne "[${RED}ERROR${NC}] $@\n"
}

#消息汇报函数
function log_app_msg() {
	echo -ne "[${BLUE}INFO${NC}] $@\n"
}

#创建工作文件目录
function create_workdir()
{
  WORKDIR=${WORKDIR}/sources/
  #如果不存在这个目录就创建,创建失败就报错并退出
  if [ ! -d $WORKDIR ]; then
    mkdir -p ${WORKDIR} || {
      log_failure_msg "error when creates workdir $WORKDIR"
      exit 1
    }
  fi
  return 0
}

#构建bazel的函数
function build_bazel()
{
  #创建目录
  mkdir -p ${WORKDIR}/bin/

  #如果版本不同或未找到,则强制编译Bazel
  if [ -z "$BAZEL_BIN" ] || [ "$($BAZEL_BIN version | grep -i 'label' | awk '{ print $3 }' | tr -d '-')" != "${BAZEL_VERSION}" ]; then
      BAZEL_BIN="${WORKDIR}/bin/bazel-${BAZEL_VERSION}"
  fi
  
  #默认路径
  PATH="${WORKDIR}/bin/:${PATH}"
  #判断是否已安装bazel
  if [ -f "$BAZEL_BIN" ]; then
    log_app_msg "bazel already installed."
    #确保使用版本的正确
    rm -f ${WORKDIR}/bin/bazel &>/dev/null
    #bazel建立软连接后删除???
    ln -sf "${WORKDIR}/bin/bazel-${BAZEL_VERSION}" "${WORKDIR}/bin/bazel" &>/dev/null
    return 0
  fi
  set_selected_python_default

 #切换到工作路径
  cd $WORKDIR
#如果不存在就在github上下载到指定位置
  if [ ! -f bazel-${BAZEL_VERSION}-dist.zip ]; then
    wget --no-check-certificate https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-dist.zip
  fi
#如果目录不存在就创建,并且解压到指定目录并删除压缩包
  if [ ! -d bazel-${BAZEL_VERSION} ]; then
    mkdir bazel-${BAZEL_VERSION}
    unzip bazel-${BAZEL_VERSION}-dist.zip -d bazel-${BAZEL_VERSION}/
    rm -f bazel-${BAZEL_VERSION}-dist.zip
    #到解压后文件的目录
    cd bazel-${BAZEL_VERSION}/
    #?如果bazel补丁文件存在则执行
    if [ "$BAZEL_PATCH" == "yes" ]; then
      bazel_patch || {
        log_failure_msg "error when apply patch"
        exit 1
      }
    fi
  else
    cd bazel-${BAZEL_VERSION}/
  fi
 #执行编译
  ./compile.sh
  #如果缺少文件就报错
  if [ ! -f ./output/bazel ]; then
    log_failure_msg "error when compile bazel"
    exit 1
  fi
  
#赋予执行权限
  chmod +x output/bazel
  #改名
  mv output/bazel "${WORKDIR}/bin/bazel-${BAZEL_VERSION}"
  #建立软连接并删除前者
  ln -sf "${WORKDIR}/bin/bazel-${BAZEL_VERSION}" "${WORKDIR}/bin/bazel" &>/dev/null

  return 0
}

#工具链函数
function toolchain()
{
#检查编译器是否存在,存在则检查URL
  [ "$CROSSTOOL_COMPILER" != "yes" ] || [ -z "$CROSSTOOL_URL" ] && return 0
#设置
  CROSSTOOL_DIR="${WORKDIR}/toolchain/${CROSSTOOL_DIR}/"

#检查交叉编译器的路径是否存在,不存在就创建
  [ ! -d "${CROSSTOOL_DIR}/${CROSSTOOL_NAME}/bin/" ] && {
    mkdir -p ${WORKDIR}/toolchain/
    #下载压缩包,如果失败就报错
    wget --no-check-certificate $CROSSTOOL_URL -O toolchain.tar.xz || {
      log_failure_msg "error when download crosstool"
      exit 1
    }
    #解压到指定路径,解压如果错误报错并退出
    tar xf toolchain.tar.xz -C ${WORKDIR}/toolchain/ || {
      log_failure_msg "error when extract crosstool"
      exit 1
    }
    #删除压缩包
    rm toolchain.tar.xz &>/dev/null
  }

}

#下载tensorflow的函数
function download_tensorflow()
{
 #到工作路径下
  cd ${WORKDIR}
  #检测是否存在tensorflow的文件,不存在就去git上clone
  if [ ! -d tensorflow ]; then
    git clone --recurse-submodules ${TF_GIT_URL} || return 1
    cd tensorflow/
  else
    cd tensorflow/
    #???清除操作
    [ "$1" != "noclean" ] && $BAZEL_BIN clean &>/dev/null

    #退回当前版本
    git reset --hard
    #从工作目录中删除所有没有tracked过的文件
    git clean -f -d
    #切换到master分支
    git checkout master
    #删除本地分支
    git branch -D __temp__
    #更新
    git pull
  fi
#切换分支,失败则报错
  git checkout ${TF_VERSION} || {
    log_failure_msg "error when using tensorflow version ${TF_VERSION}"
    exit 1
  }

  #创建一个临时分支以应用一些补丁并重新使用克隆的文件夹
  git checkout -b __temp__

  #设置git local config以应用补丁
  git config user.email "temp@example.com"
  git config user.name "temp"

#检测tensorflow补丁是否存在
  if [ "$TF_PATCH" == "yes" ]; then
     tf_patch || {
       log_failure_msg "error when apply patch"
       exit 1
     }
  fi

#检测交叉编译工具并打补丁?
  if [ ! -z "$CROSSTOOL_DIR" ] && [ ! -z "$CROSSTOOL_NAME" ]; then
    tf_toolchain_patch "$CROSSTOOL_NAME" "$CROSSTOOL_DIR" "$CROSSTOOL_ROOT" "$CROSSTOOL_EXTRA_INCLUDE" || {
      log_failure_msg "error when apply crosstool patch"
      exit 1
    }
  fi
  
#将我们需要提交的代码从工作区添加到暂存区,就是告诉git系统,我们要提交哪些文件
#之后就可以使用git commit命令进行提交了
  git add .
  git commit -m "temp modifications"

  return 0
}

function configure_tensorflow()
{
  # 配置 tensorflow
  #到tensorflow目录下
  cd ${WORKDIR}/tensorflow
  #清空目录?
  [ "$1" != "noclean" ] && $BAZEL_BIN clean
  #配置环境
  export PYTHON_BIN_PATH=$(command -v python${TF_PYTHON_VERSION})
  export ${TF_BUILD_VARS}

  set_selected_python_default

  #如果启用了need_cuda,则搜索sdk
  if [ "$TF_NEED_CUDA" == "1" ]; then
     local nvcc_path=$(command -v nvcc)#局部变量
#如果存在,设置局部变量
     if [ ! -z "$nvcc_path" ]; then
                            
         local cuda_location=$(echo $nvcc_path | sed 's/\/bin\/nvcc//')#对文件中的所有行编号,但只显示非空白行的行号
         #设置为在版本文本中第三列,以.为分割,取前两个      
         local cuda_version=$(cat "${cuda_location}/version.txt" | awk '{ print $3 }' | cut -d'.' -f-2)
         #查找 截取.为分割第三个
         local cudnn_version=$(readlink $(find "${cuda_location}/" -iname '*libcudnn.so') | cut -d'.' -f3)
#配置环境变量
         export CUDA_TOOLKIT_PATH="$cuda_location"
         export TF_CUDA_VERSION=$cuda_version
         export TF_CUDNN_VERSION=$cudnn_version
     else
         export TF_NEED_CUDA=0
     fi
  fi
#开始使用此python文件配置,失败报错
  yes '' | $PYTHON_BIN_PATH configure.py || {
      log_failure_msg "error when configure tensorflow"
      exit 1
  }
  return 0
}

#配置tensorflow的函数
function build_tensorflow()
{
  cd ${WORKDIR}/tensorflow
#检测文件是否都存在
  if [ ! -z "$BAZEL_AVALIABLE_RAM" ] && [ ! -z "$BAZEL_AVALIABLE_CPU" ] && [ ! -z "$BAZEL_AVALIABLE_IO" ]; then
    BAZEL_LOCAL_RESOURCES="--local_resources ${BAZEL_AVALIABLE_RAM},${BAZEL_AVALIABLE_CPU},${BAZEL_AVALIABLE_IO}"
  fi
#如果?,在BAZEL_EXTRA_FLAGS添加
  [[ "${BAZEL_EXTRA_FLAGS}" == *"build_pip_package"* ]] && BAZEL_EXTRA_FLAGS+=" --python_path=python${TF_PYTHON_VERSION}"
#build pip package???
  $BAZEL_BIN build ${BAZEL_LOCAL_RESOURCES} -c opt ${BAZEL_COPT_FLAGS} --verbose_failures ${BAZEL_EXTRA_FLAGS} || return 1

  #如有需要,制造whl
  [[ "${BAZEL_EXTRA_FLAGS}" == *"build_pip_package"* ]] && {
    unset BDIST_OPTS
    #如果激活了交叉编译,则构建通用whl
    if [ ! -z "$CROSSTOOL_DIR" ] && [ ! -z "$CROSSTOOL_NAME" ]; then
      export BDIST_OPTS="--universal"
    fi
#创建目录
    mkdir -p ${TF_BUILD_OUTPUT} || {
      log_failure_msg "error when creates output dir $TF_BUILD_OUTPUT"
      exit 1
    }

    # 构建whl
    bazel-bin/tensorflow/tools/pip_package/build_pip_package $TF_BUILD_OUTPUT || return 1

    if [ ! -z "$BDIST_OPTS" ]; then
    "#f设置为 前者目录查找whl文件内第一行
      local f="${TF_BUILD_OUTPUT}/$(ls -t $TF_BUILD_OUTPUT | grep -i '.whl' | head -n1)
      #new_f为f的???(这段离谱的正则表达式在结尾解释)
      local new_f="$(echo $f | sed -rn "s/tensorflow-([^-]+)-([^-]+)-.*/tensorflow-\1-\2-none-${CROSSTOOL_WHEEL_ARCH}.whl/p")"
      #改名
      mv $f $new_f
      log_app_msg "wheel was renamed of $f for $new_f"
    fi
  }

  # 复制库文件(如果需要)
  [[ "${BAZEL_EXTRA_FLAGS}" == *"libtensorflow"* ]] && {
    #收集库文件到TF_BUILD_OUTPUT
    cp bazel-bin/tensorflow/libtensorflow* $TF_BUILD_OUTPUT &>/dev/null
    cp bazel-bin/tensorflow/lite/libtensorflowlite* $TF_BUILD_OUTPUT &>/dev/null
    cp tensorflow/c/c_api.h $TF_BUILD_OUTPUT &>/dev/null
    log_app_msg "Library files moved to $TF_BUILD_OUTPUT"
  }

  log_app_msg "Done."
}

#准备环境的函数
function prepare_env()
{
  # prepare environment for compiling
  create_workdir
  build_bazel
  toolchain
  download_tensorflow "$1"
  echo -ne "Workdir:            \t${WORKDIR}\n"
  echo -ne "Bazel binary:       \t${BAZEL_BIN}\n"
  [ ! -z "$CROSSTOOL_DIR" ] && echo -ne "Toolchain directory:\t${CROSSTOOL_DIR}\n"
}


function main()
{
  prepare_env "$1"
  configure_tensorflow "$1"
    build_tensorflow
}
#如果传入“prepare”则执行环境配置函数,否则执行主函数
[ "$2" == "prepare" ] && prepare_env || main "$2"
存在的问题以及解释
clean命令:clean是bazel命令

*"build_pip_package"* 

$BAZEL_BIN build ${BAZEL_LOCAL_RESOURCES} -c opt ${BAZEL_COPT_FLAGS} --verbose_failures ${BAZEL_EXTRA_FLAGS}
local new_f="$(echo $f | sed -rn "s/tensorflow-([^-]+)-([^-]+)-.*/tensorflow-\1-\2-none-${CROSSTOOL_WHEEL_ARCH}.whl/p")"

这段含有正则和sed的命令比较长,逐个分析。
首先是前面 “local new_f = ”说明是定义局部变量。
echo $f |说明是把前面的变量f 的内容传给后面
后面这段是重点,

sed -rn "s/tensorflow-([^-]+)-([^-]+)-.*/tensorflow-\1-\2-none-${CROSSTOOL_WHEEL_ARCH}.whl/p"

sed命令的r和n参数
r表示含有正则表达式
n表示静默输出,仅显示script处理后的结果
s/表示替换
/p表示打印
除去这些即为正则表达式的内容

tensorflow-([^-]+)-([^-]+)-.*/tensorflow-\1-\2-none-${CROSSTOOL_WHEEL_ARCH}.whl
([^-]+)
()括号是分组用,在这个表达式里没有作用
[^-]意思是不包含-这个字符
+意思是至少一个或多个
总体意思:不包含-的任意字符,字符个数不限,但至少一个字符
 
.* 就是单个字符匹配任意次,即贪婪匹配 ,此处可以理解为把 -([^-]+)-([^-]+)-匹配到的内容之后的所有内容
整体即为
 -([^-]+)-([^-]+)-.*
-{不含“-”的至少一个字符}-{不含“-”的至少一个字符}-{之后所有的字符}  
替换后
-{不含“-”的至少一个字符}-{不含“-”的至少一个字符}-none-变量.whl

为了验证,采用在线正则表达式来测试一下:
下面的测试中,图一没加.*正则匹配到了-t-t-和-weqwewq-1-
在这里插入图片描述
第二张图由于.*符号,所以把第一次匹配到的-t-t-之后的内容全部输出了。
在这里插入图片描述

tensorflow介绍:
http://www.tensorfly.cn/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值