From e5bc34a7b1699f998fc7190e8acf7b9930d5ba42 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 18 Jun 2021 11:28:33 -0400 Subject: [PATCH] [buildsystem] remove use of ninja entirely * modify contrib/window.sh now uses makefiles * create contrib/android.sh for building shared libs for android apk * update drone ci jizz for android * update cmake/StaticBuild.cmake to use $(MAKE) so that builds can parallelize (super epic) * remove android directory as it is no longer needed --- .drone.jsonnet | 37 ++-- android/.gitignore | 18 -- android/AndroidManifest.xml | 46 ----- android/build.gradle | 81 -------- android/build.xml | 96 --------- android/proguard-project.txt | 20 -- android/project.properties | 14 -- android/readme.md | 33 ---- android/res/drawable/icon.png | Bin 6565 -> 0 bytes android/res/layout/activity_perms_asker.xml | 27 --- .../res/layout/activity_perms_explanation.xml | 27 --- android/res/menu/options_main.xml | 16 -- android/res/values/strings.xml | 19 -- android/res/values/template-dimens.xml | 16 -- android/settings.gradle | 1 - .../network/loki/lokinet/LokiNetActivity.java | 185 ------------------ .../lokinet/NetworkStateChangeReceiver.java | 28 --- .../loki/lokinet/PermsAskerActivity.java | 173 ---------------- .../lokinet/PermsExplanationActivity.java | 38 ---- cmake/StaticBuild.cmake | 8 +- contrib/android.sh | 39 ++++ contrib/ci/drone-static-upload.sh | 6 +- contrib/windows.sh | 4 +- .../network/loki/lokinet/LokinetConfig.java | 0 .../network/loki/lokinet/LokinetDaemon.java | 0 25 files changed, 60 insertions(+), 872 deletions(-) delete mode 100644 android/.gitignore delete mode 100755 android/AndroidManifest.xml delete mode 100644 android/build.gradle delete mode 100644 android/build.xml delete mode 100644 android/proguard-project.txt delete mode 100644 android/project.properties delete mode 100644 android/readme.md delete mode 100644 android/res/drawable/icon.png delete mode 100644 android/res/layout/activity_perms_asker.xml delete mode 100644 android/res/layout/activity_perms_explanation.xml delete mode 100644 android/res/menu/options_main.xml delete mode 100755 android/res/values/strings.xml delete mode 100644 android/res/values/template-dimens.xml delete mode 100644 android/settings.gradle delete mode 100755 android/src/network/loki/lokinet/LokiNetActivity.java delete mode 100644 android/src/network/loki/lokinet/NetworkStateChangeReceiver.java delete mode 100644 android/src/network/loki/lokinet/PermsAskerActivity.java delete mode 100644 android/src/network/loki/lokinet/PermsExplanationActivity.java create mode 100755 contrib/android.sh rename {android => jni/java}/src/network/loki/lokinet/LokinetConfig.java (100%) rename {android => jni/java}/src/network/loki/lokinet/LokinetDaemon.java (100%) diff --git a/.drone.jsonnet b/.drone.jsonnet index 54951b7b6..6715be1ba 100644 --- a/.drone.jsonnet +++ b/.drone.jsonnet @@ -1,6 +1,6 @@ local default_deps_base='libsystemd-dev python3-dev libuv1-dev libunbound-dev nettle-dev libssl-dev libevent-dev libsqlite3-dev libcurl4-openssl-dev'; local default_deps_nocxx='libsodium-dev ' + default_deps_base; // libsodium-dev needs to be >= 1.0.18 -local default_deps='g++ ' + default_deps_nocxx; // g++ sometimes needs replacement +local default_deps='build-essential ' + default_deps_nocxx; local default_windows_deps='mingw-w64 zip nsis'; local docker_base = 'registry.oxen.rocks/lokinet-ci-'; @@ -49,20 +49,20 @@ local debian_pipeline(name, image, ] else [] ) + [ 'eatmydata ' + apt_get_quiet + ' dist-upgrade -y', - 'eatmydata ' + apt_get_quiet + ' install -y gdb cmake git ninja-build pkg-config ccache ' + deps, + 'eatmydata ' + apt_get_quiet + ' install -y gdb cmake git pkg-config ccache ' + deps, 'mkdir build', 'cd build', - 'cmake .. -G Ninja -DWITH_SETCAP=OFF -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_BUILD_TYPE='+build_type+' ' + + 'cmake .. -DWITH_SETCAP=OFF -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_BUILD_TYPE='+build_type+' ' + (if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + '-DWITH_LTO=' + (if lto then 'ON ' else 'OFF ') + cmake_extra, - 'ninja -j' + jobs + ' -v', + 'make -j' + jobs, '../contrib/ci/drone-gdb.sh ./test/testAll --use-colour yes', ] + extra_cmds, } ], }; -local apk_builder(name, image, extra_cmds=[], allow_fail=false) = { +local apk_builder(name, image, extra_cmds=[], allow_fail=false, jobs=6) = { kind: 'pipeline', type: 'docker', name: name, @@ -76,11 +76,7 @@ local apk_builder(name, image, extra_cmds=[], allow_fail=false) = { [if allow_fail then "failure"]: "ignore", environment: { SSH_KEY: { from_secret: "SSH_KEY" }, ANDROID: "android" }, commands: [ - "cd android", - "rm -f local.properties", - "echo 'sdk.dir=/usr/lib/android-sdk' >> local.properties", - "echo 'ndk.dir=/usr/lib/android-ndk' >> local.properties", - "GRADLE_USER_HOME=/cache/gradle/${DRONE_STAGE_MACHINE} gradle --no-daemon assembleDebug", + 'JOBS='+jobs+' NDK=/usr/lib/android-ndk ./contrib/android.sh' ] + extra_cmds } ] @@ -113,17 +109,10 @@ local windows_cross_pipeline(name, image, 'echo "man-db man-db/auto-update boolean false" | debconf-set-selections', apt_get_quiet + ' update', apt_get_quiet + ' install -y eatmydata', - 'eatmydata ' + apt_get_quiet + ' install -y build-essential cmake git ninja-build pkg-config ccache g++-mingw-w64-x86-64-posix nsis zip automake libtool', + 'eatmydata ' + apt_get_quiet + ' install -y build-essential cmake git pkg-config ccache g++-mingw-w64-x86-64-posix nsis zip automake libtool', 'update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix', 'update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix', - 'mkdir build', - 'cd build', - 'cmake .. -G Ninja -DCMAKE_EXE_LINKER_FLAGS=-fstack-protector -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_TOOLCHAIN_FILE=../contrib/cross/mingw'+toolchain+'.cmake -DCMAKE_BUILD_TYPE='+build_type+' ' + - (if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + - (if lto then '' else '-DWITH_LTO=OFF ') + - "-DBUILD_STATIC_DEPS=ON -DDOWNLOAD_SODIUM=ON -DBUILD_PACKAGE=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF -DNATIVE_BUILD=OFF -DSTATIC_LINK=ON" + - cmake_extra, - 'ninja -j' + jobs + ' -v package', + 'JOBS=' + jobs + ' ./contrib/windows.sh' ] + extra_cmds, } ], @@ -204,9 +193,9 @@ local mac_builder(name, 'ulimit -n 1024', // because macos sets ulimit to 256 for some reason yeah idk 'mkdir build', 'cd build', - 'cmake .. -G Ninja -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' + + 'cmake .. -DCMAKE_CXX_FLAGS=-fcolor-diagnostics -DCMAKE_BUILD_TYPE='+build_type+' ' + (if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') + cmake_extra, - 'ninja -j' + jobs + ' -v', + 'make -j' + jobs, './test/testAll --use-colour yes', ] + extra_cmds, } @@ -254,12 +243,12 @@ local mac_builder(name, ], jobs=4), // android apk builder - apk_builder("android apk", "registry.oxen.rocks/lokinet-ci-android", extra_cmds=['UPLOAD_OS=anrdoid ../contrib/ci/drone-static-upload.sh']), - + apk_builder("android apk", "registry.oxen.rocks/lokinet-ci-android", extra_cmds=['UPLOAD_OS=anrdoid ./contrib/ci/drone-static-upload.sh']), + // Windows builds (x64) windows_cross_pipeline("Windows (amd64)", docker_base+'debian-win32-cross', toolchain='64', extra_cmds=[ - '../contrib/ci/drone-static-upload.sh' + './contrib/ci/drone-static-upload.sh' ]), // Static build (on bionic) which gets uploaded to builds.lokinet.dev: diff --git a/android/.gitignore b/android/.gitignore deleted file mode 100644 index b8e7e769a..000000000 --- a/android/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -gen -tests -bin -libs -log* -obj -.gradle -.idea -.externalNativeBuild -ant.properties -local.properties -build.sh -android.iml -build -gradle -gradlew -gradlew.bat -gradle.properties \ No newline at end of file diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml deleted file mode 100755 index 082852b42..000000000 --- a/android/AndroidManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 3fd226539..000000000 --- a/android/build.gradle +++ /dev/null @@ -1,81 +0,0 @@ -buildscript { - repositories { - mavenCentral() - jcenter() - google() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' - } -} - -apply plugin: 'com.android.application' - - -repositories { - jcenter() - maven { - url 'https://maven.google.com' - } - google() -} - -android { - compileSdkVersion 28 - defaultConfig { - applicationId "network.loki.lokinet" - targetSdkVersion 28 - minSdkVersion 23 - versionCode 1 - versionName '0.8.4' - externalNativeBuild { - cmake { - targets "lokinet-android" - arguments "-DWITH_LTO=OFF", "-DCXXOPTS_BUILD_TESTS=OFF","-DWITH_TESTS=OFF", "-DCMAKE_CROSSCOMPILING=ON", "-DNATIVE_BUILD=OFF", "-DANDROID=ON", "-DANDROID_STL=c++_static", "-DBUILD_STATIC_DEPS=ON", "-DBUILD_SHARED_LIBS=OFF", "-DSTATIC_LINK=ON", "-DANDROID_ARM_MODE=arm", "-DFORCE_OXENMQ_SUBMODULE=ON", "-DBUILD_LIBLOKINET=OFF" - cppFlags "-std=c++17" - abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' - // abiFilters 'armeabi-v7a' - // abiFilters 'arm64-v8a', 'x86_64', 'armeabi-v7a' - } - } - - - } - externalNativeBuild { - cmake { - path "../CMakeLists.txt" - } - } - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src'] - res.srcDirs = ['res'] - jniLibs.srcDirs = ['libs'] - assets.srcDirs = ['assets'] - } - } - signingConfigs { - jeff { - storeFile file("jeff-apk.jks") - keyAlias "jeff-apk" - } - } - buildTypes { - release { - minifyEnabled true - //signingConfig signingConfigs.jeff - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' - debuggable false - } - debug { - // jniDebuggable true - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } -} - - diff --git a/android/build.xml b/android/build.xml deleted file mode 100644 index ffe9081c8..000000000 --- a/android/build.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/proguard-project.txt b/android/proguard-project.txt deleted file mode 100644 index f2fe1559a..000000000 --- a/android/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/android/project.properties b/android/project.properties deleted file mode 100644 index 919ca9c3b..000000000 --- a/android/project.properties +++ /dev/null @@ -1,14 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-28 diff --git a/android/readme.md b/android/readme.md deleted file mode 100644 index 647032dea..000000000 --- a/android/readme.md +++ /dev/null @@ -1,33 +0,0 @@ -# lokinet android - -this directory contains basic stuff for lokinet on android. - -## Prerequsites - -To build you need the following: - -* Gradle (6.x) -* Android SDK (latest version) -* Android NDK (latest version) - -## Building - -Next set up the path to Android SDK and NDK in `local.properties` - -``` -sdk.dir=/path/to/android/sdk -ndk.dir=/path/to/android/ndk -``` - -Then build: - - $ gradle assemble - -This fetches a large amount (several dozen Gigabytes) of files from some -server somewhere dumping it on your filesystem to make the thing do the -building, then proceeds to peg all your cores for several dozen minutes -while it does the required incantations to build 2 apks. - -The build outputs apks to to subdirectories in `build/outputs/apk/` -one called `debug` for debug builds and one called `release` for release builds. - diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png deleted file mode 100644 index 30ad9ddcb15345bb334ecb0e5c043aeb4b77392c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6565 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 - - - -