diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..00a51aff5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# These are explicitly windows files and should use crlf +*.bat text eol=crlf + diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2ed2cdd3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build + +# Ignore Gradle local options +local.properties diff --git a/CMakeLists.txt b/CMakeLists.txt index 93c8b04a5..64dd17dd9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,11 @@ set( CACHE STRING "Path where to install RetroShare system wide data" ) +option( + RS_EXPORT_JNI_ONLOAD + "Export libretroshare JNI_OnLoad. See src/rs_android/rsjni.cpp for details" + ON ) + ################################################################################ find_package(Git REQUIRED) @@ -163,6 +168,9 @@ target_include_directories( ${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ) +install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +# TODO: install public headers find_package(OpenSSL REQUIRED) target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSSL_INCLUDE_DIR}) @@ -199,6 +207,7 @@ if(RS_BITDHT) CHECK_PASS "BitDHT submodule found at ${BITDHT_DEVEL_DIR} using it" ) add_subdirectory(${BITDHT_DEVEL_DIR} ${CMAKE_BINARY_DIR}/bitdht) + set(RS_BITDHT_DIR "${BITDHT_DEVEL_DIR}") else() FetchContent_Declare( bitdht @@ -209,6 +218,8 @@ if(RS_BITDHT) TIMEOUT 10 ) FetchContent_MakeAvailable(bitdht) + + set(RS_BITDHT_DIR "${bitdht_SOURCE_DIR}") endif() add_compile_definitions(RS_USE_BITDHT) @@ -230,9 +241,6 @@ if(RS_JSON_API) find_package(Doxygen REQUIRED) find_package(Python3 REQUIRED) - ## TODO: execute at build time instead that at cofiguration time see - ## add_custom_command or add_custom_target - set( JSON_API_GENERATOR_WORK_DIR "${CMAKE_BINARY_DIR}/jsonapi-generator.workdir/" ) @@ -379,7 +387,7 @@ if(RS_BRODCAST_DISCOVERY) ) FetchContent_MakeAvailable(udp-discovery-cpp) - target_link_libraries(${PROJECT_NAME} PRIVATE udp-discovery-cpp) + target_link_libraries(${PROJECT_NAME} PRIVATE udp-discovery) ## TODO: Temporary work around target_include_directories should be added ## upstream @@ -407,5 +415,43 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") add_compile_definitions(RS_DATA_DIR="${RS_DATA_DIR}") endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") +################################################################################ + +if(RS_EXPORT_JNI_ONLOAD) + add_compile_definitions(RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD) +endif(RS_EXPORT_JNI_ONLOAD) + +################################################################################ + +#if(CMAKE_SYSTEM_NAME STREQUAL "Android") +if(RS_ANDROID) + FetchContent_Declare( + jni-hpp + GIT_REPOSITORY "https://gitlab.com/RetroShare/jni-hpp.git" + GIT_TAG "origin/master" + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + TIMEOUT 10 + ) + FetchContent_MakeAvailable(jni-hpp) + + include_directories(${jni-hpp_SOURCE_DIR}/include) + + if(RS_BITDHT) + set(RS_ANDROID_ASSETS_DIR "${CMAKE_BINARY_DIR}/android-assets") + set(RS_ANDROID_VALUES_DIR "${RS_ANDROID_ASSETS_DIR}/values") + file(MAKE_DIRECTORY "${RS_ANDROID_VALUES_DIR}") + file( + COPY "${RS_BITDHT_DIR}/src/bitdht/bdboot.txt" + DESTINATION "${RS_ANDROID_VALUES_DIR}" ) + set( + ANDROID_ASSETS_DIRECTORIES + "${RS_ANDROID_ASSETS_DIR};${ANDROID_ASSETS_DIRECTORIES}" ) + endif(RS_BITDHT) +endif(RS_ANDROID) +#endif(CMAKE_SYSTEM_NAME STREQUAL "Android") + +################################################################################ + ## Useful to debug CMake -#set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..69eeb1d02 --- /dev/null +++ b/build.gradle @@ -0,0 +1,226 @@ +/* + * libretroshare Android AAR library gradle builder + * + * Copyright (C) 2022 Gioacchino Mazzurco + * Copyright (C) 2022 Asociación Civil Altermundi + * + * SPDX-License-Identifier: CC0-1.0 + */ + +buildscript +{ + repositories + { + // The order in which you list these repositories matter. + google() + mavenCentral() + } + + dependencies + { + classpath 'com.android.tools.build:gradle:7.1.+' + } +} + +allprojects +{ + repositories + { + // The order in which you list these repositories matter. + google() + mavenCentral() + } +} + +ext.buildLibretroshareNativeLib = +{ + pApiLevel, /* Android API level */ + pAbi, /* Arch name as seen in AAR native libraries directories */ + pNdkPath, /* Android NDK path */ + pReuseToolchain = true /* If true reuse previously built toochain */ -> + + /* Convert pAbi into corresponding prepare toolchain ANDROID_NDK_ARCH */ + def toolchainArch = "unsupported" + def libcxxsharedTriple = "unsupported" + switch(pAbi) + { + case "armeabi-v7a": + toolchainArch = "arm"; + libcxxsharedTriple = "arm-linux-androideabi"; + break; + case "arm64-v8a": + toolchainArch = "arm64"; + libcxxsharedTriple = "aarch64-linux-android"; + break; + default: + throw new GradleException( + "buildLibretroshareNativeLib unsupported pAbi: $pAbi" ); + break; + } + + def toolchainsWorkdir = "${buildDir}/native_toolchains/" + mkdir toolchainsWorkdir + + def currToolchainPath = "$toolchainsWorkdir/$pApiLevel-$toolchainArch/" + + // Todo: use proper way to resolve the script path + def toolChainScriptPath = "${projectDir}/../build_scripts/Android/prepare-toolchain-clang.sh" + + if(!pReuseToolchain || !file(currToolchainPath).exists()) + { + exec + { + workingDir toolchainsWorkdir + environment "ANDROID_NDK_PATH", pNdkPath + environment "NATIVE_LIBS_TOOLCHAIN_PATH", currToolchainPath + environment "ANDROID_PLATFORM_VER", pApiLevel + environment "ANDROID_NDK_ARCH", toolchainArch + commandLine toolChainScriptPath /*, 'build_libretroshare'*/ + } + } + else + {/* + exec + { + workingDir toolchainsWorkdir + environment "ANDROID_NDK_PATH", pNdkPath + environment "NATIVE_LIBS_TOOLCHAIN_PATH", currToolchainPath + environment "ANDROID_PLATFORM_VER", pApiLevel + environment "ANDROID_NDK_ARCH", toolchainArch + commandLine toolChainScriptPath, 'build_libretroshare' + }*/ + } + + def nativeLibsDir = "${buildDir}/native_libs-$pApiLevel/" + mkdir nativeLibsDir + + def currAbiLibDir = "${nativeLibsDir}/$pAbi/" + mkdir currAbiLibDir + copy + { + from "${currToolchainPath}/sysroot/usr/lib/libretroshare.so" + into currAbiLibDir + } + + copy + { + from "${currToolchainPath}/sysroot/usr/lib/${libcxxsharedTriple}/libc++_shared.so" + into currAbiLibDir + } +} + +apply plugin: 'com.android.library' +apply plugin: 'maven-publish' + +android +{ + // see https://stackoverflow.com/questions/27301867/what-is-compilesdkversion + compileSdkVersion 21 + + sourceSets + { + main + { + java.srcDirs = [ 'src/rs_android/' ] + manifest.srcFile 'src/rs_android/AndroidManifest.xml' + assets.srcDirs = [ "${buildDir}/libretroshare-build/android-assets/" ] + jniLibs.srcDirs = [ "${buildDir}/native_libs-16" ] + } + + minApi16 + { + jniLibs.srcDirs = [ "${buildDir}/native_libs-16" ] + } + + minApi21 + { + jniLibs.srcDirs = [ "${buildDir}/native_libs-21" ] + } + + minApi24 + { + jniLibs.srcDirs = [ "${buildDir}/native_libs-24" ] + } + } + + lintOptions + { + disable 'LongLogTag' + } + + flavorDimensions 'api' + + def currNdk = android.getNdkDirectory().getAbsolutePath() + + productFlavors + { + minApi16 + { + minSdkVersion '16' + targetSdkVersion '16' + + def currApi = minSdkVersion.mApiLevel + versionNameSuffix "-API_${currApi}" + + buildLibretroshareNativeLib(currApi, "armeabi-v7a", currNdk) + } + + minApi21 + { + minSdkVersion '21' + targetSdkVersion '21' + + def currApi = minSdkVersion.mApiLevel + versionNameSuffix "-API_${currApi}" + + buildLibretroshareNativeLib(currApi, "arm64-v8a", currNdk) + buildLibretroshareNativeLib(currApi, "armeabi-v7a", currNdk) + } + + minApi24 + { + minSdkVersion '24' + targetSdkVersion '28' + + def currApi = minSdkVersion.mApiLevel + versionNameSuffix "-API_${currApi}" + + buildLibretroshareNativeLib(currApi, "arm64-v8a", currNdk) + buildLibretroshareNativeLib(currApi, "armeabi-v7a", currNdk) + } + } + + publishing + { + multipleVariants + { + allVariants() + } + } +} + +afterEvaluate +{ + publishing + { + // see https://developer.android.com/reference/tools/gradle-api/7.1/com/android/build/api/dsl/LibraryPublishing + publications + { + android.libraryVariants.each + { + variant -> + + publishing.publications.create(variant.name, MavenPublication) + { + from components.findByName(variant.name) + groupId = 'org.retroshare.service' + // -${variant.flavorName} + artifactId "${rootProject.name}-${variant.name}" + version "0.6.6" + + artifacts = [ "${buildDir}/outputs/aar/${rootProject.name}-${variant.flavorName}-${variant.buildType.name}.aar" ] + } + } + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..7454180f2 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffed3a254 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..744e882ed --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/misc/Android/Dockerfile b/misc/Android/Dockerfile new file mode 100644 index 000000000..490a247c9 --- /dev/null +++ b/misc/Android/Dockerfile @@ -0,0 +1,117 @@ +## To prepare an image suitable as base for Gitlab CI use +## image name must match gitlab repository name, you can play just with the tag +## the part after : +# export CI_IMAGE_NAME="registry.gitlab.com/retroshare/retroshare:android_arm_base" +# docker build --squash --tag "${CI_IMAGE_NAME}" \ +# --build-arg QT_INSTALLER_JWT_TOKEN="your qt JWT token goes here" . +# +# To build Android ARMv8 (64 bit) package pass also +# export CI_IMAGE_NAME="registry.gitlab.com/retroshare/retroshare:android_arm64_base" +# --build-arg ANDROID_NDK_ARCH=arm64 --build-arg ANDROID_PLATFORM_VER=21 + +## --squash is very important in case of GitlabCI shared runners as they are +## limited to 25GB disk size + +## To push it to gitlab CI registry you need first to login and the to push +# docker login registry.gitlab.com +# docker push ${CI_IMAGE_NAME} + +## To extract the generated APK easily you can run after the build complete +# docker cp \ +# $(docker create --rm ${CI_IMAGE_NAME}):/retroshare-service-android-build/android-build/build/outputs/apk/debug/android-build-debug.apk \ +# /tmp/RetroShare_Android_Service.apk + + +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive +ENV APT_UNAT="--assume-yes --quiet" + +RUN apt-get update $APT_UNAT && apt-get upgrade --show-upgraded $APT_UNAT && \ + apt-get clean $APT_UNAT +RUN apt-get install --no-install-recommends $APT_UNAT \ + bash build-essential bzip2 cmake curl chrpath doxygen \ + git p7zip python qt5-default qttools5-dev tclsh unzip wget zip + +# Dependencies to create Android pkg +RUN apt-get install --no-install-recommends $APT_UNAT \ + openjdk-8-jre openjdk-8-jdk openjdk-8-jdk-headless gradle + +ARG FRESHCLONE=0 +ARG REPO_URL=https://gitlab.com/RetroShare/RetroShare.git +ARG REPO_BRANCH=master +ARG REPO_DEPTH="--depth 2000" + +RUN git clone $REPO_DEPTH $REPO_URL -b $REPO_BRANCH && cd RetroShare && \ + git fetch --tags + +ENV PREPARE_TOOLCHAIN="/RetroShare/build_scripts/Android/prepare-toolchain-clang.sh" +ENV NATIVE_LIBS_TOOLCHAIN_PATH="/android-toolchain/" + +ARG ANDROID_PLATFORM_VER=16 +ARG ANDROID_NDK_ARCH=arm + +ENV ANDROID_SDK_PATH="/opt/android-sdk" +ENV ANDROID_HOME="$ANDROID_SDK_PATH" +ENV ANDROID_SDK_ROOT="$ANDROID_SDK_PATH" + +ENV ANDROID_NDK_PATH="/opt/android-ndk" +ENV ANDROID_NDK_ROOT="$ANDROID_NDK_PATH" + +ENV PATH="$PATH:$ANDROID_HOME/tools" +ENV PATH="$PATH:$ANDROID_HOME/platform-tools" +ENV JAVA_HOME="/usr/lib/jvm/java-8-openjdk-amd64/" + +RUN mkdir /bCache +WORKDIR /bCache + +## Quick HACK to ease development +#COPY prepare-toolchain-clang.sh $PREPARE_TOOLCHAIN + +RUN $PREPARE_TOOLCHAIN install_android_sdk +RUN $PREPARE_TOOLCHAIN install_android_ndk +RUN $PREPARE_TOOLCHAIN + +ARG QT_INSTALLER_JWT_TOKEN +RUN $PREPARE_TOOLCHAIN install_qt_android +# Avoid Qt account details leak into the image +RUN rm -f /root/.local/share/Qt/qtaccount.ini +# Shrink image by removing unneeded Qt components +RUN rm -r \ + $NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Docs/ \ + $NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Examples/ \ + $NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Tools/ + +RUN mkdir /jsonapi-generator-build +WORKDIR /jsonapi-generator-build/ +RUN qmake ../RetroShare/jsonapi-generator/src/ \ + CONFIG+=no_retroshare_plugins \ + CONFIG+=no_retroshare_service CONFIG+=no_retroshare_gui \ + CONFIG+=rs_jsonapi CONFIG+=no_rs_sam3_libsam3 && \ + make -j$(nproc) + +RUN mkdir /retroshare-service-android-build +WORKDIR /retroshare-service-android-build +ARG RS_SERVICE_QMAKE_EXTRA_OPTS +RUN $($PREPARE_TOOLCHAIN get_qt_dir | head -n 1)/bin/qmake ../RetroShare \ + -spec android-clang \ + CONFIG+=retroshare_service CONFIG+=rs_jsonapi \ + RS_UPNP_LIB=miniupnpc \ + JSONAPI_GENERATOR_EXE=/jsonapi-generator-build/jsonapi-generator \ + NATIVE_LIBS_TOOLCHAIN_PATH=$NATIVE_LIBS_TOOLCHAIN_PATH \ + CONFIG+=no_retroshare_gui CONFIG+=no_rs_service_webui_terminal_password \ + CONFIG+=no_rs_service_terminal_login \ + CONFIG+=no_rs_sam3 CONFIG+=no_rs_sam3_libsam3 \ + $RS_SERVICE_QMAKE_EXTRA_OPTS +RUN make -j$(nproc) +RUN make install INSTALL_ROOT=/retroshare-service-android-build/android-build/ +RUN $($PREPARE_TOOLCHAIN get_qt_dir | head -n 1)/bin/androiddeployqt \ + --input retroshare-service/src/android-libretroshare-service.so-deployment-settings.json \ + --output android-build --android-platform android-$ANDROID_PLATFORM_VER \ + --jdk $JAVA_HOME --gradle + + +RUN rm -rf /bCache + +# Clean apt cache +RUN apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/misc/Android/README.asciidoc b/misc/Android/README.asciidoc new file mode 100644 index 000000000..c47974161 --- /dev/null +++ b/misc/Android/README.asciidoc @@ -0,0 +1,400 @@ += RetroShare development on Android + +// SPDX-FileCopyrightText: RetroShare Team +// SPDX-License-Identifier: CC-BY-SA-4.0 + + +Compiling an application for Android is not as easy as one would imagine, +expecially one like RetroShare that has a big codebase and is not well +documented. This document is aimed to empower the reader so she can hopefully +succed or at least have a significant help in compiling her own RetroShare APK +installable on Android. + + +== Preparing The Environement + +First of all setup your Qt for Android development environement following the +guide on the link:http://doc.qt.io/qt-5/androidgs.html[Qt for android web site]. +At this point you should have Android SDK, Android NDK, and Qt for Android +working fine, and you should be capable of executing on an Android emulator or +on your Android phone Qt for Android examples. + +But RetroShare is not as simple to compile as those examples. The good news is +that Android NDK ships all the necessary to build a custom toolchain that is +suitable to build RetroShare. +In order to build the toolchain with needed libraries RetroShare provides the ++android-prepare-toolchain.sh+ script; before you execute it you should define +some variables the script cannot determine in an easy and reliable manner by +itself in your terminal. + +[source,bash] +------------------------------------------------------------------------------- +## The path where Android NDK is installed in your system +export ANDROID_NDK_PATH="/opt/android-ndk/" + +## The path where your fresh compiled toolchain will be installed, make sure +## the parent exists +export NATIVE_LIBS_TOOLCHAIN_PATH="${HOME}/Builds/android-toolchains/retroshare-android/" + +## The CPU architecture of the Android device you want to target +export ANDROID_NDK_ARCH="arm" + +## The Android API level the Android device you want to target +export ANDROID_PLATFORM_VER="16" + +## The number of core that yout host CPU have (just to speed up compilation) set +## it to 1 if unsure +export HOST_NUM_CPU=1 + +./android-prepare-toolchain.sh +------------------------------------------------------------------------------- + + +== Preparing Qt Creator + +Now that your environement is set up you should configure Qt Creator for Android +following the +link:http://doc.qt.io/qtcreator/creator-developing-android.html[official guide]. +At the end of this step your Qt Creator should recognize the Android compiler +and the Qt for Android kit. + +Your Kit is now ready to use. Now you can open RetroShare as a Qt Creator +project and in the Projects left menu add the newly created kit if not already +present, so you can select it on the build type selection button down on the +left. + +Now you need to set properly a few options like `JSONAPI_GENERATOR_EXE` and +disable some of RetroShare modules like `retroshare-gui` that are not available +on Android so you will have to go to + +_Qt Creator left pane -> Projects -> Build and Run -> Android SOMESTUFF kit -> +Build Steps -> qmake -> Additional arguments_ + + +and add the following configurations (change `Your_Path` according to your +deployment) + +[source,makefile] +------------------------------------------------------------------------------- +CONFIG+=retroshare_service CONFIG+=rs_jsonapi CONFIG+=no_keywords +RS_UPNP_LIB=miniupnpc +JSONAPI_GENERATOR_EXE=Your_Path/jsonapi-generator/src/jsonapi-generator +NATIVE_LIBS_TOOLCHAIN_PATH=Your_Path/retroshare-android-16-arm/ +CONFIG+=no_retroshare_gui CONFIG+=no_rs_service_webui_terminal_password +CONFIG+=no_rs_service_terminal_login +CONFIG+=no_rs_sam3 CONFIG+=no_rs_sam3_libsam3 +------------------------------------------------------------------------------- + +TIP: Some versions of QtCreator try to find the Android SDK in +`/opt/android/sdk`. A workaround to this is to make a symbolic link there +pointing to your SDK installation path, like ++mkdir -p /opt/android/sdk && ln -s /home/user/android-sdk-linux +/opt/android/sdk+ + + +== Quircks + +=== Protected Apps + +On some Android devices like +Huawei ALE-L21+ background applications are +killed when screen is turned off unless they are in the _protected app_ list. +At moment seems apps developers don't have a way to have the application +_protected_ by default, unless the phone vendor decide the app is _popular_ so +the user have to enable _protection_ for RetroShare manually on those mobile +phones. + + +{empty} + +To enable enable _protection_: +Android menu -> Settings -> Privacy & security +-> Protected apps -> RetroShare+ + +{empty} + + +Other devices may offer similar _features_ please report them. + + +=== APK signature mismatch + +If you try to install a RetroShare APK that comes from a different source +(eg: if you try to upgrade from F-Droid when you originally installed an APK +build by yourself) Android will prevent that from happening. In that case the +only solution is to uninstall the app and then install the new APK but if you do +it also the application data and your precious cryptographic keys, friend list +etc. will be lost forever. +To avoid that you can attempt to manually backup and then restore from the +command-line (`adb backup` seems not working either) to change the app source +without erasing the appliation data. + +CAUTION: Following steps require root access on your Android device + +.Backup RetroShare Android application data +[source,bash] +-------------------------------------------------------------------------------- +export ORIG_DIR="/data/data/org.retroshare.android.qml_app" +export BACKUP_DIR="org.retroshare.android.qml_app.backup" + +adb root + +adb shell am force-stop org.retroshare.android.qml_app +sleep 1s + +mkdir ${BACKUP_DIR} + +# Avoid adb pull failing +adb shell rm ${ORIG_DIR}/files/.retroshare/libresapi.sock +adb pull ${ORIG_DIR}/files/ ${BACKUP_DIR}/files/ +-------------------------------------------------------------------------------- + +After this you should be able to uninstall the old APK with your preferred +method, as example from the command-line. + +.Uninstall RetroShare Android from the command-line +[source,bash] +-------------------------------------------------------------------------------- +adb uninstall org.retroshare.android.qml_app +-------------------------------------------------------------------------------- + +Now you can install a different signature APK and then restore the application +data with the following commands. + +[source,bash] +-------------------------------------------------------------------------------- +export ORIG_DIR="/data/data/org.retroshare.android.qml_app" +export BACKUP_DIR="org.retroshare.android.qml_app.backup" + +adb root + +## Launch the app to make sure the parent directory exists and has proper owner +adb shell monkey -p org.retroshare.android.qml_app -c android.intent.category.LAUNCHER 1 +sleep 1s + +adb shell am force-stop org.retroshare.android.qml_app +sleep 1s + + +APP_OWNER="$(adb shell busybox ls -lnd ${ORIG_DIR} | awk '{print $3":"$4}')" +adb shell rm -rf ${ORIG_DIR}/files +adb push ${BACKUP_DIR}/files/ ${ORIG_DIR}/files/ +adb shell busybox chown -R ${APP_OWNER} ${ORIG_DIR}/files/ +-------------------------------------------------------------------------------- + +Opening RetroShare android app now should show your old profile. + + +== Debugging with GDB + +If building RetroShare Android package seems tricky, setting up a functional +debugging environement for it feels like black magic. This section is meant to +help you doing it with less headache and hopefully in a reproducible way. + +Unfortunately at the time of the last update to this guide, Qt build system +strips debugging symbols from the package and from the buildroot also if you +compile with debugging enabled. Fiddling with `qmake` configurations and +variables like `CONFIG+=debug`, `CONFIG+=force_debug_info` or `QMAKE_STRIP` +either as commandline arguments or inside retroshare `.pro` and `.pri` files is +uneffective. IMHO Qt should handle this on itself so it is probably worth +reporting a bug to them. So to workaround this problem you need to fiddle a bit +with the Android NDK. In my case I always keep +Debug+ or +Release+ suffix in +my build directory name depending on what kind of build it is, so I use this +information and modify `llvm-strip` in a way that it will strip only if stripped +file path doesn't contain +Debug+. + +.Modify llvm-strip inside Android NDK +-------------------------------------------------------------------------------- +## Set ANDROID_NDK_PATH to your Android NDK installation path +export ANDROID_NDK_PATH="/opt/android-ndk/" + +## Define a convenience variable with llvm-strip path +export ANDROID_NDK_LLVM_STRIP="${ANDROID_NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip" + +## If not existing yer create a backup of the original llvm-strip +[ -f "${ANDROID_NDK_LLVM_STRIP}.back" ] || + cp "${ANDROID_NDK_LLVM_STRIP}" "${ANDROID_NDK_LLVM_STRIP}.back" + +## Create a new llvm-strip that does nothing if the argument path contains Debug +cat > "${ANDROID_NDK_LLVM_STRIP}" << LLVMSTRIPTRICK +#!/bin/bash + +echo "\${2}" | grep -q Debug || + "${ANDROID_NDK_LLVM_STRIP}.back" --strip-all "\${2}" + +LLVMSTRIPTRICK + +## Eventually you can revert back simply by running +# `mv "${ANDROID_NDK_LLVM_STRIP}.back" "${ANDROID_NDK_LLVM_STRIP}"` +-------------------------------------------------------------------------------- + + +To attach to the `retroshare-service` running on Android you need also to pull a +debugging sysroot out of your device first, RetroShare sources provides an +helper script to do that. + +.Prepare debugging sysroot with helper script +[source,bash] +-------------------------------------------------------------------------------- +## Set RetroShare source path +export RS_SOURCE_DIR="${HOME}/Development/rs-develop" + +## Optionally set your device ID first available will be used, you can run +## `adb devices` to list available devices. +#export ANDROID_SERIAL="YT013PSPGK" + +## Optionally set a path where to save the debugging sysroot otherwise default +## is used. +#export DEBUG_SYSROOT="${HOME}/Builds/debug_sysroot/${ANDROID_SERIAL}/" + +## Run the helper script +${RS_SOURCE_DIR}/build_scripts/Android/pull_sysroot.sh +-------------------------------------------------------------------------------- + +.Prepare Android NDK GDB configurations +[source,bash] +-------------------------------------------------------------------------------- +## Optionally set Qt version variable consistently with your installation +export QT_VERSION="5.12.7" + +## Optionally set Qt architecture variable consistently with Android device +export QT_ARCH="arm64_v8a" + +## Optionally set Qt path variable consistently with your installation +export QT_DIR="/opt/Qt-${QT_VERSION}/${QT_VERSION}/" + +## Optionally set RetroShare buildroot path +export RS_BUILD_DIR="${HOME}/Builds/RetroShare-Android_for_${QT_ARCH}_Clang_Qt_${QT_VERSION//./_}_android_${QT_ARCH}-Debug/" + +## Optionally set gdb config file path +export GDB_CONFIGS_FILE="${HOME}/Builds/gdb_configs_${QT_ARCH}" + +## Generate Android NDK GDB configuration +${RS_SOURCE_DIR}/build_scripts/Android/generate_gdb_init_commands.sh +-------------------------------------------------------------------------------- + + +You will need to run the following steps everytime you want to debug +`retroshare-service` on Android. + +Make sure `retroshare-service` is running on your connected Android device. + +.Run GDB server on your Android device from your host console +[source,bash] +-------------------------------------------------------------------------------- +${RS_SOURCE_DIR}/build_scripts/Android/start_gdbserver.sh +-------------------------------------------------------------------------------- + + +.Run Android NDK GDB on your workstation and attach +[source,bash] +-------------------------------------------------------------------------------- +## Start NDK gdb +${ANDROID_NDK_PATH}/prebuilt/linux-x86_64/bin/gdb + +## Instruct GDB how and where to find debugging symbols +(gdb) source $GDB_CONFIGS_FILE + +## Connect to the gdbserver running on the phone +(gdb) target remote 127.0.01:5039 + +## Have fun debugging +(gdb) +-------------------------------------------------------------------------------- + + +== Debugging with Qt Creator + +WARNING: As of the last update to this guide, debugging retroshare-service +running on Android via Qt creator doesn't wrok even with all the trickery +explained in this section, you better learn how to debug with GDB reading +carefully previous section. + +Qt Creator actually support debugging only for the foreground activity, so to +debug what's happening in the core extra trickery is needed. + +- Run the App in Debug mode from QtCreator "Start Debugging" button +- Enable QtCreator debugger console view Menu->Window->Debugger Log +- Run +show solib-search-path+ in the QtCreator GDB console +- Take note of the output you get in the right pane of the console +- Thanks https://stackoverflow.com/a/31164313 for the idea + +TIP: QtCreator GDB console seems a bit buggy and easly trigger timeout +message when a command is run, in that case attempt to run the command while the +debugging is paused or at breakpoint, or with other similar tricks. + +CAUTION: Following steps require root access on your Android device + +Now on your phone yuo need to authorize root access to applications, then once +you plug your sacrifical Android phone run this commands + +.Run gdbserver as root on Android phone +[source,bash] +-------------------------------------------------------------------------------- +## Open a shell from your workstation on the connected Android phone +adb shell + +## take the note of the phone IP address +ip address show + +## Gain root permissions on the shell +su + +## Attach with gdbserver and listen on one TCP port +gdbserver :4567 --attach $(pgrep org.retroshare.android.qml_app:rs) +-------------------------------------------------------------------------------- + + +.Prepare and run Android NDK GDB on your workstation +[source,bash] +-------------------------------------------------------------------------------- +## Setup some convenience variables +NDK_GDB="${ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gdb" +RS_BUILD_PATH="${HOME}/Builds/RetroShare-Android_for_armeabi_v7a_GCC_4_9_Qt_5_9_2_android_armv7-Debug/" + +## Start Android NDK GDB of your phone architecture passing the executable +$NDK_GDB $RS_BUILD_PATH/retroshare-android-service/src/libretroshare-android-service.so + +## Instruct GDB how and where to find debugging symbols +(gdb) set auto-solib-add on +(gdb) set solib-search-path THE:BIG:LIST:OF:DIRECTORIES:YOU:TAKE:NOTE:BEFORE + +## Connect to the gdbserver running on the phone +(gdb) target remote $PHONE_IP:4567 + +## Have fun debugging +(gdb) +-------------------------------------------------------------------------------- + +TIP: Some time WiFi power saving on Android mess with the GDB connection, +to prevent that from appening open another +adb shell+ and live +ping+ toward +your work-station running + +== Embedding into other Android packages + +As showed by https://elrepo.io/[elRepo.io] developers it is possible and quite +easy to embed `retroshare-service` into other Android packages see description + +https://gitlab.com/elRepo.io/elRepo.io-android/-/blob/master/README.adoc + +And implementation details + +https://gitlab.com/elRepo.io/elRepo.io-android/-/blob/master/android/app/build.gradle + + +== Furter Readings + +- link:http://doc.qt.io/qt-5/android-support.html[] +- link:https://developer.android.com/ndk/guides/libs.html[] +- link:retroshare://forum?name=Compiling%20nogui%20for%20android&id=8fd22bd8f99754461e7ba1ca8a727995&msgid=4e0f92330600bba9cf978f384f4b7b2f2ca64eff[] +- link:retroshare://file?name=Android%20Native%20Development%20Kit%20Cookbook.pdf&size=29214468&hash=0123361c1b14366ce36118e82b90faf7c7b1b136[] +- link:https://groups.google.com/forum/#!topic/android-developers/srATPaL0aRU[] +- link:https://stackoverflow.com/questions/31638986/protected-apps-setting-on-huawei-phones-and-how-to-handle-it[] +- link:https://tthtlc.wordpress.com/2012/09/19/how-to-do-remote-debugging-via-gdbserver-running-inside-the-android-phone/[] +- link:https://source.android.com/devices/tech/debug/[] +- link:https://source.android.com/devices/tech/debug/gdb[] +- link:https://fw4spl-org.github.io/fw4spl-blog/2015/07/27/Native-debugging-on-Android-with-QtCreator.html[] +- link:https://fragglet.livejournal.com/19646.html[] +- link:https://github.com/android-ndk/ndk/issues/773[How to build without using standalone toolchain?] + +== License + +Copyright (C) 2016-2021 Gioacchino Mazzurco + +Copyright (C) 2020-2021 Asociación Civil Altermundi + + +This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. + +image::https://i.creativecommons.org/l/by-sa/4.0/88x31.png[Creative Commons License, link=http://creativecommons.org/licenses/by-sa/4.0/] diff --git a/misc/Android/generate_gdb_init_commands.sh b/misc/Android/generate_gdb_init_commands.sh new file mode 100755 index 000000000..3a9883950 --- /dev/null +++ b/misc/Android/generate_gdb_init_commands.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# Script to prepare Android NDK GDB configurations to debug retroshare-service +# +# Copyright (C) 2020 Gioacchino Mazzurco +# Copyright (C) 2020 Asociación Civil Altermundi +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see + + +## Define default value for variable, take two arguments, $1 variable name, +## $2 default variable value, if the variable is not already define define it +## with default value. +function define_default_value() +{ + VAR_NAME="${1}" + DEFAULT_VALUE="${2}" + + [ -z "${!VAR_NAME}" ] && export ${VAR_NAME}="${DEFAULT_VALUE}" +} + +define_default_value QT_VERSION "5.12.4" +define_default_value QT_ARCH "arm64_v8a" +define_default_value QT_DIR "/opt/Qt-${QT_VERSION}/${QT_VERSION}/" +define_default_value ANDROID_SERIAL "$(adb devices | head -n 2 | tail -n 1 | awk '{print $1}')" +define_default_value RS_BUILD_DIR "${HOME}/Builds/RetroShare-Android_for_${QT_ARCH}_Clang_Qt_${QT_VERSION//./_}_android_${QT_ARCH}-Debug/" +define_default_value RS_SOURCE_DIR "${HOME}/Development/rs-develop/" +define_default_value DEBUG_SYSROOT "${HOME}/Builds/debug_sysroot/${ANDROID_SERIAL}/" +define_default_value GDB_CONFIGS_FILE "${HOME}/Builds/gdb_configs_${QT_ARCH}" + +scanDir() +{ + find "$1" -type d -not -path '*/\.git/*' | tr '\n' ':' >> $GDB_CONFIGS_FILE +} + +putSeparator() +{ + echo >> $GDB_CONFIGS_FILE + echo >> $GDB_CONFIGS_FILE +} + +echo "set sysroot ${DEBUG_SYSROOT}" > $GDB_CONFIGS_FILE +putSeparator + +echo "set auto-solib-add on" >> $GDB_CONFIGS_FILE +echo -n "set solib-search-path " >> $GDB_CONFIGS_FILE +scanDir "${RS_BUILD_DIR}" +scanDir "${DEBUG_SYSROOT}" +scanDir "${QT_DIR}/android_${QT_ARCH}/lib/" +scanDir "${QT_DIR}/android_${QT_ARCH}/plugins/" +scanDir "${QT_DIR}/android_${QT_ARCH}/qml/" +putSeparator + +echo -n "directory " >> $GDB_CONFIGS_FILE +scanDir ${RS_SOURCE_DIR}/jsonapi-generator/src +scanDir ${RS_SOURCE_DIR}/libbitdht/src +scanDir ${RS_SOURCE_DIR}/openpgpsdk/src +scanDir ${RS_SOURCE_DIR}/libretroshare/src +scanDir ${RS_SOURCE_DIR}/retroshare-service/src +scanDir ${RS_SOURCE_DIR}/supportlibs/rapidjson/include/ +scanDir ${RS_SOURCE_DIR}/supportlibs/restbed/source/ +scanDir ${RS_SOURCE_DIR}/supportlibs/udp-discovery-cpp/ +scanDir ${RS_SOURCE_DIR}/supportlibs/restbed/dependency/asio/asio/include/ +scanDir ${RS_SOURCE_DIR}/supportlibs/restbed/dependency/catch/include/ +putSeparator + +## see https://stackoverflow.com/questions/28972367/gdb-backtrace-without-stopping +echo "catch signal SIGSEGV" >> $GDB_CONFIGS_FILE +echo "commands + bt + continue + end" >> $GDB_CONFIGS_FILE +putSeparator + +echo GDB_CONFIGS_FILE=$GDB_CONFIGS_FILE diff --git a/misc/Android/prepare-toolchain-clang.sh b/misc/Android/prepare-toolchain-clang.sh new file mode 100755 index 000000000..4519d591d --- /dev/null +++ b/misc/Android/prepare-toolchain-clang.sh @@ -0,0 +1,920 @@ +#!/bin/bash + +# Script to prepare RetroShare Android package building toolchain +# +# Copyright (C) 2016-2021 Gioacchino Mazzurco +# Copyright (C) 2020-2021 Asociación Civil Altermundi +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see +# +# SPDX-FileCopyrightText: Retroshare Team +# SPDX-License-Identifier: AGPL-3.0-only + + +## Define default value for variable, take two arguments, $1 variable name, +## $2 default variable value, if the variable is not already define define it +## with default value. +function define_default_value() +{ + VAR_NAME="${1}" + DEFAULT_VALUE="${2}" + + [ -z "${!VAR_NAME}" ] && export ${VAR_NAME}="${DEFAULT_VALUE}" || true +} + +## You are supposed to provide the following variables according to your system setup +define_default_value ANDROID_NDK_PATH "/opt/android-ndk/" +define_default_value ANDROID_NDK_ARCH "arm" +define_default_value ANDROID_PLATFORM_VER "16" +define_default_value NATIVE_LIBS_TOOLCHAIN_PATH "${HOME}/Builds/android-toolchains/retroshare-android-${ANDROID_PLATFORM_VER}-${ANDROID_NDK_ARCH}/" +define_default_value HOST_NUM_CPU $(nproc) + +define_default_value ANDROID_SDK_INSTALL "false" +define_default_value ANDROID_SDK_TOOLS_VERSION "3859397" +define_default_value ANDROID_SDK_TOOLS_SHA256 444e22ce8ca0f67353bda4b85175ed3731cae3ffa695ca18119cbacef1c1bea0 +define_default_value ANDROID_SDK_VERSION "29.0.3" + +define_default_value ANDROID_NDK_INSTALL "false" +define_default_value ANDROID_NDK_VERSION "r21" +define_default_value ANDROID_NDK_SHA256 b65ea2d5c5b68fb603626adcbcea6e4d12c68eb8a73e373bbb9d23c252fc647b + +define_default_value BZIP2_SOURCE_VERSION "1.0.6" +define_default_value BZIP2_SOURCE_SHA256 a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd + +define_default_value OPENSSL_SOURCE_VERSION "1.1.1c" +define_default_value OPENSSL_SOURCE_SHA256 f6fb3079ad15076154eda9413fed42877d668e7069d9b87396d0804fdb3f4c90 + +define_default_value SQLITE_SOURCE_YEAR "2018" +define_default_value SQLITE_SOURCE_VERSION "3250200" +define_default_value SQLITE_SOURCE_SHA256 da9a1484423d524d3ac793af518cdf870c8255d209e369bd6a193e9f9d0e3181 + +define_default_value SQLCIPHER_SOURCE_VERSION "4.4.3" +define_default_value SQLCIPHER_SOURCE_SHA256 b8df69b998c042ce7f8a99f07cf11f45dfebe51110ef92de95f1728358853133 + +define_default_value LIBUPNP_SOURCE_VERSION "1.8.4" +define_default_value LIBUPNP_SOURCE_SHA256 976c3e4555604cdd8391ed2f359c08c9dead3b6bf131c24ce78e64d6669af2ed + +define_default_value QT_ANDROID_VIA_INSTALLER "false" +define_default_value QT_VERSION "5.12.11" +define_default_value QT_INSTALLER_VERSION "4.1.1" +define_default_value QT_INSTALLER_SHA256 1266ffd0d1b0e466244e3bc8422975c1aa9d96745b6bb28d422f7f92df11f34c +define_default_value QT_INSTALLER_JWT_TOKEN "" +define_default_value QT_INSTALL_PATH "${NATIVE_LIBS_TOOLCHAIN_PATH}/Qt/" + +define_default_value QT_ANDROID_INSTALLER_SHA256 a214084e2295c9a9f8727e8a0131c37255bf724bfc69e80f7012ba3abeb1f763 + +define_default_value RESTBED_SOURCE_REPO "https://github.com/Corvusoft/restbed.git" +define_default_value RESTBED_SOURCE_VERSION f74f9329dac82e662c1d570b7cd72c192b729eb4 + +define_default_value UDP_DISCOVERY_CPP_SOURCE "https://github.com/truvorskameikin/udp-discovery-cpp.git" +define_default_value UDP_DISCOVERY_CPP_VERSION "develop" + +define_default_value XAPIAN_SOURCE_VERSION "1.4.7" +define_default_value XAPIAN_SOURCE_SHA256 13f08a0b649c7afa804fa0e85678d693fd6069dd394c9b9e7d41973d74a3b5d3 + +define_default_value RAPIDJSON_SOURCE_VERSION "1.1.0" +define_default_value RAPIDJSON_SOURCE_SHA256 bf7ced29704a1e696fbccf2a2b4ea068e7774fa37f6d7dd4039d0787f8bed98e + +define_default_value MINIUPNPC_SOURCE_VERSION "2.1.20190625" +define_default_value MINIUPNPC_SOURCE_SHA256 8723f5d7fd7970de23635547700878cd29a5c2bb708b5e5475b2d1d2510317fb + +# zlib and libpng versions walks toghether +define_default_value ZLIB_SOURCE_VERSION "1.2.11" +define_default_value ZLIB_SOURCE_SHA256 4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066 + +define_default_value LIBPNG_SOURCE_VERSION "1.6.37" +define_default_value LIBPNG_SOURCE_SHA256 505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca + +define_default_value LIBJPEG_SOURCE_VERSION "9d" +define_default_value LIBJPEG_SOURCE_SHA256 6c434a3be59f8f62425b2e3c077e785c9ce30ee5874ea1c270e843f273ba71ee + +define_default_value TIFF_SOURCE_VERSION "4.2.0" +define_default_value TIFF_SOURCE_SHA256 eb0484e568ead8fa23b513e9b0041df7e327f4ee2d22db5a533929dfc19633cb + +define_default_value CIMG_SOURCE_VERSION "2.9.7" +define_default_value CIMG_SOURCE_SHA256 595dda9718431a123b418fa0db88e248c44590d47d9b1646970fa0503e27fa5c + +define_default_value PHASH_SOURCE_REPO "https://gitlab.com/g10h4ck/pHash.git" +define_default_value PHASH_SOURCE_VERSION origin/android-ndk + +define_default_value MVPTREE_SOURCE_REPO "https://github.com/starkdg/mvptree.git" +define_default_value MVPTREE_SOURCE_VERSION origin/master + +define_default_value REPORT_DIR "$(pwd)/$(basename ${NATIVE_LIBS_TOOLCHAIN_PATH})_build_report/" + +define_default_value RS_SRC_DIR "$(realpath $(dirname $BASH_SOURCE)/../../)" + + +cArch="" +eABI="" +cmakeABI="" + +case "${ANDROID_NDK_ARCH}" in +"arm") + cArch="${ANDROID_NDK_ARCH}" + eABI="eabi" + ;; +"arm64") + cArch="aarch64" + eABI="" + ;; +"x86") + cArch="i686" + eABI="" + ;; +"x86_64") + echo "ANDROID_NDK_ARCH=${ANDROID_NDK_ARCH} not supported yet" + exit -1 + cArch="??" + eABI="" +esac + +export SYSROOT="${NATIVE_LIBS_TOOLCHAIN_PATH}/sysroot/" +export PREFIX="${SYSROOT}/usr/" +export CC="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-clang" +export CXX="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-clang++" +export AR="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-ar" +export RANLIB="${NATIVE_LIBS_TOOLCHAIN_PATH}/bin/${cArch}-linux-android${eABI}-ranlib" + +# Used to instruct cmake to explicitely ignore host libraries +export HOST_IGNORE_PREFIX="/usr/" + + +## $1 filename, $2 sha256 hash +function check_sha256() +{ + echo ${2} "${1}" | sha256sum -c &> /dev/null +} + +## $1 filename, $2 sha256 hash, $3 url +function verified_download() +{ + FILENAME="$1" + SHA256="$2" + URL="$3" + + check_sha256 "${FILENAME}" "${SHA256}" || + { + rm -rf "${FILENAME}" + + wget -O "${FILENAME}" "$URL" || + { + echo "Failed downloading ${FILENAME} from $URL" + exit 1 + } + + check_sha256 "${FILENAME}" "${SHA256}" || + { + echo "SHA256 mismatch for ${FILENAME} from ${URL} expected sha256 ${SHA256} got $(sha256sum ${FILENAME} | awk '{print $1}')" + exit 1 + } + } +} + +# This function is the result of reading and testing many many stuff be very +# careful editing it +function andro_cmake() +{ +# Using android.toolchain.cmake as documented here +# https://developer.android.com/ndk/guides/cmake seens to break more things then +# it fixes :-\ + + cmakeProc="" + case "${ANDROID_NDK_ARCH}" in + "arm") + cmakeProc="armv7-a" + ;; + "arm64") + cmakeProc="aarch64" + ;; + "x86") + cmakeProc="i686" + ;; + "x86_64") + cmakeProc="x86_64" + ;; + *) + echo "Unhandled NDK architecture ${ANDROID_NDK_ARCH}" + exit -1 + ;; + esac + + _hi="$HOST_IGNORE_PREFIX" + + cmake \ + -DCMAKE_SYSTEM_PROCESSOR=$cmakeProc \ + -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ + -DCMAKE_PREFIX_PATH="${PREFIX}" \ + -DCMAKE_SYSTEM_PREFIX_PATH="${PREFIX}" \ + -DCMAKE_INCLUDE_PATH="${PREFIX}/include" \ + -DCMAKE_SYSTEM_INCLUDE_PATH="${PREFIX}/include" \ + -DCMAKE_LIBRARY_PATH="${PREFIX}/lib" \ + -DCMAKE_SYSTEM_LIBRARY_PATH="${PREFIX}/lib" \ + -DCMAKE_INSTALL_PREFIX="${PREFIX}" \ + -DCMAKE_IGNORE_PATH="$_hi/include;$_hi/lib;$_hi/lib64" \ + $@ + + # It is probably ok to do not touch CMAKE_PROGRAM_PATH and + # CMAKE_SYSTEM_PROGRAM_PATH +} + +function git_source_get() +{ + sourceDir="$1" ; shift #$1 + sourceRepo="$1" ; shift #$2 + sourceVersion="$1" ; shift #$3 + # extra paramethers are treated as submodules + + [ -d "$sourceDir" ] && + { + pushd "$sourceDir" + actUrl="$(git remote get-url origin)" + [ "$actUrl" != "$sourceRepo" ] && rm -rf "${sourceDir}" + popd + } || true + + [ -d $sourceDir ] || git clone "$sourceRepo" "$sourceDir" + pushd $sourceDir + + git fetch --all + git reset --hard ${sourceVersion} + + while [ "$1" != "" ] ; do + git submodule update --init "$1" + pushd "$1" + git reset --hard + shift + popd + done + + popd +} + +declare -A TASK_REGISTER + +function task_register() +{ + TASK_REGISTER[$1]=true +} + +function task_unregister() +{ + # we may simply wipe them but we could benefit from keeping track of + # unregistered tasks too + TASK_REGISTER[$1]=false +} + +function task_logfile() +{ + echo "$REPORT_DIR/$1.log" +} + +function task_run() +{ + mTask="$1" ; shift + + [ "${TASK_REGISTER[$mTask]}" != "true" ] && + { + echo "Attempt to run not registered task $mTask $@" + return -1 + } + + logFile="$(task_logfile $mTask)" + if [ -f "$logFile" ] ; then + echo "Task $mTask already run more details at $logFile" + else + date | tee > "$logFile" + $mTask $@ |& tee --append "$logFile" + mRetval="${PIPESTATUS[0]}" + echo "Task $mTask return ${mRetval} more details at $logFile" + date | tee --append "$logFile" + return ${mRetval} + fi +} + +function task_zap() +{ + rm -f "$(task_logfile $1)" +} + +DUPLICATED_INCLUDES_LIST_FILE="${REPORT_DIR}/duplicated_includes_list" +DUPLICATED_INCLUDES_DIR="${REPORT_DIR}/duplicated_includes/" + +task_register install_android_sdk +install_android_sdk() +{ + tFile="sdk-tools-linux-${ANDROID_SDK_TOOLS_VERSION}.zip" + + verified_download "${tFile}" "${ANDROID_SDK_TOOLS_SHA256}" \ + "https://dl.google.com/android/repository/${tFile}" + + unzip "${tFile}" + mkdir -p "$ANDROID_SDK_PATH" + rm -rf "$ANDROID_SDK_PATH/tools/" + mv --verbose tools/ "$ANDROID_SDK_PATH/tools/" + + # Install Android SDK + yes | $ANDROID_SDK_PATH/tools/bin/sdkmanager --licenses && \ + $ANDROID_SDK_PATH/tools/bin/sdkmanager --update + $ANDROID_SDK_PATH/tools/bin/sdkmanager "platforms;android-$ANDROID_PLATFORM_VER" + $ANDROID_SDK_PATH/tools/bin/sdkmanager "build-tools;$ANDROID_SDK_VERSION" +} + +task_register install_android_ndk +install_android_ndk() +{ + tFile="android-ndk-${ANDROID_NDK_VERSION}-linux-x86_64.zip" + + verified_download "${tFile}" "${ANDROID_NDK_SHA256}" \ + "https://dl.google.com/android/repository/${tFile}" + + unzip "${tFile}" + mkdir -p "$ANDROID_NDK_PATH" + rm -rf "$ANDROID_NDK_PATH" + mv --verbose "android-ndk-${ANDROID_NDK_VERSION}/" "$ANDROID_NDK_PATH/" +} + +## More information available at https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html +task_register bootstrap_toolchain +bootstrap_toolchain() +{ + rm -rf "${NATIVE_LIBS_TOOLCHAIN_PATH}" + ${ANDROID_NDK_PATH}/build/tools/make_standalone_toolchain.py --verbose \ + --arch ${ANDROID_NDK_ARCH} --install-dir ${NATIVE_LIBS_TOOLCHAIN_PATH} \ + --api ${ANDROID_PLATFORM_VER} + + # Avoid problems with arm64 some libraries installing on lib64 + ln -s "${PREFIX}/lib/" "${PREFIX}/lib64" + + pushd "${PREFIX}/include/" + find . -not -type d > "${DUPLICATED_INCLUDES_LIST_FILE}" + popd +} + +## This avoid include errors due to -isystem and -I ordering issue +task_register deduplicate_includes +deduplicate_includes() +{ + while read delFile ; do + mNewPath="${DUPLICATED_INCLUDES_DIR}/$delFile" + mkdir --verbose --parents "$(dirname "$mNewPath")" + mv --verbose "${PREFIX}/include/$delFile" "$mNewPath" + done < "${DUPLICATED_INCLUDES_LIST_FILE}" +} + +task_register reduplicate_includes +reduplicate_includes() +{ + pushd "${DUPLICATED_INCLUDES_DIR}" + find . -not -type d | while read delFile ; do + mv --verbose "${delFile}" "${PREFIX}/include/$delFile" + done + popd +} + +# $1 optional prefix prepended only if return value is not empty +# $2 optional suffix appended only if return value is not empty +task_register get_qt_arch +get_qt_arch() +{ + local QT_VERSION_COMP="$(echo $QT_VERSION | awk -F. '{print $1*1000000+$2*1000+$3}')" + local QT_ARCH="" + + # Qt >= 5.15.0 ships all Android architectures toghether + [ "$QT_VERSION_COMP" -lt "5015000" ] && + { + case "${ANDROID_NDK_ARCH}" in + "arm") + QT_ARCH="armv7" + ;; + "arm64") + QT_ARCH="arm64_v8a" + ;; + "x86") + QT_ARCH="x86" + ;; + esac + + echo "$1$QT_ARCH$2" + } +} + +task_register get_qt_dir +get_qt_dir() +{ + echo "${QT_INSTALL_PATH}/${QT_VERSION}/android$(get_qt_arch _)/" +} + +## More information available at https://wiki.qt.io/Online_Installer_4.x +task_register install_qt_android +install_qt_android() +{ + [ "$QT_INSTALLER_JWT_TOKEN" == "" ] && + { + echo "To run Qt installer QT_INSTALLER_JWT_TOKEN environement variable \ +need to be set to a valid JWT token see https://wiki.qt.io/Online_Installer_4.x" + return -1 + } + + QT_VERSION_CODE="$(echo $QT_VERSION | tr -d .)" + QT_INSTALLER="qt-unified-linux-x86_64-${QT_INSTALLER_VERSION}-online.run" + tMajDotMinVer="$(echo $QT_INSTALLER_VERSION | awk -F. '{print $1"."$2}')" + verified_download $QT_INSTALLER $QT_INSTALLER_SHA256 \ + "https://master.qt.io/archive/online_installers/${tMajDotMinVer}/${QT_INSTALLER}" + + chmod a+x ${QT_INSTALLER} + QT_QPA_PLATFORM=minimal ./${QT_INSTALLER} \ + install qt.qt5.${QT_VERSION_CODE}.android$(get_qt_arch _) \ + --accept-licenses --accept-obligations --confirm-command \ + --default-answer --no-default-installations \ + --root "${QT_INSTALL_PATH}" +} + +## More information available at retroshare://file?name=Android%20Native%20Development%20Kit%20Cookbook.pdf&size=29214468&hash=0123361c1b14366ce36118e82b90faf7c7b1b136 +task_register build_bzlib +build_bzlib() +{ + B_dir="bzip2-${BZIP2_SOURCE_VERSION}" + rm -rf $B_dir + + verified_download $B_dir.tar.gz $BZIP2_SOURCE_SHA256 \ + http://distfiles.gentoo.org/distfiles/bzip2-${BZIP2_SOURCE_VERSION}.tar.gz + + tar -xf $B_dir.tar.gz + cd $B_dir + sed -i "/^CC=.*/d" Makefile + sed -i "/^AR=.*/d" Makefile + sed -i "/^RANLIB=.*/d" Makefile + sed -i "/^LDFLAGS=.*/d" Makefile + sed -i "s/^all: libbz2.a bzip2 bzip2recover test/all: libbz2.a bzip2 bzip2recover/" Makefile + make -j${HOST_NUM_CPU} + make install PREFIX=${PREFIX} +# sed -i "/^CC=.*/d" Makefile-libbz2_so +# make -f Makefile-libbz2_so -j${HOST_NUM_CPU} +# cp libbz2.so.1.0.6 ${SYSROOT}/usr/lib/libbz2.so + cd .. +} + +## More information available at http://doc.qt.io/qt-5/opensslsupport.html +task_register build_openssl +build_openssl() +{ + B_dir="openssl-${OPENSSL_SOURCE_VERSION}" + rm -rf $B_dir + + verified_download $B_dir.tar.gz $OPENSSL_SOURCE_SHA256 \ + https://www.openssl.org/source/$B_dir.tar.gz + + tar -xf $B_dir.tar.gz + cd $B_dir +## We link openssl statically to avoid android silently sneaking in his own +## version of libssl.so (we noticed this because it had some missing symbol +## that made RS crash), the crash in some android version is only one of the +## possible problems the fact that android insert his own binary libssl.so pose +## non neglegible security concerns. + oBits="32" + [[ ${ANDROID_NDK_ARCH} =~ .*64.* ]] && oBits=64 + + ANDROID_NDK="${ANDROID_NDK_PATH}" PATH="${SYSROOT}/bin/:${PATH}" \ + ./Configure linux-generic${oBits} -fPIC --prefix="${PREFIX}" \ + --openssldir="${SYSROOT}/etc/ssl" +# sed -i 's/LIBNAME=$$i LIBVERSION=$(SHLIB_MAJOR).$(SHLIB_MINOR) \\/LIBNAME=$$i \\/g' Makefile +# sed -i '/LIBCOMPATVERSIONS=";$(SHLIB_VERSION_HISTORY)" \\/d' Makefile + + # Avoid documentation build which is unneded and time consuming + echo "exit 0; " > util/process_docs.pl + + make -j${HOST_NUM_CPU} + make install + rm -f ${PREFIX}/lib/libssl.so* + rm -f ${PREFIX}/lib/libcrypto.so* + cd .. +} + +task_register build_sqlite +build_sqlite() +{ + B_dir="sqlite-autoconf-${SQLITE_SOURCE_VERSION}" + rm -rf $B_dir + + verified_download $B_dir.tar.gz $SQLITE_SOURCE_SHA256 \ + https://www.sqlite.org/${SQLITE_SOURCE_YEAR}/$B_dir.tar.gz + + tar -xf $B_dir.tar.gz + cd $B_dir + ./configure --with-pic --prefix="${PREFIX}" --host=${cArch}-linux + make -j${HOST_NUM_CPU} + make install + rm -f ${PREFIX}/lib/libsqlite3.so* + cd .. +} + +task_register build_sqlcipher +build_sqlcipher() +{ + task_run build_sqlite + + B_dir="sqlcipher-${SQLCIPHER_SOURCE_VERSION}" + rm -rf $B_dir + + T_file="${B_dir}.tar.gz" + + verified_download $T_file $SQLCIPHER_SOURCE_SHA256 \ + https://github.com/sqlcipher/sqlcipher/archive/v${SQLCIPHER_SOURCE_VERSION}.tar.gz + + tar -xf $T_file + cd $B_dir +# case "${ANDROID_NDK_ARCH}" in +# "arm64") +# # SQLCipher config.sub is outdated and doesn't recognize newer architectures +# rm config.sub +# autoreconf --verbose --install --force +# automake --add-missing --copy --force-missing +# ;; +# esac + ./configure --with-pic --build=$(sh ./config.guess) \ + --host=${cArch}-linux \ + --prefix="${PREFIX}" --with-sysroot="${SYSROOT}" \ + --enable-tempstore=yes \ + --disable-tcl --disable-shared \ + CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="${PREFIX}/lib/libcrypto.a" + make -j${HOST_NUM_CPU} + make install + cd .. +} + +task_register build_libupnp +build_libupnp() +{ + B_dir="pupnp-release-${LIBUPNP_SOURCE_VERSION}" + B_ext=".tar.gz" + B_file="${B_dir}${B_ext}" + rm -rf $B_dir + + verified_download $B_file $LIBUPNP_SOURCE_SHA256 \ + https://github.com/mrjimenez/pupnp/archive/release-${LIBUPNP_SOURCE_VERSION}${B_ext} + + tar -xf $B_file + cd $B_dir + ./bootstrap +## liupnp must be configured as static library because if not the linker will +## look for libthreadutils.so.6 at runtime that cannot be packaged on android +## as it supports only libname.so format for libraries, thus resulting in a +## crash at startup. + ./configure --with-pic --enable-static --disable-shared --disable-samples \ + --disable-largefile \ + --prefix="${PREFIX}" --host=${cArch}-linux + make -j${HOST_NUM_CPU} + make install + cd .. +} + +task_register build_rapidjson +build_rapidjson() +{ + B_dir="rapidjson-${RAPIDJSON_SOURCE_VERSION}" + D_file="${B_dir}.tar.gz" + verified_download $D_file $RAPIDJSON_SOURCE_SHA256 \ + https://github.com/Tencent/rapidjson/archive/v${RAPIDJSON_SOURCE_VERSION}.tar.gz + tar -xf $D_file + cp -r "${B_dir}/include/rapidjson/" "${PREFIX}/include/rapidjson" +} + +task_register build_restbed +build_restbed() +{ + S_dir="restbed" + B_dir="${S_dir}-build" + git_source_get "$S_dir" "$RESTBED_SOURCE_REPO" "${RESTBED_SOURCE_VERSION}" \ + "dependency/asio" "dependency/catch" + + rm -rf "$B_dir"; mkdir "$B_dir" + pushd "$B_dir" + andro_cmake -DBUILD_TESTS=OFF -DBUILD_SSL=OFF -B. -H../${S_dir} + make -j${HOST_NUM_CPU} + make install + popd +} + +task_register build_udp-discovery-cpp +build_udp-discovery-cpp() +{ + S_dir="udp-discovery-cpp" + [ -d $S_dir ] || git clone $UDP_DISCOVERY_CPP_SOURCE $S_dir + cd $S_dir + git checkout $UDP_DISCOVERY_CPP_VERSION + cd .. + + B_dir="udp-discovery-cpp-build" + rm -rf ${B_dir}; mkdir ${B_dir}; cd ${B_dir} + andro_cmake -B. -H../$S_dir + make -j${HOST_NUM_CPU} + cp libudp-discovery.a "${PREFIX}/lib/" + cp ../$S_dir/*.hpp "${PREFIX}/include/" + cd .. +} + +task_register build_xapian +build_xapian() +{ + B_dir="xapian-core-${XAPIAN_SOURCE_VERSION}" + D_file="$B_dir.tar.xz" + verified_download $D_file $XAPIAN_SOURCE_SHA256 \ + https://oligarchy.co.uk/xapian/${XAPIAN_SOURCE_VERSION}/$D_file + rm -rf $B_dir + tar -xf $D_file + cd $B_dir + B_endiannes_detection_failure_workaround="ac_cv_c_bigendian=no" + B_large_file="" + [ "${ANDROID_PLATFORM_VER}" -lt "24" ] && B_large_file="--disable-largefile" + ./configure ${B_endiannes_detection_failure_workaround} ${B_large_file} \ + --with-pic \ + --disable-backend-inmemory --disable-backend-remote \ + --disable--backend-chert --enable-backend-glass \ + --host=${cArch}-linux --enable-static --disable-shared \ + --prefix="${PREFIX}" --with-sysroot="${SYSROOT}" + make -j${HOST_NUM_CPU} + make install + cd .. +} + +task_register build_miniupnpc +build_miniupnpc() +{ + S_dir="miniupnpc-${MINIUPNPC_SOURCE_VERSION}" + B_dir="miniupnpc-${MINIUPNPC_SOURCE_VERSION}-build" + D_file="$S_dir.tar.gz" + verified_download $D_file $MINIUPNPC_SOURCE_SHA256 \ + http://miniupnp.free.fr/files/${D_file} + rm -rf $S_dir $B_dir + tar -xf $D_file + mkdir $B_dir + cd $B_dir + andro_cmake \ + -DUPNPC_BUILD_STATIC=TRUE \ + -DUPNPC_BUILD_SHARED=FALSE \ + -DUPNPC_BUILD_TESTS=FALSE \ + -DUPNPC_BUILD_SAMPLE=FALSE \ + -B. -S../$S_dir + make -j${HOST_NUM_CPU} + make install + cd .. +} + +task_register build_zlib +build_zlib() +{ + S_dir="zlib-${ZLIB_SOURCE_VERSION}" + B_dir="zlib-${ZLIB_SOURCE_VERSION}-build" + D_file="$S_dir.tar.xz" + verified_download $D_file $ZLIB_SOURCE_SHA256 \ + http://www.zlib.net/${D_file} + rm -rf $S_dir $B_dir + tar -xf $D_file + mkdir $B_dir + cd $B_dir + andro_cmake -B. -S../$S_dir + make -j${HOST_NUM_CPU} + make install + rm -f ${PREFIX}/lib/libz.so* + cd .. +} + +task_register build_libpng +build_libpng() +{ + task_run build_zlib + + S_dir="libpng-${LIBPNG_SOURCE_VERSION}" + B_dir="libpng-${LIBPNG_SOURCE_VERSION}-build" + D_file="$S_dir.tar.xz" + verified_download $D_file $LIBPNG_SOURCE_SHA256 \ + https://download.sourceforge.net/libpng/${D_file} + rm -rf $S_dir $B_dir + tar -xf $D_file + + # libm is part of bionic An android + sed -i -e 's/find_library(M_LIBRARY m)/set(M_LIBRARY "")/' $S_dir/CMakeLists.txt + + # Disable hardware acceleration as they are problematic for Android + # compilation and are not supported by all phones, it is necessary to fiddle + # with CMakeLists.txt as libpng 1.6.37 passing it as cmake options seems not + # working properly + # https://github.com/imagemin/optipng-bin/issues/97 + # https://github.com/opencv/opencv/issues/7600 + echo "add_definitions(-DPNG_ARM_NEON_OPT=0)" >> $S_dir/CMakeLists.txt + + mkdir $B_dir + pushd $B_dir + + HW_OPT="OFF" +# [ "$ANDROID_PLATFORM_VER" -ge "22" ] && HW_OPT="ON" + + andro_cmake \ + -DPNG_SHARED=OFF \ + -DPNG_STATIC=ON \ + -DPNG_TESTS=OFF \ + -DPNG_HARDWARE_OPTIMIZATIONS=$HW_OPT \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON \ + -B. -S../$S_dir + make -j${HOST_NUM_CPU} + make install + popd +} + +task_register build_libjpeg +build_libjpeg() +{ + S_dir="jpeg-${LIBJPEG_SOURCE_VERSION}" + D_file="jpegsrc.v${LIBJPEG_SOURCE_VERSION}.tar.gz" + verified_download $D_file $LIBJPEG_SOURCE_SHA256 \ + https://www.ijg.org/files/$D_file + rm -rf $S_dir + tar -xf $D_file + cd $S_dir + ./configure --with-pic --prefix="${PREFIX}" --host=${cArch}-linux + make -j${HOST_NUM_CPU} + make install + rm -f ${PREFIX}/lib/libjpeg.so* + cd .. +} + +task_register build_tiff +build_tiff() +{ + S_dir="tiff-${TIFF_SOURCE_VERSION}" + B_dir="${S_dir}-build" + D_file="tiff-${TIFF_SOURCE_VERSION}.tar.gz" + + verified_download $D_file $TIFF_SOURCE_SHA256 \ + https://download.osgeo.org/libtiff/${D_file} + + rm -rf $S_dir $B_dir + tar -xf $D_file + mkdir $B_dir + + # Disable tools building, not needed for retroshare, and depending on some + # OpenGL headers not available on Android + echo "" > $S_dir/tools/CMakeLists.txt + + # Disable tests building, not needed for retroshare, and causing linker + # errors + echo "" > $S_dir/test/CMakeLists.txt + + # Disable extra tools building, not needed for retroshare, and causing + # linker errors + echo "" > $S_dir/contrib/CMakeLists.txt + + # Disable more unneded stuff + echo "" > $S_dir/build/CMakeLists.txt + echo "" > $S_dir/html/CMakeLists.txt + echo "" > $S_dir/man/CMakeLists.txt + echo "" > $S_dir/port/CMakeLists.txt + + # Change to static library build + sed -i 's\add_library(tiff\add_library(tiff STATIC\' \ + $S_dir/libtiff/CMakeLists.txt + + cd $B_dir + #TODO: build dependecies to support more formats + andro_cmake \ + -Dlibdeflate=OFF -Djbig=OFF -Dlzma=OFF -Dzstd=OFF -Dwebp=OFF \ + -Djpeg12=OFF \ + -Dcxx=OFF \ + -B. -S../$S_dir + make -j${HOST_NUM_CPU} + make install + cd .. +} + +task_register build_cimg +build_cimg() +{ + task_run build_libpng + task_run build_libjpeg + task_run build_tiff + + S_dir="CImg-${CIMG_SOURCE_VERSION}" + D_file="CImg_${CIMG_SOURCE_VERSION}.zip" + + verified_download $D_file $CIMG_SOURCE_SHA256 \ + https://cimg.eu/files/${D_file} + + unzip -o $D_file + + cp --archive --verbose "$S_dir/CImg.h" "$PREFIX/include/" +} + +task_register build_phash +build_phash() +{ + task_run build_cimg + + S_dir="pHash" + B_dir="${S_dir}-build" + + git_source_get "$S_dir" "$PHASH_SOURCE_REPO" "${PHASH_SOURCE_VERSION}" + + rm -rf $B_dir; mkdir $B_dir ; pushd $B_dir + andro_cmake -DPHASH_DYNAMIC=OFF -DPHASH_STATIC=ON -B. -H../pHash + make -j${HOST_NUM_CPU} + make install + popd +} + +task_register fetch_jni_hpp +fetch_jni_hpp() +{ + local rDir="supportlibs/jni.hpp/" + + [ "$(ls "${RS_SRC_DIR}/${rDir}" | wc -l)" -gt "4" ] || + git -C ${RS_SRC_DIR} submodule update --init ${rDir} +} + +task_register build_mvptree +build_mvptree() +{ + S_dir="mvptree" + B_dir="${S_dir}-build" + + git_source_get "$S_dir" "$MVPTREE_SOURCE_REPO" "${MVPTREE_SOURCE_VERSION}" + rm -rf $B_dir; mkdir $B_dir ; pushd $B_dir + andro_cmake -B. -H../${S_dir} + make -j${HOST_NUM_CPU} + make install + popd +} + +task_register build_libretroshare +build_libretroshare() +{ + S_dir="/home/gio/Development/rs-develop/libretroshare" + B_dir="libretroshare-build" + +# -DCMAKE_SYSTEM_NAME="Android" \ +# -DCMAKE_ANDROID_NDK="$ANDROID_NDK_PATH" \ +# -DCMAKE_SYSTEM_VERSION=$ANDROID_PLATFORM_VER \ + +# -D RS_FORUM_DEEP_INDEX=ON -D RS_JSON_API=ON \ + + rm -rf $B_dir; mkdir $B_dir ; pushd $B_dir + andro_cmake -B. -H${S_dir} -DCMAKE_BUILD_TYPE=Release \ + -D RS_ANDROID=ON -D RS_WARN_DEPRECATED=OFF -D RS_WARN_LESS=ON \ + -D RS_LIBRETROSHARE_STATIC=OFF -D RS_LIBRETROSHARE_SHARED=ON \ + -D RS_BRODCAST_DISCOVERY=ON -D RS_EXPORT_JNI_ONLOAD=ON + make -j${HOST_NUM_CPU} + make install + popd +} + +task_register get_native_libs_toolchain_path +get_native_libs_toolchain_path() +{ + echo ${NATIVE_LIBS_TOOLCHAIN_PATH} +} + +task_register build_default_toolchain +build_default_toolchain() +{ + task_run bootstrap_toolchain || return $? + task_run build_bzlib || return $? + task_run build_openssl || return $? + task_run build_sqlcipher || return $? + task_run build_rapidjson || return $? +# task_run build_restbed || return $? +# task_run build_udp-discovery-cpp || return $? + task_run build_xapian || return $? + task_run build_miniupnpc || return $? + task_run build_phash || return $? +# task_run fetch_jni_hpp || return $? + task_run build_libretroshare || return $? +# task_run deduplicate_includes || return $? + task_run get_native_libs_toolchain_path || return $? +} + +if [ "$1" == "" ]; then + rm -rf "$REPORT_DIR" + mkdir -p "$REPORT_DIR" + cat "$0" > "$REPORT_DIR/build_script" + env > "$REPORT_DIR/build_env" + build_default_toolchain +else + # do not delete report directory in this case so we can reuse material + # produced by previous run, like deduplicated includes + mkdir -p "$REPORT_DIR" + while [ "$1" != "" ] ; do + task_zap $1 + task_run $1 || exit $? + shift + done +fi diff --git a/misc/Android/pull_sysroot.sh b/misc/Android/pull_sysroot.sh new file mode 100755 index 000000000..d474610e4 --- /dev/null +++ b/misc/Android/pull_sysroot.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +# Script to pull debugging sysroot from Android devices +# +# Copyright (C) 2020 Gioacchino Mazzurco +# Copyright (C) 2020 Asociación Civil Altermundi +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see + +<<"ASCIIDOC" + +Pull files from Android device to prepare a debugging sysroot +Inspired by: +https://fw4spl-org.github.io/fw4spl-blog/2015/07/27/Native-debugging-on-Android-with-QtCreator.html + +The goal is to have a local copy of the sysroot of the connected device. +For that we use the command `adb pull ` + +We will get a copy of: + +- `/system/lib/` +- `/vendor/lib/` +- `libc.so` +- `libcutils.so` + +As well as the binaries `linker` and `app_process` + +IMPORTANT: +from one device to another, the remote file `app_process` can be a binary file +or a symlink to a binary file - which is NOT ok for us. +That's so we will try to pull every known possible variants of `app_process`, +e.g. `app_process32` or `app_process_init` + +ASCIIDOC + + +## Define default value for variable, take two arguments, $1 variable name, +## $2 default variable value, if the variable is not already define define it +## with default value. +function define_default_value() +{ + VAR_NAME="${1}" + DEFAULT_VALUE="${2}" + + [ -z "${!VAR_NAME}" ] && export ${VAR_NAME}="${DEFAULT_VALUE}" +} + +define_default_value ANDROID_SERIAL "$(adb devices | head -n 2 | tail -n 1 | awk '{print $1}')" +define_default_value DEBUG_SYSROOT "${HOME}/Builds/debug_sysroot/${ANDROID_SERIAL}/" + +rm -rf "${DEBUG_SYSROOT}" + +for mDir in "/system/lib/" "/vendor/lib/"; do + mkdir -p "${DEBUG_SYSROOT}/${mDir}" + # adb pull doesn't behave like rsync dirA/ dirB/ so avoid nesting the + # directory by deleting last one before copying + rmdir "${DEBUG_SYSROOT}/${mDir}" + adb pull "${mDir}" "${DEBUG_SYSROOT}/${mDir}" +done + +# Retrieve the specific binaries - some of these adb commands will fail, since +# some files may not exist, but that's ok. + +mkdir -p "${DEBUG_SYSROOT}/system/bin/" +for mBin in "/system/bin/linker" "/system/bin/app_process" \ + "/system/bin/app_process_init" "/system/bin/app_process32" \ + "/system/bin/app_process64" ; do + adb pull "${mBin}" "${DEBUG_SYSROOT}/${mBin}" +done + +# Verify which variants of the specific binaries could be pulled +echo +echo "Found the following specific binaries:" +echo +ls -1 "${DEBUG_SYSROOT}/system/bin/"* +ls -1 "${DEBUG_SYSROOT}/system/lib/libc.so"* +ls -1 "${DEBUG_SYSROOT}/system/lib/libcutils.so"* +echo + +echo DEBUG_SYSROOT="${DEBUG_SYSROOT}" diff --git a/misc/Android/start_gdbserver.sh b/misc/Android/start_gdbserver.sh new file mode 100755 index 000000000..1fd751e67 --- /dev/null +++ b/misc/Android/start_gdbserver.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# Script to start gdbserver on Android device and attach to retroshare-service +# +# Copyright (C) 2020 Gioacchino Mazzurco +# Copyright (C) 2020 Asociación Civil Altermundi +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the +# Free Software Foundation, version 3. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see + +<<"ASCIIDOC" + +Start gdbserver on Android device and attach it to the retroshare service +process + +Inspired by: +https://fw4spl-org.github.io/fw4spl-blog/2015/07/27/Native-debugging-on-Android-with-QtCreator.html + +ASCIIDOC + + +## Define default value for variable, take two arguments, $1 variable name, +## $2 default variable value, if the variable is not already define define it +## with default value. +function define_default_value() +{ + VAR_NAME="${1}" + DEFAULT_VALUE="${2}" + + [ -z "${!VAR_NAME}" ] && export ${VAR_NAME}="${DEFAULT_VALUE}" || true +} + +define_default_value ANDROID_APK_PACKAGE "org.retroshare.service" +define_default_value ANDROID_PROCESS_NAME "org.retroshare.service:rs" +define_default_value ANDROID_INSTALL_PATH "" +define_default_value LIB_GDB_SERVER_PATH "" +define_default_value ANDROID_SERIAL "$(adb devices | head -n 2 | tail -n 1 | awk '{print $1}')" +define_default_value GDB_SERVER_PORT 5039 + +adb_ushell() +{ + adb shell run-as ${ANDROID_APK_PACKAGE} $@ +} + +[ -z "${ANDROID_INSTALL_PATH}" ] && +{ + ANDROID_INSTALL_PATH="$(adb_ushell pm path "${ANDROID_APK_PACKAGE}")" + ANDROID_INSTALL_PATH="$(dirname ${ANDROID_INSTALL_PATH#"package:"})" + [ -z "${ANDROID_INSTALL_PATH}" ] && + cat < +#include "retroshare/rsturtle.h" #include "util/rstime.h" +#include "rs_android/largefile_retrocompat.hpp" + /* For Thread Behaviour */ const uint32_t DMULTIPLEX_MIN = 10; /* 10 msec sleep */ diff --git a/src/ft/ftfilecreator.cc b/src/ft/ftfilecreator.cc index a5c354092..e38edc571 100644 --- a/src/ft/ftfilecreator.cc +++ b/src/ft/ftfilecreator.cc @@ -19,18 +19,21 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifdef WINDOWS_SYS -#include "util/rsstring.h" -#include "util/rswin.h" -#endif + +#include +#include +#include #include "ftfilecreator.h" -#include -#include #include "util/rstime.h" -#include -#include -#include +#include "util/rsdiscspace.h" +#include "util/rsdir.h" +#include "rs_android/largefile_retrocompat.hpp" + +#ifdef WINDOWS_SYS +# include "util/rsstring.h" +# include "util/rswin.h" +#endif /******* * #define FILE_DEBUG 1 diff --git a/src/ft/ftfileprovider.cc b/src/ft/ftfileprovider.cc index 0660a9bca..b789f9057 100644 --- a/src/ft/ftfileprovider.cc +++ b/src/ft/ftfileprovider.cc @@ -19,17 +19,20 @@ * along with this program. If not, see . * * * *******************************************************************************/ -#ifdef WINDOWS_SYS -#include "util/rswin.h" -#endif // WINDOWS_SYS + +#include +#include #include "ftfileprovider.h" #include "ftchunkmap.h" - -#include "util/rsdir.h" -#include -#include #include "util/rstime.h" +#include "util/rsdir.h" +#include "rs_android/largefile_retrocompat.hpp" + +#ifdef WINDOWS_SYS +# include "util/rswin.h" +#endif // WINDOWS_SYS + /******** * #define DEBUG_FT_FILE_PROVIDER 1 diff --git a/src/libretroshare.pro b/src/libretroshare.pro index 413e0b0a8..bbc898934 100644 --- a/src/libretroshare.pro +++ b/src/libretroshare.pro @@ -1093,14 +1093,6 @@ test_bitdht { android-* { lessThan(ANDROID_API_VERSION, 24) { - -## TODO: This probably disable largefile support and maybe is not necessary with -## __ANDROID_API__ >= 24 hence should be made conditional or moved to a -## compatibility header - DEFINES *= "fopen64=fopen" - DEFINES *= "fseeko64=fseeko" - DEFINES *= "ftello64=ftello" - ## @See: rs_android/README-ifaddrs-android.adoc HEADERS += \ rs_android/ifaddrs-android.h \ @@ -1115,6 +1107,7 @@ android-* { PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs) HEADERS += \ + rs_android/largefile_retrocompat.hpp \ rs_android/androidcoutcerrcatcher.hpp \ rs_android/retroshareserviceandroid.hpp \ rs_android/rsjni.hpp diff --git a/src/rs_android/AndroidManifest.xml b/src/rs_android/AndroidManifest.xml new file mode 100644 index 000000000..426c66705 --- /dev/null +++ b/src/rs_android/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/rs_android/largefile_retrocompat.hpp b/src/rs_android/largefile_retrocompat.hpp new file mode 100644 index 000000000..0140011ff --- /dev/null +++ b/src/rs_android/largefile_retrocompat.hpp @@ -0,0 +1,31 @@ +/******************************************************************************* + * * + * libretroshare: retroshare core library * + * * + * Copyright (C) 2016-2021 Gioacchino Mazzurco * + * Copyright (C) 2021 Asociación Civil Altermundi * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of the * + * License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ +#pragma once + +#ifdef __ANDROID__ +# include +# if __ANDROID_API__ < 24 +# define fopen64 fopen +# define fseeko64 fseeko +# define ftello64 ftello +# endif +#endif diff --git a/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java b/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java index 818f06348..0e3d5ced9 100644 --- a/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java +++ b/src/rs_android/org/retroshare/service/RetroShareServiceAndroid.java @@ -1,7 +1,8 @@ /* * RetroShare - * Copyright (C) 2016-2021 Gioacchino Mazzurco - * Copyright (C) 2021 Asociación Civil Altermundi + * + * Copyright (C) 2016-2022 Gioacchino Mazzurco + * Copyright (C) 2021-2022 Asociación Civil Altermundi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -36,7 +37,7 @@ public class RetroShareServiceAndroid extends Service public static final int DEFAULT_JSON_API_PORT = 9092; public static final String DEFAULT_JSON_API_BINDING_ADDRESS = "127.0.0.1"; - static { System.loadLibrary("retroshare-service"); } + static { System.loadLibrary("retroshare"); } public static void start( Context ctx, int jsonApiPort, String jsonApiBindAddress ) diff --git a/src/util/rsdir.cc b/src/util/rsdir.cc index aa7e59299..0f7594f5b 100644 --- a/src/util/rsdir.cc +++ b/src/util/rsdir.cc @@ -27,6 +27,15 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "util/rsdir.h" #include "util/rsstring.h" @@ -37,16 +46,6 @@ #include "retroshare/rstypes.h" #include "retroshare/rsnotify.h" #include "rsthreads.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include #if defined(WIN32) || defined(__CYGWIN__) #include "util/rsstring.h" @@ -60,6 +59,8 @@ #define canonicalize_file_name(p) realpath(p, NULL) #endif +#include "rs_android/largefile_retrocompat.hpp" + /**** * #define RSDIR_DEBUG 1 ****/ @@ -580,7 +581,7 @@ bool RsDirUtil::checkCreateDirectory(const std::string& dir) std::string RsDirUtil::removeSymLinks(const std::string& path) { -#if defined(WINDOWS_SYS) || defined(__APPLE__) || defined(__ANDROID__) +#if defined(WINDOWS_SYS) || defined(__APPLE__) //|| defined(__ANDROID__) #warning (Mr.Alice): I don't know how to do this on windows/MacOS/Android. See https://msdn.microsoft.com/en-us/library/windows/desktop/hh707084(v=vs.85).aspx' //if(!S_OK == PathCchCanonicalizeEx(tmp,...) ; return path ;