1#!/usr/bin/env bash
2# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ==============================================================================
16
17set -e
18
19function is_absolute {
20  [[ "$1" = /* ]] || [[ "$1" =~ ^[a-zA-Z]:[/\\].* ]]
21}
22
23function real_path() {
24  is_absolute "$1" && echo "$1" || echo "$PWD/${1#./}"
25}
26
27function move_to_root_if_exists () {
28  arg_to_move="$1"
29  if [ -e "${arg_to_move}" ]; then
30    mv ${arg_to_move} ./
31  fi
32}
33
34function reorganize_includes() {
35  TMPDIR="${1%/}"
36}
37
38PLATFORM="$(uname -s | tr 'A-Z' 'a-z')"
39function is_windows() {
40  if [[ "${PLATFORM}" =~ (cygwin|mingw32|mingw64|msys)_nt* ]]; then
41    true
42  else
43    false
44  fi
45}
46
47function prepare_src() {
48  if [ $# -lt 1 ] ; then
49    echo "No destination dir provided"
50    exit 1
51  fi
52
53  TMPDIR="${1%/}"
54  mkdir -p "$TMPDIR"
55  EXTERNAL_INCLUDES="${TMPDIR}/tflite_support/include/external"
56
57  echo $(date) : "=== Preparing sources in dir: ${TMPDIR}"
58
59  if [ ! -d bazel-bin/tensorflow_lite_support ]; then
60    echo "Could not find bazel-bin.  Did you run from the root of the build tree?"
61    exit 1
62  fi
63
64  if is_windows; then
65    rm -rf ./bazel-bin/tensorflow_lite_support/tools/pip_package/simple_console_for_windows_unzip
66    mkdir -p ./bazel-bin/tensorflow_lite_support/tools/pip_package/simple_console_for_windows_unzip
67    echo "Unzipping simple_console_for_windows.zip to create runfiles tree..."
68    unzip -o -q ./bazel-bin/tensorflow_lite_support/tools/pip_package/simple_console_for_windows.zip -d ./bazel-bin/tensorflow_lite_support/tools/pip_package/simple_console_for_windows_unzip
69    echo "Unzip finished."
70    # runfiles structure after unzip the python binary
71    RUNFILES=bazel-bin/tensorflow_lite_support/tools/pip_package/simple_console_for_windows_unzip/runfiles/org_tensorflow_lite_support
72
73    # TODO(b/165872313): Investigate the case and remove the hack.
74    # On Windows, __init__.py are not auto genereated at directories that only
75    # contains Pybind libraries.
76    touch "$RUNFILES/tensorflow_lite_support/metadata/cc/__init__.py"
77    touch "$RUNFILES/tensorflow_lite_support/metadata/cc/python/__init__.py"
78    touch "$RUNFILES/tensorflow_lite_support/metadata/flatbuffers_lib/__init__.py"
79  else
80    RUNFILES=bazel-bin/tensorflow_lite_support/tools/pip_package/build_pip_package.runfiles/org_tensorflow_lite_support
81  fi
82
83  cp "$RUNFILES/LICENSE" "${TMPDIR}"
84  cp -R "$RUNFILES/tensorflow_lite_support" "${TMPDIR}"
85
86  reorganize_includes "${TMPDIR}"
87
88  cp tensorflow_lite_support/tools/pip_package/MANIFEST.in ${TMPDIR}
89  cp tensorflow_lite_support/tools/pip_package/README ${TMPDIR}/README.md
90  cp tensorflow_lite_support/tools/pip_package/setup.py ${TMPDIR}
91
92  # A helper entry.
93  mkdir ${TMPDIR}/tflite_support
94  cp tensorflow_lite_support/tools/pip_package/tflite_support.__init__.py ${TMPDIR}/tflite_support/__init__.py
95}
96
97function build_wheel() {
98  if [ $# -lt 2 ] ; then
99    echo "No src and dest dir provided"
100    exit 1
101  fi
102
103  TMPDIR="$1"
104  DEST="$2"
105  PKG_NAME_FLAG="$3"
106
107  # Before we leave the top-level directory, make sure we know how to
108  # call python.
109  if [[ -e tools/python_bin_path.sh ]]; then
110    source tools/python_bin_path.sh
111  fi
112
113  pushd ${TMPDIR} > /dev/null
114
115  rm -f MANIFEST
116  echo $(date) : "=== Building wheel"
117  "${PYTHON_BIN_PATH:-python}" setup.py bdist_wheel ${PKG_NAME_FLAG} >/dev/null
118  mkdir -p ${DEST}
119  cp dist/* ${DEST}
120  popd > /dev/null
121  echo $(date) : "=== Output wheel file is in: ${DEST}"
122}
123
124function usage() {
125  echo "Usage:"
126  echo "$0 [--src srcdir] [--dst dstdir] [options]"
127  echo "$0 dstdir [options]"
128  echo ""
129  echo "    --src                 prepare sources in srcdir"
130  echo "                              will use temporary dir if not specified"
131  echo ""
132  echo "    --dst                 build wheel in dstdir"
133  echo "                              if dstdir is not set do not build, only prepare sources"
134  echo ""
135  echo "  Options:"
136  echo "    --project_name <name>           set project name to <name>"
137  echo "    --version <version>             reset the pip package version to <version>"
138  echo "    --nightly_flag                  build TFLite Support nightly"
139  echo ""
140  echo "When using bazel, add the following flag: --run_under=\"cd \$PWD && \""
141  echo ""
142  exit 1
143}
144
145function main() {
146  PKG_NAME_FLAG=""
147  PROJECT_NAME=""
148  NIGHTLY_BUILD=0
149  SRCDIR=""
150  DSTDIR=""
151  CLEANSRC=1
152  VERSION=""
153  while true; do
154    if [[ "$1" == "--help" ]]; then
155      usage
156      exit 1
157    elif [[ "$1" == "--nightly_flag" ]]; then
158      NIGHTLY_BUILD=1
159    elif [[ "$1" == "--project_name" ]]; then
160      shift
161      if [[ -z "$1" ]]; then
162        break
163      fi
164      PROJECT_NAME="$1"
165    elif [[ "$1" == "--version" ]]; then
166      shift
167      if [[ -z "$1" ]]; then
168        break
169      fi
170      VERSION="$1"
171    elif [[ "$1" == "--src" ]]; then
172      shift
173      SRCDIR="$(real_path $1)"
174      CLEANSRC=0
175    elif [[ "$1" == "--dst" ]]; then
176      shift
177      DSTDIR="$(real_path $1)"
178    else
179      echo "Unrecognized flag: $1"
180      usage
181      exit 1
182    fi
183    shift
184
185    if [[ -z "$1" ]]; then
186      break
187    fi
188  done
189
190  if [[ -z "$DSTDIR" ]] && [[ -z "$SRCDIR" ]]; then
191    echo "No destination dir provided"
192    usage
193    exit 1
194  fi
195
196  if [[ -z "$SRCDIR" ]]; then
197    # make temp srcdir if none set
198    SRCDIR="$(mktemp -d -t tmp.XXXXXXXXXX)"
199  fi
200
201  if [[ -z "$DSTDIR" ]]; then
202      # only want to prepare sources
203      exit
204  fi
205
206  if [[ -n ${PROJECT_NAME} ]]; then
207    PKG_NAME_FLAG="--project_name ${PROJECT_NAME}"
208  elif [[ ${NIGHTLY_BUILD} == "1" ]]; then
209    PKG_NAME_FLAG="--project_name tflite_support_nightly"
210  fi
211
212  if [[ ${NIGHTLY_BUILD} == "1" ]]; then
213    # we use a script to update versions to avoid any tool differences on different platforms.
214    if [[ ! -z ${VERSION} ]]; then
215      python tensorflow_lite_support/tools/ci_build/update_version.py --src "." --version ${VERSION} --nightly
216    else
217      python tensorflow_lite_support/tools/ci_build/update_version.py --src "." --nightly
218    fi
219  elif [[ ! -z ${VERSION} ]]; then
220    python tensorflow_lite_support/tools/ci_build/update_version.py --src "." --version ${VERSION}
221  fi
222
223  prepare_src "$SRCDIR"
224
225  build_wheel "$SRCDIR" "$DSTDIR" "$PKG_NAME_FLAG"
226
227  if [[ $CLEANSRC -ne 0 ]]; then
228    rm -rf "${TMPDIR}"
229  fi
230}
231
232main "$@"
233