Как собрать Telegram в Termux?

Рейтинг: 1Ответов: 1Опубликовано: 17.05.2023

Всем привет. Я пытаюсь скомпилировать Telegram для Android в Termux терминале. Мой девайс это OnePlus 9 Pro 12GB RAM на aarch64 процессоре. Это мой репо, где я работаю: https://github.com/diskree/TelegramTermux. Инструменты JDK, SDK и NDK я загрузил отсюда https://github.com/lzhiyong/termux-ndk/releases. Я уже успешно собрал несколько рандомных проектов с гитхаб, поэтому проблема не в моём окружении. Все инструкции для сборки, описанные в данном репозитории, соблюдены.

Telegram проект использует NDK r21e + CMake 3.10.2, но минимально поддерживаемыми версиями в Termux являются NDK r23c и CMake 3.23.1, поэтому пришлось обновить их в build.gradle файлах в модуле проекта TMessagesProj и в модуле приложения TMessagesProj_App.

Итак, вот ошибка:

C/C++: ld.lld: error: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol ff_cos_32; recompile with -fPIC
C/C++: ld.lld: error: relocation R_AARCH64_ADD_ABS_LO12_NC cannot be used against symbol ff_cos_32; recompile with -fPIC

Это проблема связана с ошибкой в компоновке ffmpeg библиотеки, следовательно, подумал я, придется собирать её самому. Подобных библиотек (которые лежат уже скомпилированные в исходниках), четыре - boringssl, ffmpeg, libvpx, libwebp. Я решил сделать с ними, то же самое, что сделано в форке https://github.com/Telegram-FOSS-Team/Telegram-FOSS - компиляцию из исходников. Так же я попытался обновить скрипты сборки libvpx и ffmpeg с учётом структуры новых версий NDK, а заодно исправить ошибку, добавив флаг -fPIC:

Уточню, также, что сборка должна запуститься только на моём девайсе, поэтому все архитектуры, кроме arm64 отключены во всех конфигурациях сборки gradle.

Вот обновлённый скрипт для сборки libvpx:

#!/bin/bash
set -e

function build_one {
    echo "Building ${ARCH}..."

    PLATFORM=${NDK}/platforms/android-${ANDROID_API}/arch-${ARCH}

    TOOLS_PREFIX="${LLVM_BIN}/${ARCH_NAME}-linux-${BIN_MIDDLE}-"

    export LD="${LLVM_BIN}/ld.lld"
    export AR="${LLVM_BIN}/llvm-ar"
    export STRIP="${LLVM_BIN}/llvm-strip"
    export RANLIB="${LLVM_BIN}/llvm-ranlib"
    export NM="${LLVM_BIN}/llvm-nm"

    export CC_PREFIX="${LLVM_BIN}/${CLANG_PREFIX}-linux-${BIN_MIDDLE}${ANDROID_API}-"

    export CC=${CC_PREFIX}clang
    export CXX=${CC_PREFIX}clang++
    export AS="${LLVM_PREFIX}/${ARCH_NAME}-linux-${BIN_MIDDLE}/bin/as"

    export CFLAGS="-DANDROID -fpic -fpie ${OPTIMIZE_CFLAGS}"
    export CPPFLAGS="${CFLAGS}"
    export CXXFLAGS="${CFLAGS} -std=c++11"
    export ASFLAGS="-D__ANDROID__"
    export LDFLAGS="-L${PLATFORM}/usr/lib"
    
    if [ "x86" = ${ARCH} ]; then
        sed -i '20s/^/#define rand() ((int)lrand48())\n/' vpx_dsp/add_noise.c
    fi

    echo "Cleaning..."
    make clean || true

    echo "Configuring..."

    ./configure \
    --extra-cflags="-isystem ${LLVM_PREFIX}/sysroot/usr/include/${ARCH_NAME}-linux-${BIN_MIDDLE} -isystem ${LLVM_PREFIX}/sysroot/usr/include" \
    --libc="${LLVM_PREFIX}/sysroot" \
    --prefix=${PREFIX} \
    --target=${TARGET} \
    ${CPU_DETECT} \
    --as=yasm \
    --enable-static \
    --enable-pic \
    --disable-docs \
    --enable-libyuv \
    --enable-small \
    --enable-optimizations \
    --enable-better-hw-compatibility \
    --disable-examples \
    --disable-tools \
    --disable-debug \
    --disable-unit-tests \
    --disable-install-docs \
    --enable-realtime-only \
    --enable-vp8 \
    --enable-vp9 \
    --disable-webm-io

    make -j$COMPILATION_PROC_COUNT install
    
    if [ "x86" = ${ARCH} ]; then
        sed -i '20d' vpx_dsp/add_noise.c
    fi
}

function setCurrentPlatform {

    CURRENT_PLATFORM="$(uname -s)"
    case "${CURRENT_PLATFORM}" in
        Darwin*)
            BUILD_PLATFORM=darwin-x86_64
            COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
            ;;
        Linux*)
            BUILD_PLATFORM=linux-x86_64
            COMPILATION_PROC_COUNT=$(nproc)
            ;;
        *)
            echo -e "\033[33mWarning! Unknown platform ${CURRENT_PLATFORM}! falling back to linux-x86_64\033[0m"
            BUILD_PLATFORM=linux-x86_64
            COMPILATION_PROC_COUNT=1
            ;;
    esac

    echo "Build platform: ${BUILD_PLATFORM}"
    echo "Parallel jobs: ${COMPILATION_PROC_COUNT}"

}

function checkPreRequisites {

    if ! [ -d "libvpx" ] || ! [ "$(ls -A libvpx)" ]; then
        echo -e "\033[31mFailed! Submodule 'libvpx' not found!\033[0m"
        echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
        exit
    fi

    if [ -z "$NDK" -a "$NDK" == "" ]; then
        echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
        exit
    fi
}

setCurrentPlatform
checkPreRequisites

cd libvpx

#common
LLVM_PREFIX="${NDK}/toolchains/llvm/prebuilt/linux-x86_64"
LLVM_BIN="${LLVM_PREFIX}/bin"
VERSION="4.9"
ANDROID_API=21

function build {
    for arg in "$@"; do
        case "${arg}" in
            x86_64)
                ARCH=x86_64
                ARCH_NAME=x86_64
                PREBUILT_ARCH=x86_64
                CLANG_PREFIX=x86_64
                BIN_MIDDLE=android
                CPU=x86_64
                OPTIMIZE_CFLAGS="-O3 -march=x86-64 -mtune=intel -msse4.2 -mpopcnt -m64 -fPIC"
                TARGET="x86_64-android-gcc"
                PREFIX=./build/$CPU
                CPU_DETECT="--enable-runtime-cpu-detect"
                build_one
            ;;
            x86)
                ARCH=x86
                ARCH_NAME=i686
                PREBUILT_ARCH=x86
                CLANG_PREFIX=i686
                BIN_MIDDLE=android
                CPU=i686
                OPTIMIZE_CFLAGS="-O3 -march=i686 -mtune=intel -msse3 -mfpmath=sse -m32 -fPIC"
                TARGET="x86-android-gcc"
                PREFIX=./build/$ARCH
                CPU_DETECT="--enable-runtime-cpu-detect"
                build_one
            ;;
            arm64)
                ARCH=arm64
                ARCH_NAME=aarch64
                PREBUILT_ARCH=aarch64
                CLANG_PREFIX=aarch64
                BIN_MIDDLE=android
                CPU=arm64-v8a
                OPTIMIZE_CFLAGS="-O3 -march=armv8-a -fPIC"
                TARGET="arm64-android-gcc"
                PREFIX=./build/$CPU
                CPU_DETECT="--disable-runtime-cpu-detect"
                build_one
            ;;
            arm)
                ARCH=arm
                ARCH_NAME=arm
                PREBUILT_ARCH=arm
                CLANG_PREFIX=armv7a
                BIN_MIDDLE=androideabi
                CPU=armeabi-v7a
                OPTIMIZE_CFLAGS="-Os -march=armv7-a -mfloat-abi=softfp -mfpu=neon -mtune=cortex-a8 -mthumb -D__thumb__"
                TARGET="armv7-android-gcc --enable-neon --disable-neon-asm"
                PREFIX=./build/$CPU
                CPU_DETECT="--disable-runtime-cpu-detect"
                build_one
            ;;
            *)
            ;;
        esac
    done
}

if (( $# == 0 )); then
    build x86_64 x86 arm arm64
else
    build $@
fi

И для сборки ffmpeg:

#!/bin/bash
set -e
function build_one {
    echo "Building ${ARCH}..."

    PLATFORM=${NDK}/platforms/android-${ANDROID_API}/arch-${ARCH}

    TOOLS_PREFIX="${LLVM_BIN}/${ARCH_NAME}-linux-${BIN_MIDDLE}-"

    LD="${LLVM_BIN}/ld.lld"
    AR="${LLVM_BIN}/llvm-ar"
    STRIP="${LLVM_BIN}/llvm-strip"
    NM="${LLVM_BIN}/llvm-nm"

    CC_PREFIX="${LLVM_BIN}/${CLANG_PREFIX}-linux-${BIN_MIDDLE}${ANDROID_API}-"

    CC=${CC_PREFIX}clang
    CXX=${CC_PREFIX}clang++
    
    INCLUDES=" -I${LIBVPXPREFIX}/include"
    LIBS=" -L${LIBVPXPREFIX}/lib"

    echo "Cleaning..."
    rm -f config.h
    make clean || true

    echo "Configuring..."

    ./configure \
    --nm=${NM} \
    --ar=${AR} \
    --strip=${STRIP} \
    --cc=${CC} \
    --cxx=${CXX} \
    --enable-stripping \
    --arch=$ARCH \
    --target-os=android \
    --enable-cross-compile \
    --x86asmexe=$NDK/prebuilt/${BUILD_PLATFORM}/bin/yasm \
    --prefix=$PREFIX \
    --enable-pic \
    --disable-shared \
    --enable-static \
    --enable-asm \
    --enable-inline-asm \
    --enable-x86asm \
    --cross-prefix=$CROSS_PREFIX \
    --sysroot="${LLVM_PREFIX}/sysroot" \
    --extra-cflags="${INCLUDES} -Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
    --extra-cxxflags="${INCLUDES} -Wl,-Bsymbolic -Os -DCONFIG_LINUX_PERF=0 -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static -fPIC" \
    --extra-ldflags="${LIBS} -Wl,-Bsymbolic -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -fPIC" \
    \
    --enable-version3 \
    --enable-gpl \
    \
    --disable-linux-perf \
    \
    --disable-doc \
    --disable-htmlpages \
    --disable-avx \
    \
    --disable-everything \
    --disable-network \
    --disable-zlib \
    --disable-avfilter \
    --disable-avdevice \
    --disable-postproc \
    --disable-debug \
    --disable-programs \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-postproc \
    --disable-avdevice \
    \
    --enable-libvpx \
    --enable-decoder=libvpx_vp9 \
    --enable-runtime-cpudetect \
    --enable-pthreads \
    --enable-avresample \
    --enable-swscale \
    --enable-protocol=file \
    --enable-decoder=opus \
    --enable-decoder=h264 \
    --enable-decoder=mpeg4 \
    --enable-decoder=mjpeg \
    --enable-decoder=gif \
    --enable-decoder=alac \
    --enable-demuxer=mov \
    --enable-demuxer=gif \
    --enable-demuxer=ogg \
    --enable-demuxer=matroska \
    --enable-hwaccels \
    $ADDITIONAL_CONFIGURE_FLAG

    #echo "continue?"
    #read
    make -j$COMPILATION_PROC_COUNT
    make install
}

function setCurrentPlatform {

    CURRENT_PLATFORM="$(uname -s)"
    case "${CURRENT_PLATFORM}" in
        Darwin*)
            BUILD_PLATFORM=darwin-x86_64
            COMPILATION_PROC_COUNT=`sysctl -n hw.physicalcpu`
            ;;
        Linux*)
            BUILD_PLATFORM=linux-x86_64
            COMPILATION_PROC_COUNT=$(nproc)
            ;;
        *)
            echo -e "\033[33mWarning! Unknown platform ${CURRENT_PLATFORM}! falling back to linux-x86_64\033[0m"
            BUILD_PLATFORM=linux-x86_64
            COMPILATION_PROC_COUNT=1
            ;;
    esac

    echo "Build platform: ${BUILD_PLATFORM}"
    echo "Parallel jobs: ${COMPILATION_PROC_COUNT}"

}

function checkPreRequisites {

    if ! [ -d "ffmpeg" ] || ! [ "$(ls -A ffmpeg)" ]; then
        echo -e "\033[31mFailed! Submodule 'ffmpeg' not found!\033[0m"
        echo -e "\033[31mTry to run: 'git submodule init && git submodule update'\033[0m"
        exit
    fi

    if [ -z "$NDK" -a "$NDK" == "" ]; then
        echo -e "\033[31mFailed! NDK is empty. Run 'export NDK=[PATH_TO_NDK]'\033[0m"
        exit
    fi
}

setCurrentPlatform
checkPreRequisites

# TODO: fix env variable for NDK
# NDK=/opt/android-sdk/ndk-bundle

cd ffmpeg

## common
LLVM_PREFIX="${NDK}/toolchains/llvm/prebuilt/linux-x86_64"
LLVM_BIN="${LLVM_PREFIX}/bin"
VERSION="4.9"

function build {
    for arg in "$@"; do
        case "${arg}" in
            x86_64)
                ANDROID_API=21

                ARCH=x86_64
                ARCH_NAME=x86_64
                PREBUILT_ARCH=x86_64
                PREBUILT_MIDDLE=
                CLANG_PREFIX=x86_64
                BIN_MIDDLE=android
                CPU=x86_64
                PREFIX=./build/$CPU
                LIBVPXPREFIX=../libvpx/build/$ARCH_NAME
                ADDITIONAL_CONFIGURE_FLAG="--disable-asm"
                build_one
            ;;
            arm64)
                ANDROID_API=21

                ARCH=arm64
                ARCH_NAME=aarch64
                PREBUILT_ARCH=aarch64
                PREBUILT_MIDDLE="-linux-android"
                CLANG_PREFIX=aarch64
                BIN_MIDDLE=android
                CPU=arm64-v8a
                OPTIMIZE_CFLAGS=
                PREFIX=./build/$CPU
                LIBVPXPREFIX=../libvpx/build/$CPU
                ADDITIONAL_CONFIGURE_FLAG="--enable-neon --enable-optimizations"
                build_one
            ;;
            arm)
                ANDROID_API=16

                ARCH=arm
                ARCH_NAME=arm
                PREBUILT_ARCH=arm
                PREBUILT_MIDDLE="-linux-androideabi"
                CLANG_PREFIX=armv7a
                BIN_MIDDLE=androideabi
                CPU=armv7-a
                OPTIMIZE_CFLAGS="-marm -march=$CPU"
                PREFIX=./build/armeabi-v7a
                LIBVPXPREFIX=../libvpx/build/armeabi-v7a
                ADDITIONAL_CONFIGURE_FLAG=--enable-neon
                build_one
            ;;
            x86)
                ANDROID_API=16

                ARCH=x86
                ARCH_NAME=i686
                PREBUILT_ARCH=x86
                PREBUILT_MIDDLE=
                CLANG_PREFIX=i686
                BIN_MIDDLE=android
                CPU=i686
                OPTIMIZE_CFLAGS="-march=$CPU"
                PREFIX=./build/$ARCH
                LIBVPXPREFIX=../libvpx/build/$ARCH
                ADDITIONAL_CONFIGURE_FLAG="--disable-x86asm --disable-inline-asm --disable-asm"
                build_one
            ;;
            *)
            ;;
        esac
    done
}

if (( $# == 0 )); then
    build x86_64 arm64 arm x86
else
    build $@
fi

Так же я написал скрипт, который сам забирает нужные версии исходников всех внешних библиотек по хешам коммитов, указанным в FOSS форке как git subversion, и компилирует их только для arm64 (архитектура моего девайса):

/data/data/com.termux/files/usr/bin/su -c "rm -r boringssl"
/data/data/com.termux/files/usr/bin/su -c "rm -r ffmpeg"
/data/data/com.termux/files/usr/bin/su -c "rm -r libvpx"
/data/data/com.termux/files/usr/bin/su -c "rm -r libwebp"

git clone https://github.com/google/boringssl boringssl
cd boringssl
git checkout a6d321b11fa80496b7c8ae6405468c212d4f5c87
cd ..
git clone https://github.com/FFmpeg/FFmpeg ffmpeg
cd ffmpeg
git checkout 4bc4cafaef8a55462138d7b6f7579c1522de26dc
cd ..
git clone https://github.com/webmproject/libvpx libvpx
cd libvpx
git checkout d6eb9696aa72473c1a11d34d928d35a3acc0c9a9
cd ..
git clone https://github.com/webmproject/libwebp libwebp
cd libwebp
git checkout 113968ca47b1d1affbfe88472364b15699e239d6
cd ..
export NDK=~/storage/ndk
export NINJA_PATH=~/storage/sdk/cmake/3.23.1/bin/ninja
./build_libvpx_clang.sh arm64
./build_ffmpeg_clang.sh arm64
./patch_ffmpeg.sh
./patch_boringssl.sh
./build_boringssl.sh arm64

Так вот, вся эта работа тоже ничего не дала. ошибка осталась, хотя -fPIC указан во флагах конфигурации ffmpeg. Что можно сделать?

Ответы

▲ 1Принят

Нужно было добавить -Wl,-Bsymbolic в CMAKE_SHARED_LINKER_FLAGS внутри CMakeLists.txt. Я нашел этот фикс, гуляя по обсуждению схожих проблем на гитхабе. После этого телега наконец-то собралась в термуксе!

Также я вернулся к проекту стандартного Telegram, так как компиляция библиотек от FOSS не нужна. Вот мой репо: https://github.com/diskree/Telegram-Termux