| #!/usr/bin/env bash |
| set -euo pipefail |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| PYTHON_VERSION="${PYTHON_VERSION:-3.10}" |
| PYTHON_PATCH="${PYTHON_PATCH:-18}" |
| PY_STANDALONE_TAG="${PY_STANDALONE_TAG:-20250818}" |
| |
| PORTABLE_PYTHON="${PORTABLE_PYTHON:-false}" |
|
|
| |
| |
| : "${PORTABLE_PY_FILENAME:=}" |
| : "${PORTABLE_PY_SHA256:=}" |
| |
|
|
| |
| if [ "x${USE_PIP:-}" == "x" ]; then |
| USE_PIP=false |
| fi |
|
|
| |
| function _is_musl() { |
| |
| if command -v ldd >/dev/null 2>&1; then |
| ldd --version 2>&1 | grep -qi musl && return 0 |
| fi |
| |
| if command -v getconf >/dev/null 2>&1; then |
| getconf GNU_LIBC_VERSION >/dev/null 2>&1 || return 0 |
| fi |
| return 1 |
| } |
|
|
| function _triple() { |
| local os="" arch="" libc="gnu" |
| case "$(uname -s)" in |
| Linux*) os="unknown-linux" ;; |
| Darwin*) os="apple-darwin" ;; |
| MINGW*|MSYS*|CYGWIN*) os="pc-windows-msvc" ;; |
| *) echo "Unsupported OS $(uname -s)"; exit 1;; |
| esac |
|
|
| case "$(uname -m)" in |
| x86_64) arch="x86_64" ;; |
| aarch64|arm64) arch="aarch64" ;; |
| armv7l) arch="armv7" ;; |
| i686|i386) arch="i686" ;; |
| ppc64le) arch="ppc64le" ;; |
| s390x) arch="s390x" ;; |
| riscv64) arch="riscv64" ;; |
| *) echo "Unsupported arch $(uname -m)"; exit 1;; |
| esac |
|
|
| if [[ "$os" == "unknown-linux" ]]; then |
| if _is_musl; then |
| libc="musl" |
| else |
| libc="gnu" |
| fi |
| echo "${arch}-${os}-${libc}" |
| else |
| echo "${arch}-${os}" |
| fi |
| } |
|
|
| function _portable_dir() { |
| echo "${EDIR}/python" |
| } |
|
|
| function _portable_bin() { |
| |
| echo "$(_portable_dir)/bin" |
| } |
|
|
| function _portable_python() { |
| if [ -x "$(_portable_bin)/python3" ]; then |
| echo "$(_portable_bin)/python3" |
| else |
| echo "$(_portable_bin)/python" |
| fi |
| } |
|
|
|
|
| |
| _macosPortableEnv() { |
| if [ "$(uname -s)" = "Darwin" ]; then |
| export DYLD_LIBRARY_PATH="$(_portable_dir)/lib${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}" |
| export DYLD_FALLBACK_LIBRARY_PATH="$(_portable_dir)/lib${DYLD_FALLBACK_LIBRARY_PATH:+:${DYLD_FALLBACK_LIBRARY_PATH}}" |
| fi |
| } |
|
|
| |
| _unquarantinePortablePython() { |
| if [ "$(uname -s)" = "Darwin" ]; then |
| command -v xattr >/dev/null 2>&1 && xattr -dr com.apple.quarantine "$(_portable_dir)" || true |
| fi |
| } |
|
|
| |
| function ensurePortablePython() { |
| local pdir="$(_portable_dir)" |
| local pbin="$(_portable_bin)" |
| local pyexe |
|
|
| if [ -x "${pbin}/python3" ] || [ -x "${pbin}/python" ]; then |
| _macosPortableEnv |
| return 0 |
| fi |
|
|
| mkdir -p "${pdir}" |
| local triple="$(_triple)" |
|
|
| local full_ver="${PYTHON_VERSION}.${PYTHON_PATCH}" |
| local fn="" |
| if [ -n "${PORTABLE_PY_FILENAME}" ]; then |
| fn="${PORTABLE_PY_FILENAME}" |
| else |
| |
| fn="cpython-${full_ver}+${PY_STANDALONE_TAG}-${triple}-install_only.tar.gz" |
| fi |
|
|
| local url="https://github.com/astral-sh/python-build-standalone/releases/download/${PY_STANDALONE_TAG}/${fn}" |
| local tmp="${pdir}/${fn}" |
| echo "Downloading portable Python: ${fn}" |
| |
| if command -v curl >/dev/null 2>&1; then |
| curl -L --fail --retry 3 --retry-delay 1 -o "${tmp}" "${url}" |
| else |
| wget -O "${tmp}" "${url}" |
| fi |
|
|
| if [ -n "${PORTABLE_PY_SHA256}" ]; then |
| echo "${PORTABLE_PY_SHA256} ${tmp}" | sha256sum -c - |
| fi |
|
|
| echo "Extracting ${fn} -> ${pdir}" |
| |
| tar -xzf "${tmp}" -C "${pdir}" |
| rm -f "${tmp}" |
|
|
| |
| |
| local inner |
| inner="$(find "${pdir}" -type f -path "*/bin/python*" -maxdepth 3 2>/dev/null | head -n1 || true)" |
| if [ -n "${inner}" ]; then |
| local inner_root |
| inner_root="$(dirname "$(dirname "${inner}")")" |
| if [ "${inner_root}" != "${pdir}" ]; then |
| |
| shopt -s dotglob |
| mv "${inner_root}/"* "${pdir}/" |
| rm -rf "${inner_root}" |
| shopt -u dotglob |
| fi |
| fi |
|
|
| _unquarantinePortablePython |
| _macosPortableEnv |
| |
| pyexe="$(_portable_python)" |
| "${pyexe}" -V |
| } |
|
|
| |
| function init() { |
| BACKEND_NAME=${PWD##*/} |
| MY_DIR=$(realpath "$(dirname "$0")") |
| BUILD_PROFILE=$(getBuildProfile) |
|
|
| EDIR=${MY_DIR} |
| if [ "x${ENV_DIR:-}" != "x" ]; then |
| EDIR=${ENV_DIR} |
| fi |
|
|
| if [ ! -z "${LIMIT_TARGETS:-}" ]; then |
| isValidTarget=$(checkTargets ${LIMIT_TARGETS}) |
| if [ ${isValidTarget} != true ]; then |
| echo "${BACKEND_NAME} can only be used on the following targets: ${LIMIT_TARGETS}" |
| exit 0 |
| fi |
| fi |
|
|
| echo "Initializing libbackend for ${BACKEND_NAME}" |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| function getBuildProfile() { |
| if [ x"${BUILD_TYPE:-}" == "xcublas" ] || [ x"${BUILD_TYPE:-}" == "xl4t" ]; then |
| if [ ! -z "${CUDA_MAJOR_VERSION:-}" ]; then |
| echo ${BUILD_TYPE}${CUDA_MAJOR_VERSION} |
| else |
| echo ${BUILD_TYPE} |
| fi |
| return 0 |
| fi |
|
|
| if [ -d "/opt/intel" ]; then |
| echo "intel" |
| return 0 |
| fi |
|
|
| if [ -n "${BUILD_TYPE:-}" ]; then |
| echo ${BUILD_TYPE} |
| return 0 |
| fi |
|
|
| echo "cpu" |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| _makeVenvPortable() { |
| local update_pyvenv_cfg=false |
| if [ "${1:-}" = "--update-pyvenv-cfg" ]; then |
| update_pyvenv_cfg=true |
| fi |
|
|
| local venv_dir="${EDIR}/venv" |
| local vbin="${venv_dir}/bin" |
|
|
| [ -d "${vbin}" ] || return 0 |
|
|
| |
| |
| local rel_py='../../python/bin/python3' |
|
|
| for name in python3 python; do |
| if [ -e "${vbin}/${name}" ] || [ -L "${vbin}/${name}" ]; then |
| rm -f "${vbin}/${name}" |
| fi |
| done |
| ln -s "${rel_py}" "${vbin}/python3" |
| ln -s "python3" "${vbin}/python" |
|
|
| |
| |
| if [ "$update_pyvenv_cfg" = "true" ]; then |
| local pyvenv_cfg="${venv_dir}/pyvenv.cfg" |
| if [ -f "${pyvenv_cfg}" ]; then |
| local portable_dir="$(_portable_dir)" |
| |
| |
| if [ -d "${portable_dir}" ]; then |
| portable_dir="$(cd "${portable_dir}" && pwd)" |
| else |
| |
| portable_dir="../python" |
| fi |
| local sed_i=(sed -i) |
| |
| if sed --version >/dev/null 2>&1; then |
| sed_i=(sed -i) |
| else |
| sed_i=(sed -i '') |
| fi |
| |
| |
| if grep -q "^home = " "${pyvenv_cfg}"; then |
| "${sed_i[@]}" "s|^home = .*|home = ${portable_dir}|" "${pyvenv_cfg}" |
| else |
| |
| echo "home = ${portable_dir}" >> "${pyvenv_cfg}" |
| fi |
| fi |
| fi |
|
|
| |
| |
| local ve_abs="${vbin}/python" |
| local sed_i=(sed -i) |
| |
| if sed --version >/dev/null 2>&1; then |
| sed_i=(sed -i) |
| else |
| sed_i=(sed -i '') |
| fi |
|
|
| for f in "${vbin}"/*; do |
| [ -f "$f" ] || continue |
| |
| head -c2 "$f" 2>/dev/null | grep -q '^#!' || continue |
| |
| if head -n1 "$f" | grep -Fq "${ve_abs}"; then |
| "${sed_i[@]}" '1s|^#!.*$|#!/usr/bin/env python3|' "$f" |
| chmod +x "$f" 2>/dev/null || true |
| fi |
| done |
| } |
|
|
|
|
| |
| |
| |
| |
| function ensureVenv() { |
| local interpreter="" |
|
|
| if [ "x${PORTABLE_PYTHON}" == "xtrue" ] || [ -e "$(_portable_python)" ]; then |
| echo "Using portable Python" |
| ensurePortablePython |
| interpreter="$(_portable_python)" |
| else |
| |
| if command -v python${PYTHON_VERSION} >/dev/null 2>&1; then |
| interpreter="python${PYTHON_VERSION}" |
| elif command -v python3 >/dev/null 2>&1; then |
| interpreter="python3" |
| else |
| echo "No suitable system Python found, bootstrapping portable build..." |
| ensurePortablePython |
| interpreter="$(_portable_python)" |
| fi |
| fi |
|
|
| if [ ! -d "${EDIR}/venv" ]; then |
| if [ "x${USE_PIP}" == "xtrue" ]; then |
| "${interpreter}" -m venv --copies "${EDIR}/venv" |
| source "${EDIR}/venv/bin/activate" |
| "${interpreter}" -m pip install --upgrade pip |
| else |
| if [ "x${PORTABLE_PYTHON}" == "xtrue" ]; then |
| uv venv --python "${interpreter}" "${EDIR}/venv" |
| else |
| uv venv --python "${PYTHON_VERSION}" "${EDIR}/venv" |
| fi |
| fi |
| if [ "x${PORTABLE_PYTHON}" == "xtrue" ]; then |
| |
| _makeVenvPortable |
| fi |
| fi |
|
|
| |
| if [ -x "$(_portable_python)" ]; then |
| _macosPortableEnv |
| fi |
|
|
| if [ "x${VIRTUAL_ENV:-}" != "x${EDIR}/venv" ]; then |
| source "${EDIR}/venv/bin/activate" |
| fi |
| } |
|
|
|
|
| function runProtogen() { |
| ensureVenv |
| if [ "x${USE_PIP}" == "xtrue" ]; then |
| pip install grpcio-tools |
| else |
| uv pip install grpcio-tools |
| fi |
| pushd "${EDIR}" >/dev/null |
| |
| python -m grpc_tools.protoc -I../../ -I./ --python_out=. --grpc_python_out=. backend.proto |
| popd >/dev/null |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function installRequirements() { |
| ensureVenv |
| declare -a requirementFiles=( |
| "${EDIR}/requirements-install.txt" |
| "${EDIR}/requirements.txt" |
| "${EDIR}/requirements-${BUILD_TYPE:-}.txt" |
| ) |
|
|
| if [ "x${BUILD_TYPE:-}" != "x${BUILD_PROFILE}" ]; then |
| requirementFiles+=("${EDIR}/requirements-${BUILD_PROFILE}.txt") |
| fi |
| if [ "x${BUILD_TYPE:-}" == "x" ]; then |
| requirementFiles+=("${EDIR}/requirements-cpu.txt") |
| fi |
| requirementFiles+=("${EDIR}/requirements-after.txt") |
| if [ "x${BUILD_TYPE:-}" != "x${BUILD_PROFILE}" ]; then |
| requirementFiles+=("${EDIR}/requirements-${BUILD_PROFILE}-after.txt") |
| fi |
|
|
| |
| if [ "x${PORTABLE_PYTHON}" == "xtrue" ]; then |
| export C_INCLUDE_PATH="${C_INCLUDE_PATH:-}:$(_portable_dir)/include/python${PYTHON_VERSION}" |
| fi |
|
|
| for reqFile in ${requirementFiles[@]}; do |
| if [ -f "${reqFile}" ]; then |
| echo "starting requirements install for ${reqFile}" |
| if [ "x${USE_PIP}" == "xtrue" ]; then |
| pip install ${EXTRA_PIP_INSTALL_FLAGS:-} --requirement "${reqFile}" |
| else |
| uv pip install ${EXTRA_PIP_INSTALL_FLAGS:-} --requirement "${reqFile}" |
| fi |
| echo "finished requirements install for ${reqFile}" |
| fi |
| done |
|
|
| runProtogen |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function startBackend() { |
| ensureVenv |
| |
| |
| if [ "x${PORTABLE_PYTHON}" == "xtrue" ] || [ -x "$(_portable_python)" ]; then |
| _makeVenvPortable --update-pyvenv-cfg |
| fi |
|
|
| |
| |
| if [ -d "${EDIR}/lib" ]; then |
| export LD_LIBRARY_PATH="${EDIR}/lib:${LD_LIBRARY_PATH:-}" |
| echo "Added ${EDIR}/lib to LD_LIBRARY_PATH for GPU libraries" |
| fi |
|
|
| if [ ! -z "${BACKEND_FILE:-}" ]; then |
| exec "${EDIR}/venv/bin/python" "${BACKEND_FILE}" "$@" |
| elif [ -e "${MY_DIR}/server.py" ]; then |
| exec "${EDIR}/venv/bin/python" "${MY_DIR}/server.py" "$@" |
| elif [ -e "${MY_DIR}/backend.py" ]; then |
| exec "${EDIR}/venv/bin/python" "${MY_DIR}/backend.py" "$@" |
| elif [ -e "${MY_DIR}/${BACKEND_NAME}.py" ]; then |
| exec "${EDIR}/venv/bin/python" "${MY_DIR}/${BACKEND_NAME}.py" "$@" |
| fi |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| function runUnittests() { |
| ensureVenv |
| if [ ! -z "${TEST_FILE:-}" ]; then |
| testDir=$(dirname "$(realpath "${TEST_FILE}")") |
| testFile=$(basename "${TEST_FILE}") |
| pushd "${testDir}" >/dev/null |
| python -m unittest "${testFile}" |
| popd >/dev/null |
| elif [ -f "${MY_DIR}/test.py" ]; then |
| pushd "${MY_DIR}" >/dev/null |
| python -m unittest test.py |
| popd >/dev/null |
| else |
| echo "no tests defined for ${BACKEND_NAME}" |
| fi |
| } |
|
|
|
|
| |
| |
| |
|
|
| |
| function checkTargets() { |
| targets=$@ |
| declare -a targets=($targets) |
| for target in ${targets[@]}; do |
| if [ "x${BUILD_TYPE:-}" == "x${target}" ]; then |
| echo true; return 0 |
| fi |
| if [ "x${BUILD_PROFILE}" == "x${target}" ]; then |
| echo true; return 0 |
| fi |
| done |
| echo false |
| } |
|
|
| init |
|
|