Как собрать Telegram в Termux?
Всем привет. Я пытаюсь скомпилировать 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
.
Что можно сделать?