| #!/usr/bin/bash |
| # Copyright 2023 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Create a version of the Python CIPD package where all library files are |
| # stored in a single zip archive. Useful to drastically limit the number |
| # of input files in Bazel actions that depend on a custom Python toolchain |
| # target wrapping the content of this package. |
| # |
| # For example, the final output would look like: |
| # |
| # $PREFIX/ |
| # bin/ |
| # lib_python3.8.zip |
| # Zip archive containing all standard Python modules. |
| # |
| # python3 |
| # ---symlink---> python3.8 |
| # |
| # python3.8-real |
| # Real python interpreter binary (stripped). |
| # |
| # python3.8 |
| # Wrapper script that invokes python3.8-real after adjusting |
| # PYTHONPATH to point to lib_python3.8.zip to find standard |
| # modules. |
| # |
| # All other files in bin/ (e.g. 'pip3') are python scripts and need no |
| # adjustments. |
| # |
| |
| set -euxo pipefail |
| |
| SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" |
| |
| PREFIX="$1" |
| |
| ## Copy the whole bin/ directory to $PREFIX/bin/ |
| cp -Rpf bin "${PREFIX}/" |
| |
| ## Copy the whole include/ directory as well |
| cp -Rpf include "${PREFIX}/" |
| |
| # Find the real interpreter executable and copy a stripped version to |
| # $PREFIX/bin/python<version>-real |
| # |
| # NOTE: strip -xS works on both Linux and OSX. |
| python_versioned="$(readlink "${PREFIX}"/bin/python3)" |
| strip -xS -o "${PREFIX}/bin/${python_versioned}-real" "${PREFIX}"/bin/${python_versioned} |
| |
| ## Generate library archive. |
| LIBDIR=lib/${python_versioned} |
| ARCHIVE_NAME=lib_${python_versioned}.zip |
| |
| # Change the timestamp of all files that go into the zip |
| # archive to 1980-01-01 00:00:00 |
| find "${LIBDIR}" -type f | xargs touch -t 198001010000.00 |
| (cd "${LIBDIR}" && zip -0qrD ${ARCHIVE_NAME} .) |
| cp "${LIBDIR}/${ARCHIVE_NAME}" "${PREFIX}/bin/${ARCHIVE_NAME}" |
| |
| # Overwrite $PREFIX/bin/python<version> with a wrapper script that invokes |
| # the real interperter. |
| # |
| # - PYTHONHOME is set to _script_dir to ensure sys.path only contains paths |
| # relative to it. Otherwise, some hard-coded paths in the interpreter |
| # binary will be used (e.g. `/work/out/python3`), which could lead to bad |
| # surprises. |
| # |
| # - PYTHONPATH is extended to point to the zip archive, and allows the |
| # interpreter to find all system modules from it. |
| # |
| # - The `-S` flag disables site-specific module lookups. |
| # |
| # - The `-s` flag disables user-specific module lookups. |
| # |
| # Note that `python3` also supports the `-I` flag to run in "isolated" mode, |
| # where PYTHONPATH and PYTHONHOME are ignored, but this forces sys.path to |
| # strictly hard-coded values that are unusable here. |
| # |
| rm -f "${PREFIX}/bin/${python_versioned}" |
| cat > "${PREFIX}/bin/${python_versioned}" <<EOF |
| #!/bin/sh |
| # AUTO-GENERATED - DO NOT EDIT |
| if [ -n "\${BASH_VERSION}" ]; then |
| readonly _script_dir="\$(dirname "\${BASH_SOURCE[0]}")" |
| elif [ -n "\${ZSH_VERSION}" ]; then |
| _script_dir="\${0:a:h}" |
| else |
| _script_dir="\$(dirname "\$0")" |
| fi |
| PYTHONPATH="\${_script_dir}/${ARCHIVE_NAME}:\${PYTHONPATH}" \\ |
| PYTHONHOME="\${_script_dir}" \\ |
| exec "\${_script_dir}/${python_versioned}-real" -S -s "\$@" |
| EOF |
| |
| chmod a+x "${PREFIX}/bin/${python_versioned}" |
| |
| ## Copy license file. |
| |
| cp "${SCRIPT_DIR}"/LICENSE "${PREFIX}/LICENSE" |
| |
| ## Generate README.fuchsia |
| |
| sed -e 's|@PYTHON_VERSION@|'"${_3PP_VERSION}"'|g' \ |
| -e 's|@PLATFORM@|'"${_3PP_PLATFORM}"'|g' \ |
| "${SCRIPT_DIR}"/README.fuchsia.template > "${PREFIX}/README.fuchsia" |