Spaces:
Paused
Paused
| FROM python:3.11-bookworm | |
| # Устанавливаем зависимости. | |
| # Добавлены ninja-build и gfortran, которые часто требуются для сборки numpy/scipy | |
| RUN apt-get update && apt-get install -y \ | |
| wget unzip git build-essential pkg-config \ | |
| libffi-dev libssl-dev zlib1g-dev ncurses-dev \ | |
| libsqlite3-dev libreadline-dev libbz2-dev liblzma-dev \ | |
| uuid-dev curl \ | |
| cmake llvm clang \ | |
| perl ninja-build gfortran \ | |
| patchelf zip \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # === НАСТРОЙКА ОКРУЖЕНИЯ (как в примере) === | |
| ENV WORK_DIR=/build | |
| ENV OUTPUT_DIR=/app/wheels | |
| ENV NDK_VERSION=r26b | |
| ENV ANDROID_API=24 | |
| ENV ANDROID_ARCH=aarch64 | |
| ENV ANDROID_HOME=/opt/android-sdk | |
| ENV NDK_HOME=/opt/android-ndk | |
| ENV ANDROID_NDK_ROOT=/opt/android-ndk | |
| ENV PYTHON_VERSION=3.11.9 | |
| ENV OPENSSL_VERSION=3.3.0 | |
| ENV RUSTUP_HOME=/opt/rust | |
| ENV CARGO_HOME=/opt/rust | |
| ENV PATH=$PATH:/opt/rust/bin | |
| # === УСТАНОВКА RUST (Для pedalboard) === | |
| RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable | |
| RUN rustup target add aarch64-linux-android | |
| # === ПОДГОТОВКА PYTHON ИНСТРУМЕНТОВ === | |
| RUN pip install --upgrade pip && \ | |
| pip install --no-cache-dir \ | |
| Cython wheel setuptools poetry-core hatchling \ | |
| hatch-fancy-pypi-readme hatch-vcs flit-core \ | |
| expandvars maturin typing-extensions meson-python ninja | |
| WORKDIR ${WORK_DIR} | |
| # === УСТАНОВКА NDK === | |
| RUN wget -q https://dl.google.com/android/repository/android-ndk-${NDK_VERSION}-linux.zip && \ | |
| unzip -q android-ndk-${NDK_VERSION}-linux.zip && \ | |
| mv android-ndk-${NDK_VERSION} ${NDK_HOME} && \ | |
| rm android-ndk-${NDK_VERSION}-linux.zip | |
| ENV TOOLCHAIN=${NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64 | |
| ENV PATH=${TOOLCHAIN}/bin:$PATH | |
| ENV TARGET=${ANDROID_ARCH}-linux-android${ANDROID_API} | |
| ENV CC="${TOOLCHAIN}/bin/${TARGET}-clang" | |
| ENV CXX="${TOOLCHAIN}/bin/${TARGET}-clang++" | |
| ENV AR="${TOOLCHAIN}/bin/llvm-ar" | |
| ENV NM="${TOOLCHAIN}/bin/llvm-nm" | |
| ENV LD="${TOOLCHAIN}/bin/ld" | |
| ENV RANLIB="${TOOLCHAIN}/bin/llvm-ranlib" | |
| ENV STRIP="${TOOLCHAIN}/bin/llvm-strip" | |
| ENV READELF="${TOOLCHAIN}/bin/llvm-readelf" | |
| ENV CFLAGS="-target ${TARGET} -fPIC -D__ANDROID__" | |
| ENV CXXFLAGS="-target ${TARGET} -fPIC -D__ANDROID__" | |
| ENV LDFLAGS="-target ${TARGET} -fPIC" | |
| # === СБОРКА OPENSSL (Для зависимостей pedalboard/rust) === | |
| WORKDIR ${WORK_DIR} | |
| RUN wget -q https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz && \ | |
| tar -xf openssl-${OPENSSL_VERSION}.tar.gz | |
| WORKDIR ${WORK_DIR}/openssl-${OPENSSL_VERSION} | |
| RUN ./Configure android-arm64 \ | |
| -D__ANDROID_API__=${ANDROID_API} \ | |
| --prefix=${WORK_DIR}/openssl-install \ | |
| --openssldir=${WORK_DIR}/openssl-install \ | |
| no-shared no-tests | |
| RUN make -j$(nproc) && make install_sw | |
| ENV OPENSSL_DIR=${WORK_DIR}/openssl-install | |
| ENV OPENSSL_LIB_DIR=${OPENSSL_DIR}/lib64 | |
| ENV OPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/include | |
| ENV OPENSSL_STATIC=1 | |
| # === СБОРКА PYTHON (HOST) ДЛЯ ЗАГОЛОВКОВ === | |
| WORKDIR ${WORK_DIR} | |
| RUN wget -q https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz && \ | |
| tar -xf Python-${PYTHON_VERSION}.tgz | |
| WORKDIR ${WORK_DIR}/Python-${PYTHON_VERSION} | |
| # Фейковые настройки конфигурации для кросс-компиляции | |
| RUN echo "ac_cv_file__dev_ptmx=yes" > config.site && \ | |
| echo "ac_cv_file__dev_ptc=no" >> config.site && \ | |
| echo "ac_cv_func_wcsftime=no" >> config.site && \ | |
| echo "ac_cv_func_gethostbyname_r=no" >> config.site && \ | |
| echo "ac_cv_func_sendfile=no" >> config.site && \ | |
| echo "ac_cv_func_broken_mbstowcs=no" >> config.site && \ | |
| echo "ac_cv_func_wcscoll=no" >> config.site | |
| RUN CONFIG_SITE=config.site ./configure \ | |
| CFLAGS="${CFLAGS}" \ | |
| LDFLAGS="${LDFLAGS}" \ | |
| --host=aarch64-linux-android \ | |
| --build=x86_64-linux-gnu \ | |
| --prefix=${WORK_DIR}/python-install \ | |
| --disable-ipv6 \ | |
| --enable-shared \ | |
| --without-ensurepip \ | |
| --with-build-python=/usr/local/bin/python3 \ | |
| --disable-test-modules \ | |
| --without-doc-strings \ | |
| --with-system-ffi=no \ | |
| --without-decimal \ | |
| --without-ctypes | |
| RUN make -j$(nproc) libpython3.11.so || true | |
| RUN make install -i | |
| RUN mkdir -p ${WORK_DIR}/python-install/lib/python3.11 | |
| # Хак для sysconfigdata, чтобы setuptools думал, что мы на arm64 | |
| RUN find ${WORK_DIR}/Python-${PYTHON_VERSION} -name "_sysconfigdata*.py" -not -name "*x86_64*" \ | |
| -exec cp {} ${WORK_DIR}/python-install/lib/python3.11/_sysconfigdata__linux_aarch64-linux-android.py \; | |
| RUN cp ${WORK_DIR}/python-install/lib/python3.11/_sysconfigdata__linux_aarch64-linux-android.py \ | |
| /usr/local/lib/python3.11/_sysconfigdata__linux_aarch64-linux-android.py | |
| WORKDIR ${OUTPUT_DIR} | |
| # === НАСТРОЙКИ RUST ДЛЯ КРОСС-КОМПИЛЯЦИИ === | |
| ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="${CC}" | |
| ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_RUSTFLAGS="-C link-arg=-L${WORK_DIR}/python-install/lib -C link-arg=-lpython3.11 -L ${OPENSSL_LIB_DIR}" | |
| # === СКРИПТ СБОРКИ === | |
| RUN echo "#!/bin/bash" > build.sh && \ | |
| echo "set -e" >> build.sh && \ | |
| echo "export PYTHON_ANDROID_HOME=${WORK_DIR}/python-install" >> build.sh && \ | |
| echo "export CFLAGS=\"${CFLAGS} -I\${PYTHON_ANDROID_HOME}/include/python3.11 -I${OPENSSL_INCLUDE_DIR}\"" >> build.sh && \ | |
| echo "export LDFLAGS=\"${LDFLAGS} -L\${PYTHON_ANDROID_HOME}/lib -L${OPENSSL_LIB_DIR}\"" >> build.sh && \ | |
| echo "export LDSHARED=\"${CC} -shared\"" >> build.sh && \ | |
| echo "export _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata__linux_aarch64-linux-android" >> build.sh && \ | |
| echo "export _PYTHON_HOST_PLATFORM=linux-aarch64" >> build.sh && \ | |
| # Переменные для PyO3 (Pedalboard) | |
| echo "export PYO3_CROSS_LIB_DIR=${WORK_DIR}/python-install/lib" >> build.sh && \ | |
| echo "export PYO3_CROSS_INCLUDE_DIR=${WORK_DIR}/python-install/include/python3.11" >> build.sh && \ | |
| echo "export PYO3_CROSS_PYTHON_VERSION=3.11" >> build.sh && \ | |
| echo "export CARGO_BUILD_TARGET=aarch64-linux-android" >> build.sh && \ | |
| echo "export PYO3_NO_PYTHON_VERSION_CHECK=1" >> build.sh && \ | |
| # Переменные для OpenSSL crate | |
| echo "export AARCH64_LINUX_ANDROID_OPENSSL_DIR=${OPENSSL_DIR}" >> build.sh && \ | |
| echo "export AARCH64_LINUX_ANDROID_OPENSSL_LIB_DIR=${OPENSSL_LIB_DIR}" >> build.sh && \ | |
| echo "export AARCH64_LINUX_ANDROID_OPENSSL_INCLUDE_DIR=${OPENSSL_INCLUDE_DIR}" >> build.sh && \ | |
| echo "export OPENSSL_STATIC=1" >> build.sh && \ | |
| # === СПЕЦИФИКА NUMPY === | |
| # Отключаем поиск внешних библиотек BLAS/LAPACK, чтобы избежать ошибок линковки. | |
| # Numpy соберется с упрощенной линейной алгеброй. | |
| echo "export NPY_BLAS_ORDER=''" >> build.sh && \ | |
| echo "export NPY_LAPACK_ORDER=''" >> build.sh && \ | |
| echo "export NPY_DISABLE_SVML=1" >> build.sh && \ | |
| echo "" >> build.sh && \ | |
| echo "echo 'Starting Build for Numpy and Pedalboard...'" >> build.sh && \ | |
| # Сборка. Используем --no-deps, чтобы собирать колеса по одному (или вместе, но контролируемо) | |
| echo "pip wheel numpy pedalboard --wheel-dir=${OUTPUT_DIR} --no-binary=:all: --no-build-isolation -v" >> build.sh && \ | |
| chmod +x build.sh | |
| RUN ./build.sh | |
| # === POST-PROCESSING (PATCHELF) === | |
| # Патчим зависимость от libpython3.11.so.1.0 -> libpython3.11.so | |
| RUN echo "Patching wheels..." && \ | |
| for whl in *.whl; do \ | |
| echo "Processing $whl..."; \ | |
| mkdir -p tmp_wheel; \ | |
| unzip -q "$whl" -d tmp_wheel; \ | |
| find tmp_wheel -name "*.so" | while read so_file; do \ | |
| if patchelf --print-needed "$so_file" | grep -q "libpython3.11.so.1.0"; then \ | |
| echo " -> Patching $so_file"; \ | |
| patchelf --replace-needed "libpython3.11.so.1.0" "libpython3.11.so" "$so_file"; \ | |
| fi; \ | |
| done; \ | |
| cd tmp_wheel; \ | |
| zip -r -q "../$whl" .; \ | |
| cd ..; \ | |
| rm -rf tmp_wheel; \ | |
| done | |
| # === ПЕРЕИМЕНОВАНИЕ В ANDROID TAG === | |
| RUN for f in *.whl; do \ | |
| if [ -f "$f" ]; then \ | |
| new_name=$(echo "$f" | sed 's/linux_aarch64/android_24_arm64_v8a/g'); \ | |
| if [ "$f" != "$new_name" ]; then \ | |
| mv "$f" "$new_name"; \ | |
| fi \ | |
| fi \ | |
| done | |
| # === ГЕНЕРАЦИЯ ИНДЕКСА === | |
| RUN echo "<html><head><title>Android Wheels</title></head><body>" > index.html && \ | |
| echo "<h1>Numpy & Pedalboard Wheels (API 24, ARM64)</h1><ul>" >> index.html && \ | |
| find . -name "*.whl" -printf "<li><a href=\"%P\">%P</a></li>\n" | sort >> index.html && \ | |
| echo "</ul></body></html>" >> index.html | |
| EXPOSE 7860 | |
| CMD ["python3", "-m", "http.server", "7860"] |