Skip to content

Commit

Permalink
Desktop Java builds with Gradle (#633)
Browse files Browse the repository at this point in the history
* Move Android build.gradle file from root

Introduce a subproject ":android" for AndroidThemis builds. We can't
continue using top-level build.gradle for everything if we are going
to use Gradle for Desktop Java too.

This changes the invocation strings for targets which now need to be
qualified (by prefixing ":android:...").

Leave the top-level file with some common definitions. This allows to
not write them in each subproject and to use "./gradlew" right from
the repository root.

* Basic desktop Java build with Gradle

Add a subproject ":desktop" for 'Desktop Java' builds of JavaThemis.
This will produce a JAR with Java bytecode only, suitable for use by
desktop Java projects.

You can build it with

    ./gradlew :desktop:build

and collect artifacts from "src/wrappers/themis/java/build/jar".

The resulting JAR file is named "java-themis" because the name "themis"
is already taked by AndroidThemis.

* Upgrade to Gradle 5.6

Debian stable has upgraded its default Java version to 11. Gradle 4.X
does not support Java 11. This version is supported only since 5.0.
Upgrade to latest Gradle 5.X version.

Note that *the latest* version branch is Gradle 6.X. We won't jump
versions that fast.

Gradle 5.X requires Java 8 (previously it required Java 7). This cuts
some older systems that ship with only Java 7:

  - Debian 8 "Jessie" - oldoldstable, no security support since
    June 2018, LTS support lapses in July 2020

(Only for JavaThemis, obviously.)

* Enable Gradle's "configure on demand"

By default Gradle will configure all subprojects of a top-level project.
For us that means that we'll force AndroidThemis configuration even if
the user is trying to build JavaThemis for desktop. That will require
a properly installed and configured Android SDK, completely unnecessary.

Thankfully, Gradle also have an experimental "configure on demand"
mode which will configure only the projects actually requested and
needed for the build. Enable this feature. It is 'experimental' but
this means that it might not work for some projects, but Gradle team
plans to make this mode the default one. It works for us, so it's okay.

* Suppress deprecations on finalizers

We build JavaThemis with deprecation warnings enabled. Object finalizers
are deprecated since Java 9. In our case we genuienly need finalizers to
prevent native memory leaks so suppress these warnings.

* Run JUnit tests during Gradle builds

The "build" target already runs tests if they are set up. Configure
JUnit test compilation and runner.

Note that JavaThemis requires JNI library to be loaded. By default it is
installed into a location that is not present in the Java library search
path. We need to explicitly add "/usr/local/lib" to "java.library.path"
property. Also note that Gradle will run JUnit stuff in a separate JVM
so we need to pass the system property to that JVM from the main one.

* Load JNI library from each class

Every class having native methods should have a System.loadLibrary()
call so that if only that class is loaded by JVM, the native library
is also loaded correctly.

It kinda worked before because typically users and tests load other
classes, but if *only* SymmetricKey is loaded then it failed to locate
the native method. (For example, JUnit might run each test in separate
JVMs which load only necessary classes.)

* Set package version via gradle.properties

Use common properties to have a single place we need to update when
doing a release.

* More version updates suggested by Android Studio

Update Gradle support library to the latest stable version. Update
Gradle wrapper to the latest patch version too (required for some of
others updates). And update the Android test runners as well.

New test runners require AndroidX property to be enabled in the
properties file so add that as well.

* Use a newer version of JUnit

Suggested by Android Studio too.

* Downgrade Gradle library to 3.5.3

Android Studio recommends using current latest stable version 3.6.3, but
it seems to have some issues with NDK version detection. Since we have
different NDK versions in our CI environments, we can't use the version
which fails to work with them.

Gradle tools v3.6.3 fail the build and require a particular version of
NDK, for example:

    * What went wrong:
    A problem occurred configuring project ':android'.
    > No version of NDK matched the requested version 20.0.5594570. Versions available locally: 21.0.6113669

Version 3.5.X does not seem to have such issues, so let's use it then.

* Revert to using Gradle tools 3.2.1

It seems that 3.5.3 does not work either. I don't want to spend more
time on this discretionary upgrade, so just revert to the version which
is known to work and let's keep it pinned that way until we need to
upgrade to have some new features or bug fixes.
  • Loading branch information
ilammy committed May 4, 2020
1 parent 44e4763 commit 2359a0d
Show file tree
Hide file tree
Showing 17 changed files with 286 additions and 180 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- run:
name: Build Themis
command: |
./gradlew --no-daemon assembleDebug
./gradlew --no-daemon :android:assembleDebug
- run:
name: Prepare Android emulator
command: |
Expand Down Expand Up @@ -48,7 +48,7 @@ jobs:
- run:
name: Run test suite
command: |
./gradlew --no-daemon connectedAndroidTest
./gradlew --no-daemon :android:connectedAndroidTest
analyze:
docker:
Expand Down
24 changes: 7 additions & 17 deletions .github/workflows/test-java.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,12 @@ jobs:
run: |
make all themis_jni
sudo make install themis_jni_install
# TODO: run JavaThemis unit tests, once we have them,
# but for now we're only testing JNI build
- name: Check JavaThemis loading
- name: Build and test JavaThemis
# Set native library search path for Java explicitly since most
# distribution-provided JVMs do not look there by default.
run: |
cat > Test.java <<EOF
public class Test {
static {
System.loadLibrary("themis_jni");
}
public static void main(String[] args) {
System.out.println("themis_jni loaded!");
}
}
EOF
javac Test.java
java -Djava.library.path=/usr/local/lib Test
./gradlew --no-daemon -Djava.library.path=/usr/local/lib \
:desktop:build
android-tests:
name: Android emulator
Expand All @@ -76,12 +66,12 @@ jobs:
with:
submodules: true
- name: Build Themis
run: ./gradlew --no-daemon assembleDebug
run: ./gradlew --no-daemon :android:assembleDebug
# This works reliably only in macOS runners which have HAXM available.
# Ubuntu runners do not have KVM enabled, modern x86 emulators do not
# work without KVM, and ARM emulator is abysmally slow.
- name: Run test suite
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 29
script: ./gradlew --no-daemon connectedAndroidTest
script: ./gradlew --no-daemon :android:connectedAndroidTest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ tests/phpthemis/composer.json
tests/phpthemis/composer.phar
tests/phpthemis/composer.lock

# Android build system
src/wrappers/themis/android/.externalNativeBuild
third_party/boringssl/.externalNativeBuild

# php
Expand Down
42 changes: 41 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Changes that are currently in development and have not been released yet.
- ObjCThemis installed via Carthage is now called `objcthemis` instead of just `themis` ([read more](#0.13.0-objcthemis-rename)).
- Themis 0.9.6 compatibility is now disabled by default ([read more](#0.13.0-drop-0.9.6-compat)).
- Themis is known to be broken on big-endian architectures ([read more](#0.13.0-big-endian)).
- Java 7 is no longer supported, breaking Android and Java builds on outdated systems ([read more](#0.13.0-drop-java-7))

_Code:_

Expand Down Expand Up @@ -58,6 +59,31 @@ _Code:_
If you believe you are affected by this change, please reach out to us via
[[email protected]](mailto:[email protected]).

- **Android**

See also: [Java API updates](#0.13.0-java).

- **Breaking changes**

- Android build now uses Gradle 5.6 and requires Java 8 ([#633](https://github.com/cossacklabs/themis/pull/633)).

It is no longer possible to build AndroidThemis with Java 7.
Please upgrade to Java 8 or later version.

- **Deprecations**

- Unqualified Gradle targets are now deprecated ([#633](https://github.com/cossacklabs/themis/pull/633)).

To build Themis for Android, run

./gradlew :android:assembleRelease

instead of

./gradlew assembleRelease

The unqualified form still works for now, but may break in future releases.

- **C++**

- Secure Cell API updates ([#588](https://github.com/cossacklabs/themis/pull/588))
Expand Down Expand Up @@ -341,14 +367,17 @@ _Code:_

</details>

- **Java**
- <a id="0.13.0-java">**Java**</a>

- JDK location is now detected automatically in most cases, you should not need to set JAVA_HOME or JDK_INCLUDE_PATH manually ([#551](https://github.com/cossacklabs/themis/pull/551)).
- JNI libraries are now available as `libthemis-jni` packages for supported Linux systems ([#552](https://github.com/cossacklabs/themis/pull/552), [#553](https://github.com/cossacklabs/themis/pull/553)).
- Fixed a NullPointerException bug in `SecureSocket` initialisation ([#557](https://github.com/cossacklabs/themis/pull/557)).
- Some Themis exceptions have been converted from checked `Exception` to _unchecked_ `RuntimeException`, relaxing requirements for `throws` specifiers ([#563](https://github.com/cossacklabs/themis/pull/563)).
- Introduced `IKey` interface with accessors to raw key data ([#564](https://github.com/cossacklabs/themis/pull/564)).
- New class `SymmetricKey` can be used to generate symmetric keys for Secure Cell ([#565](https://github.com/cossacklabs/themis/pull/565)).
- It is now possible to build desktop Java with Gradle.
Run `./gradlew :desktop:tasks` to learn more
([#633](https://github.com/cossacklabs/themis/pull/633)).

- **Node.js**

Expand Down Expand Up @@ -546,6 +575,17 @@ _Infrastructure:_
- New Makefile targets:
- `make jsthemis` builds JsThemis from source ([#618](https://github.com/cossacklabs/themis/pull/618)).

- **Breaking changes**

- <a id="0.13.0-drop-java-7">Java 7 is no longer supported</a>
([#633](https://github.com/cossacklabs/themis/pull/633)).

Updates in Gradle build infrastructure require Java 8.

Incidentally, systems that do not have Java 8 or later available are also not supported since Themis 0.13:

- Debian 8 (“jessie”)

## [0.12.0](https://github.com/cossacklabs/themis/releases/tag/0.12.0), September 27th 2019

**TL;DR:**
Expand Down
122 changes: 9 additions & 113 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,119 +1,15 @@
apply plugin: 'com.android.library'
// Common dependency repositories for all subprojects. They need to be set
// for both Gradle build itself and for the project it compiles.
allprojects {
buildscript {
repositories {
google()
jcenter()
}
}

buildscript {
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'

// Two necessary plugins for uploading .aar to bintray
// from: https://android.jlelse.eu/how-to-distribute-android-library-in-a-convenient-way-d43fb68304a7
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
}
}

repositories {
google()
jcenter()
}

dependencies {
implementation project(":boringssl")
// Instrumentation tests
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test:rules:1.1.0'
}

android {
compileSdkVersion 28
buildToolsVersion "28.0.3"

// BoringSSL requires at least API 21. Google Play as of August 2019 requires
// to target at least API 28 (but we can still support lower versions).
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
// Our tests are written in JUnit, set default runner appropriately
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

sourceSets {
main {
java.srcDirs = ['src/wrappers/themis/java']
manifest.srcFile 'src/wrappers/themis/android/AndroidManifest.xml'
jniLibs.srcDirs = ['libs']
}
androidTest.setRoot('tests/themis/wrappers/android')
androidTest.java.srcDirs = ['tests/themis/wrappers/android']
androidTest.manifest.srcFile 'tests/themis/wrappers/android/AndroidManifest.xml'

}

// Dependencies for instrumentation tests
useLibrary 'android.test.runner'
useLibrary 'android.test.base'
useLibrary 'android.test.mock'

// ensure we execute boringssl tasks first
// tasks.whenTaskAdded({Task task -> task.dependsOn('boringssl:' + task.name)})

// publishing and bitray upload tasks should not run for ':boringssl' project
tasks.whenTaskAdded { task ->
println "executing $task ..."
if (task.name != 'bintrayUpload' && task.name != 'publishProductionPublicationToMavenLocal' && task.name != 'generatePomFileForProductionPublication') {
task.dependsOn('boringssl:' + task.name)
}
}

externalNativeBuild {
ndkBuild {
path "jni/Android.mk"
}
}
}

// distribution

apply plugin: 'com.jfrog.bintray'
apply plugin: 'maven-publish'

publishing {
publications {
Production(MavenPublication) {
artifact("$buildDir/outputs/aar/projects-release.aar")
groupId 'com.cossacklabs.com'
artifactId 'themis'
version '0.12.0'
}
}
}

bintray {
// Get Bintray credential from environment variable
user = System.getenv('BINTRAY_USER') // Get bintray User
key = System.getenv('BINTRAY_KEY') // Get bintray API Key from https://bintray.com/profile/edit -> APIKey
configurations = ['archives']
pkg {
repo = 'maven'
name = 'themis'
userOrg = 'cossacklabs'
licenses = ['Apache-2.0']
desc = 'Themis is a convenient cryptographic library for data protection. It provides secure messaging with forward secrecy and secure data storage. Themis has a unified API across 12 platforms, including Python, JavaScript, iOS/macOS, and Java/Android.'
websiteUrl = "https://cossacklabs.com/themis/"
vcsUrl = 'https://github.com/cossacklabs/themis.git'
publish = true
version {
name = '0.12.0'
released = new Date()
gpg {
sign = true
passphrase = System.getenv('BINTRAY_GPG_PASSPHRASE')
}
}
}
publications = ['Production']
}
12 changes: 12 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Enable "configuration on demand" [1] to allow building Themis for
# Desktop Java without having Android SDK installed.
#
# [1]: https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:configuration_on_demand
org.gradle.configureondemand=true

# Versions of AndroidThemis and JavaThemis packages.
androidThemisVersion=0.12.0
javaThemisVersion=0.12.0

# Android Studio insists that this is set to use JUnit test runner.
android.useAndroidX=true
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
3 changes: 1 addition & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#Wed Dec 27 12:10:05 UTC 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
Loading

0 comments on commit 2359a0d

Please sign in to comment.