blob: 0581225772140939b5ca90266b056f1fbc52e890 [file] [log] [blame]
#!/bin/sh
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -e
OUT_DIR_DEFAULT=bazel-pypi-out
USAGE="$(basename $0) <python-tag> [<output-directory>]
Build a Python wheel for public release to PyPI using a special Docker build
container. Uses bazel, but does not pollute the WORKSPACE's default cache.
<python-tag> must be one of the supported interpreters:
cp310
cp311
<output-directory> defaults to $OUT_DIR_DEFAULT.
"
case "$1" in
cp310|cp311)
PY_TAG=$1
OUTDIR=$(realpath ${2:-$OUT_DIR_DEFAULT})
mkdir -p $OUTDIR
break
;;
*)
echo usage: "$USAGE" >&2
exit 1
esac
SRCDIR=$(realpath .)
if ! test -f $SRCDIR/WORKSPACE; then
echo "error: must run from the top of the source tree" >&2
exit 1
fi
# Remove Bazel's workspace symlinks so they'll be rewritten below, pointing into
# OUTDIR.
find . -maxdepth 1 -type l -name bazel-\* | xargs rm -f
# Build the Docker image from its source file. Don't pollute the public list of
# images by tagging; just use the image's ID.
DOCKERFILE=python/tflite_micro/pypi_build.dockerfile
IMAGE_ID_FILE=$OUTDIR/image-id
docker build - --iidfile $IMAGE_ID_FILE <$DOCKERFILE
IMAGE_ID=$(cat $IMAGE_ID_FILE)
# Build the Python package within an ephemeral container.
docker run \
--rm \
--interactive \
--mount type=bind,source=$SRCDIR,destination=$SRCDIR \
--mount type=bind,source=$OUTDIR,destination=$OUTDIR \
--workdir $SRCDIR \
--env USER=$(id -un) \
$IMAGE_ID \
/bin/bash -s -e -x -u \
<<EOF
# Setup the Python compatibility tags. The PY_ABI always matches the Python
# interpreter tag. The platform tag is supplied by the build image in the
# environment variable AUDITWHEEL_PLAT.
PY_ABI=$PY_TAG
PY_PLATFORM=\$AUDITWHEEL_PLAT
PY_COMPATIBILITY=${PY_TAG}_\${PY_ABI}_\${PY_PLATFORM}
# Link the desired Python version into the PATH, where bazel will find it.
# The build image contains many different Python versions as options.
ln -sf /opt/python/$PY_TAG-$PY_TAG/bin/* /usr/bin
# Bazelisk fails if it can't check HOME for a .rc file., and pip (in
# :whl_test) installation of some dependencies (e.g., wrapt) expects HOME.
export HOME=$OUTDIR
# Bazelisk, bazel, and pip all need a writable cache directory.
export XDG_CACHE_HOME=$OUTDIR/cache
# Relocate the bazel root to keep the cache used for each Python toolchain
# separate. Drop root privledges and run as the invoking user.
call_bazel() {
setpriv --reuid=$(id -u) --regid=$(id -g) --clear-groups \
bazel \
--output_user_root=$OUTDIR/$PY_TAG-out \
"\$@" \
--action_env=HOME `# help setuptools find HOME in container` \
--action_env=USER `# bazel reads USER via whoami` \
--action_env=XDG_CACHE_HOME `# locate pip's cache inside OUTDIR`
}
# Build the wheel via bazel, using the Python compatibility tag matching the
# build environment.
call_bazel build //python/tflite_micro:whl.dist \
--//python/tflite_micro:compatibility_tag=\$PY_COMPATIBILITY
# Test, in the container environment.
call_bazel test //python/tflite_micro:whl_test \
--//python/tflite_micro:compatibility_tag=\$PY_COMPATIBILITY
EOF
# Make the output directory tree writable so it can be removed easily by the
# user with `rm -rf $OUTDIR`. Bazel leaves it write-protected.
chmod -R +w $OUTDIR
# Copy the generated wheel file to the root of the $OUTDIR.
cp bazel-bin/python/tflite_micro/whl_dist/*.whl $OUTDIR
echo "Output:\n$(ls $OUTDIR/*.whl)"