diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e27296e..a2e1631 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,10 +5,12 @@ on: types: [published] jobs: - - publish-ios: - name: Publish iOS native - runs-on: macOS-latest + upload: + name: Upload + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] steps: - name: Check out uses: actions/checkout@v2 @@ -20,54 +22,65 @@ jobs: path: ~/.konan key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-konan- - - name: Install automake + - name: Cached Gradle + uses: actions/cache@v2 + with: + path: ~/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Install Automake + if: matrix.os == 'macOS-latest' run: brew install automake - - name: Set up JDK 11 - uses: actions/setup-java@v1 + - name: Set up shell + if: matrix.os == 'windows-latest' + run: echo ::add-path::C:\msys64\usr\bin\ + - name: Check JVM + shell: bash + run: ./gradlew jvmTest + - name: Check Linux + if: matrix.os == 'ubuntu-latest' + shell: bash + run: ./gradlew linuxTest + - name: Check iOS + if: matrix.os == 'macOS-latest' + shell: bash + run: ./gradlew iosX64Test + - name: Check Android + if: matrix.os == 'macOS-latest' + uses: reactivecircus/android-emulator-runner@v2 with: - java-version: 11 - - name: Check - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: iosX64Test - - name: Publish - uses: eskatos/gradle-command-action@v1 + api-level: 29 + ndk: 21.3.6528147 + cmake: 3.10.2.4988404 + script: ./gradlew connectedCheck + - name: Publish Linux + if: matrix.os == 'ubuntu-latest' env: BINTRAY_USER: ${{ secrets.bintray_user }} BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: publishIosArm64PublicationToBintrayRepository publishIosX64PublicationToBintrayRepository - - publish: - name: Publish JVM & Linux native - runs-on: ubuntu-latest - steps: - - name: Check out - uses: actions/checkout@v2 - with: - submodules: 'true' - - name: Cached Konan - uses: actions/cache@v2 - with: - path: ~/.konan - key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-konan- - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - name: Check - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: check - - name: Publish - uses: eskatos/gradle-command-action@v1 + shell: bash + run: ./gradlew publishLinuxPublicationToBintrayRepository :jni:jvm:linux:publishJvmPublicationToBintrayRepository + - name: Publish Windows + if: matrix.os == 'windows-latest' env: BINTRAY_USER: ${{ secrets.bintray_user }} BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: publishAllPublicationsToBintrayRepository \ No newline at end of file + shell: bash + run: ./gradlew :jni:jvm:mingw:publishJvmPublicationToBintrayRepository + - name: Publish MacOS + if: matrix.os == 'macOS-latest' + env: + BINTRAY_USER: ${{ secrets.bintray_user }} + BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} + shell: bash + run: ./gradlew publish + - name: Discard + if: ${{ failure() || cancelled() }} + env: + BINTRAY_USER: ${{ secrets.bintray_user }} + BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} + run: ./gradlew postBintrayDiscard diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index b3513d9..772f75d 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -13,9 +13,12 @@ on: jobs: - publish-ios: - name: Publish iOS native - runs-on: macOS-latest + upload: + name: Upload + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] steps: - name: Check out uses: actions/checkout@v2 @@ -27,54 +30,90 @@ jobs: path: ~/.konan key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-konan- - - name: Install automake - run: brew install automake + - name: Cached Gradle + uses: actions/cache@v2 + with: + path: ~/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - - name: Check - uses: eskatos/gradle-command-action@v1 + - name: Install Automake + if: matrix.os == 'macOS-latest' + run: brew install automake + - name: Set up shell + if: matrix.os == 'windows-latest' + run: echo ::add-path::C:\msys64\usr\bin\ + - name: Check JVM + shell: bash + run: ./gradlew jvmTest + - name: Check Linux + if: matrix.os == 'ubuntu-latest' + shell: bash + run: ./gradlew linuxTest + - name: Check iOS + if: matrix.os == 'macOS-latest' + shell: bash + run: ./gradlew iosX64Test + - name: Check Android + if: matrix.os == 'macOS-latest' + uses: reactivecircus/android-emulator-runner@v2 with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: iosX64Test - - name: Publish - uses: eskatos/gradle-command-action@v1 + api-level: 29 + ndk: 21.3.6528147 + cmake: 3.10.2.4988404 + script: ./gradlew connectedCheck + - name: Publish Linux + if: matrix.os == 'ubuntu-latest' env: BINTRAY_USER: ${{ secrets.bintray_user }} BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: publishIosArm64PublicationToBintrayRepository publishIosX64PublicationToBintrayRepository -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} -PgitSha=${{ github.sha }} + shell: bash + run: ./gradlew publishLinuxPublicationToBintrayRepository :jni:jvm:linux:publishJvmPublicationToBintrayRepository -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} + - name: Publish Windows + if: matrix.os == 'windows-latest' + env: + BINTRAY_USER: ${{ secrets.bintray_user }} + BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} + shell: bash + run: ./gradlew :jni:jvm:mingw:publishJvmPublicationToBintrayRepository -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} + - name: Publish MacOS + if: matrix.os == 'macOS-latest' + env: + BINTRAY_USER: ${{ secrets.bintray_user }} + BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} + shell: bash + run: ./gradlew publish -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} + - name: Discard + if: ${{ failure() || cancelled() }} + env: + BINTRAY_USER: ${{ secrets.bintray_user }} + BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} + run: ./gradlew postBintrayDiscard -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} publish: - name: Publish JVM & Linux native + name: Publish + needs: upload runs-on: ubuntu-latest steps: - name: Check out uses: actions/checkout@v2 with: submodules: 'true' - - name: Cached Konan + - name: Cached Gradle uses: actions/cache@v2 with: - path: ~/.konan - key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-konan- + path: ~/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - - name: Check - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: check - name: Publish - uses: eskatos/gradle-command-action@v1 env: BINTRAY_USER: ${{ secrets.bintray_user }} BINTRAY_APIKEY: ${{ secrets.bintray_apikey }} - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - arguments: publishAllPublicationsToBintrayRepository -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} -PgitSha=${{ github.sha }} \ No newline at end of file + run: ./gradlew postBintrayPublish -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9738047..fac756a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,10 +19,12 @@ on: - '!.github/workflows/test.yml' jobs: - - linux: - name: JNI & Linux - runs-on: ubuntu-latest + check: + name: Check + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest, windows-latest] steps: - name: Check out uses: actions/checkout@v2 @@ -34,53 +36,38 @@ jobs: path: ~/.konan key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} restore-keys: ${{ runner.os }}-konan- - - name: Set up JDK 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - name: Check JNI - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - dependencies-cache-enabled: false - arguments: jvmTest -PnoCrossCompile=true - - name: Check Linux - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - dependencies-cache-enabled: false - arguments: linuxTest -PnoCrossCompile=true - - macos: - name: iOS & Android - runs-on: macos-latest - steps: - - name: Check out - uses: actions/checkout@v2 - with: - submodules: 'true' - - name: Cached Konan + - name: Cached Gradle uses: actions/cache@v2 with: - path: ~/.konan - key: ${{ runner.os }}-konan-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-konan- + path: ~/.gradle + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }} + restore-keys: ${{ runner.os }}-gradle- - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - name: Install Automake + if: matrix.os == 'macOS-latest' run: brew install automake + - name: Set up shell + if: matrix.os == 'windows-latest' + run: echo ::add-path::C:\msys64\usr\bin\ + - name: Check JVM + shell: bash + run: ./gradlew jvmTest + - name: Check Linux + if: matrix.os == 'ubuntu-latest' + shell: bash + run: ./gradlew linuxTest - name: Check iOS - uses: eskatos/gradle-command-action@v1 - with: - wrapper-cache-enabled: false # https://github.com/eskatos/gradle-command-action/issues/24 - dependencies-cache-enabled: false - arguments: iosX64Test -PnoCrossCompile=true + if: matrix.os == 'macOS-latest' + shell: bash + run: ./gradlew iosX64Test - name: Check Android + if: matrix.os == 'macOS-latest' uses: reactivecircus/android-emulator-runner@v2 with: api-level: 29 ndk: 21.3.6528147 cmake: 3.10.2.4988404 - script: ./gradlew connectedCheck -PnoCrossCompile=true + script: ./gradlew connectedCheck diff --git a/README.md b/README.md index 441046d..10ef65e 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,20 @@ JNI libraries are included for: Along this library, you **must** specify which JNI native library to use in your dependency manager: -* For desktop or server JVMs, you must add the `fr.acinq.secp256k1:secp256k1-jni-jvm` dependency -* For Android, you must add the `fr.acinq.secp256k1:secp256k1-jni-android` dependency +* **For desktop or server JVMs**, you must add the dependency: + * Either the `fr.acinq.secp256k1:secp256k1-jni-jvm` dependency which imports all supported platforms. + * Or the platform specific dependencies (note that you can add multiple as they do not conflict): + * `fr.acinq.secp256k1:secp256k1-jni-jvm-linux` for Linux + * `fr.acinq.secp256k1:secp256k1-jni-jvm-darwin` for Mac OS X + * `fr.acinq.secp256k1:secp256k1-jni-jvm-mingw` for Windows +* **For Android**, you must add the `fr.acinq.secp256k1:secp256k1-jni-android` dependency If you are using the JVM on an OS for which we don't provide JNI bindings (32 bits OS for example), you can use your own library native library by adding the `fr.acinq.secp256k1:secp256k1-jni-jvm` dependency and specifying its path with `-Dfr.acinq.secp256k1.lib.path` and optionally its name with `-Dfr.acinq.secp256k1.lib.name` (if unspecified bitcoink use the standard name for your OS i.e. libsecp256k1.so on Linux, secp256k1.dll on Windows, ...). +To compile your own JNI bindings, have a look add the `native/build.sh` and `jni/build.sh` scripts. + You can also specify the temporary directory where the library will be extracted with `-Djava.io.tmpdir` or `-Dfr.acinq.secp256k1.tmpdir` (if you want to use a different directory from `-Djava.io.tmpdir`). diff --git a/build.gradle.kts b/build.gradle.kts index 04ad366..3a4e5cb 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,10 @@ +import org.apache.http.impl.client.HttpClients +import org.apache.http.client.methods.HttpPost +import org.apache.http.entity.ContentType +import org.apache.http.entity.StringEntity +import org.apache.http.impl.auth.BasicScheme +import org.apache.http.auth.UsernamePasswordCredentials + plugins { kotlin("multiplatform") version "1.4-M3" `maven-publish` @@ -17,7 +24,7 @@ buildscript { allprojects { group = "fr.acinq.secp256k1" - version = "0.1.0-1.4-M3" + version = "0.2.0-1.4-M3" repositories { jcenter() @@ -58,7 +65,7 @@ kotlin { val nativeMain by sourceSets.creating { dependsOn(commonMain) } linuxX64("linux") { - secp256k1CInterop("linux") + secp256k1CInterop("host") // https://youtrack.jetbrains.com/issue/KT-39396 compilations["main"].kotlinOptions.freeCompilerArgs += listOf("-include-binary", "$rootDir/native/build/linux/libsecp256k1.a") compilations["main"].defaultSourceSet.dependsOn(nativeMain) @@ -107,21 +114,25 @@ allprojects { } } +val snapshotNumber: String? by project +val gitRef: String? by project +val eapBranch = gitRef?.split("/")?.last() ?: "dev" +val bintrayVersion = if (snapshotNumber != null) "${project.version}-$eapBranch-$snapshotNumber" else project.version.toString() +val bintrayRepo = if (snapshotNumber != null) "snapshots" else "libs" + +val bintrayUsername: String? = (properties["bintrayUsername"] as String?) ?: System.getenv("BINTRAY_USER") +val bintrayApiKey: String? = (properties["bintrayApiKey"] as String?) ?: System.getenv("BINTRAY_APIKEY") +val hasBintray = bintrayUsername != null && bintrayApiKey != null +if (!hasBintray) logger.warn("Skipping bintray configuration as bintrayUsername or bintrayApiKey is not defined") + allprojects { plugins.withId("maven-publish") { publishing { - val snapshotNumber: String? by project - - val bintrayUsername: String? = (properties["bintrayUsername"] as String?) ?: System.getenv("BINTRAY_USER") - val bintrayApiKey: String? = (properties["bintrayApiKey"] as String?) ?: System.getenv("BINTRAY_APIKEY") - if (bintrayUsername == null || bintrayApiKey == null) logger.warn("Skipping bintray configuration as bintrayUsername or bintrayApiKey is not defined") - else { - val btRepo = if (snapshotNumber != null) "snapshots" else "libs" - val btPublish = if (snapshotNumber != null) "1" else "0" + if (hasBintray) { repositories { maven { name = "bintray" - setUrl("https://api.bintray.com/maven/acinq/$btRepo/${rootProject.name}/;publish=$btPublish") + setUrl("https://api.bintray.com/maven/acinq/$bintrayRepo/${rootProject.name}/;publish=0") credentials { username = bintrayUsername password = bintrayApiKey @@ -130,12 +141,8 @@ allprojects { } } - val gitRef: String? by project - val gitSha: String? by project - val eapBranch = gitRef?.split("/")?.last() ?: "dev" - val eapSuffix = gitSha?.let { "-${it.substring(0, 7)}" } ?: "" publications.withType().configureEach { - if (snapshotNumber != null) version = "${project.version}-$eapBranch-$snapshotNumber$eapSuffix" + version = bintrayVersion pom { description.set("Bitcoin's secp256k1 library ported to Kotlin/Multiplatform for JVM, Android, iOS & Linux") url.set("https://github.com/ACINQ/secp256k1-kmp") @@ -155,3 +162,39 @@ allprojects { } } } + +if (hasBintray) { + val postBintrayPublish by tasks.creating { + doLast { + HttpClients.createDefault().use { client -> + val post = HttpPost("https://api.bintray.com/content/acinq/$bintrayRepo/${rootProject.name}/$bintrayVersion/publish").apply { + entity = StringEntity("{}", ContentType.APPLICATION_JSON) + addHeader(BasicScheme().authenticate(UsernamePasswordCredentials(bintrayUsername, bintrayApiKey), this, null)) + } + client.execute(post) + } + } + } + + val postBintrayDiscard by tasks.creating { + doLast { + HttpClients.createDefault().use { client -> + val post = HttpPost("https://api.bintray.com/content/acinq/$bintrayRepo/${rootProject.name}/$bintrayVersion/publish").apply { + entity = StringEntity("{ \"discard\": true }", ContentType.APPLICATION_JSON) + addHeader(BasicScheme().authenticate(UsernamePasswordCredentials(bintrayUsername, bintrayApiKey), this, null)) + } + client.execute(post) + } + } + } +} + +afterEvaluate { + tasks.withType() { + testLogging { + events("passed", "skipped", "failed", "standard_out", "standard_error") + showExceptions = true + showStackTraces = true + } + } +} diff --git a/cross-scripts/dockcross-linux-x64 b/cross-scripts/dockcross-linux-x64 deleted file mode 100755 index a34dd55..0000000 --- a/cross-scripts/dockcross-linux-x64 +++ /dev/null @@ -1,256 +0,0 @@ -#!/usr/bin/env bash - -DEFAULT_DOCKCROSS_IMAGE=dockcross/linux-x64:latest - -#------------------------------------------------------------------------------ -# Helpers -# -err() { - echo -e >&2 ERROR: $@\\n -} - -die() { - err $@ - exit 1 -} - -has() { - # eg. has command update - local kind=$1 - local name=$2 - - type -t $kind:$name | grep -q function -} - -#------------------------------------------------------------------------------ -# Command handlers -# -command:update-image() { - docker pull $FINAL_IMAGE -} - -help:update-image() { - echo Pull the latest $FINAL_IMAGE . -} - -command:update-script() { - if cmp -s <( docker run --rm $FINAL_IMAGE ) $0; then - echo $0 is up to date - else - echo -n Updating $0 '... ' - docker run --rm $FINAL_IMAGE > $0 && echo ok - fi -} - -help:update-image() { - echo Update $0 from $FINAL_IMAGE . -} - -command:update() { - command:update-image - command:update-script -} - -help:update() { - echo Pull the latest $FINAL_IMAGE, and then update $0 from that. -} - -command:help() { - if [[ $# != 0 ]]; then - if ! has command $1; then - err \"$1\" is not an dockcross command - command:help - elif ! has help $1; then - err No help found for \"$1\" - else - help:$1 - fi - else - cat >&2 < -ENDHELP - exit 1 - fi -} - -#------------------------------------------------------------------------------ -# Option processing -# -special_update_command='' -while [[ $# != 0 ]]; do - case $1 in - - --) - shift - break - ;; - - --args|-a) - ARG_ARGS="$2" - shift 2 - ;; - - --config|-c) - ARG_CONFIG="$2" - shift 2 - ;; - - --image|-i) - ARG_IMAGE="$2" - shift 2 - ;; - update|update-image|update-script) - special_update_command=$1 - break - ;; - -*) - err Unknown option \"$1\" - command:help - exit - ;; - - *) - break - ;; - - esac -done - -# The precedence for options is: -# 1. command-line arguments -# 2. environment variables -# 3. defaults - -# Source the config file if it exists -DEFAULT_DOCKCROSS_CONFIG=~/.dockcross -FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} - -[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG" - -# Set the docker image -FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} - -# Handle special update command -if [ "$special_update_command" != "" ]; then - case $special_update_command in - - update) - command:update - exit $? - ;; - - update-image) - command:update-image - exit $? - ;; - - update-script) - command:update-script - exit $? - ;; - - esac -fi - -# Set the docker run extra args (if any) -FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} - -# Bash on Ubuntu on Windows -UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "") -# MSYS, Git Bash, etc. -MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "") - -if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" ]; then - USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )") -fi - -# Change the PWD when working in Docker on Windows -if [ -n "$UBUNTU_ON_WINDOWS" ]; then - WSL_ROOT="/mnt/" - CFG_FILE=/etc/wsl.conf - if [ -f "$CFG_FILE" ]; then - CFG_CONTENT=$(cat $CFG_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g') - eval "$CFG_CONTENT" - if [ -n "$root" ]; then - WSL_ROOT=$root - fi - fi - HOST_PWD=`pwd -P` - HOST_PWD=${HOST_PWD/$WSL_ROOT//} -elif [ -n "$MSYS" ]; then - HOST_PWD=$PWD - HOST_PWD=${HOST_PWD/\//} - HOST_PWD=${HOST_PWD/\//:\/} -else - HOST_PWD=$PWD - [ -L $HOST_PWD ] && HOST_PWD=$(readlink $HOST_PWD) -fi - -# Mount Additional Volumes -if [ -z "$SSH_DIR" ]; then - SSH_DIR="$HOME/.ssh" -fi - -HOST_VOLUMES= -if [ -e "$SSH_DIR" -a -z "$MSYS" ]; then - HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh" -fi - -#------------------------------------------------------------------------------ -# Now, finally, run the command in a container -# -TTY_ARGS= -tty -s && [ -z "$MSYS" ] && TTY_ARGS=-ti -CONTAINER_NAME=dockcross_$RANDOM -docker run $TTY_ARGS --name $CONTAINER_NAME \ - -v "$HOST_PWD":/work \ - $HOST_VOLUMES \ - "${USER_IDS[@]}" \ - $FINAL_ARGS \ - $FINAL_IMAGE "$@" -run_exit_code=$? - -# Attempt to delete container -rm_output=$(docker rm -f $CONTAINER_NAME 2>&1) -rm_exit_code=$? -if [[ $rm_exit_code != 0 ]]; then - if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then - : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/ - else - echo "$rm_output" - exit $rm_exit_code - fi -fi - -exit $run_exit_code - -################################################################################ -# -# This image is not intended to be run manually. -# -# To create a dockcross helper script for the -# dockcross/linux-x64:latest image, run: -# -# docker run --rm dockcross/linux-x64:latest > dockcross-linux-x64-latest -# chmod +x dockcross-linux-x64-latest -# -# You may then wish to move the dockcross script to your PATH. -# -################################################################################ diff --git a/cross-scripts/dockcross-windows-x64 b/cross-scripts/dockcross-windows-x64 deleted file mode 100755 index ad0b67c..0000000 --- a/cross-scripts/dockcross-windows-x64 +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -DEFAULT_DOCKCROSS_IMAGE=dockcross/windows-x64 - -#------------------------------------------------------------------------------ -# Helpers -# -err() { - echo -e >&2 ERROR: $@\\n -} - -die() { - err $@ - exit 1 -} - -has() { - # eg. has command update - local kind=$1 - local name=$2 - - type -t $kind:$name | grep -q function -} - -#------------------------------------------------------------------------------ -# Command handlers -# -command:update-image() { - docker pull $FINAL_IMAGE -} - -help:update-image() { - echo Pull the latest $FINAL_IMAGE . -} - -command:update-script() { - if cmp -s <( docker run $FINAL_IMAGE ) $0; then - echo $0 is up to date - else - echo -n Updating $0 '... ' - docker run $FINAL_IMAGE > $0 && echo ok - fi -} - -help:update-image() { - echo Update $0 from $FINAL_IMAGE . -} - -command:update() { - command:update-image - command:update-script -} - -help:update() { - echo Pull the latest $FINAL_IMAGE, and then update $0 from that. -} - -command:help() { - if [[ $# != 0 ]]; then - if ! has command $1; then - err \"$1\" is not an dockcross command - command:help - elif ! has help $1; then - err No help found for \"$1\" - else - help:$1 - fi - else - cat >&2 < -ENDHELP - exit 1 - fi -} - -#------------------------------------------------------------------------------ -# Option processing -# -special_update_command='' -while [[ $# != 0 ]]; do - case $1 in - - --) - break - ;; - - --args|-a) - ARG_ARGS="$2" - shift 2 - ;; - - --config|-c) - ARG_CONFIG="$2" - shift 2 - ;; - - --image|-i) - ARG_IMAGE="$2" - shift 2 - ;; - update|update-image|update-script) - special_update_command=$1 - break - ;; - -*) - err Unknown option \"$1\" - command:help - exit - ;; - - *) - break - ;; - - esac -done - -# The precedence for options is: -# 1. command-line arguments -# 2. environment variables -# 3. defaults - -# Source the config file if it exists -DEFAULT_DOCKCROSS_CONFIG=~/.dockcross -FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} - -[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG" - -# Set the docker image -FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} - -# Handle special update command -if [ "$special_update_command" != "" ]; then - case $special_update_command in - - update) - command:update - exit $? - ;; - - update-image) - command:update-image - exit $? - ;; - - update-script) - command:update-script - exit $? - ;; - - esac -fi - -# Set the docker run extra args (if any) -FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} - -# If we are not running via boot2docker -if [ -z $DOCKER_HOST ]; then - USER_IDS=(-e BUILDER_UID="$( id -u )" -e BUILDER_GID="$( id -g )" -e BUILDER_USER="$( id -un )" -e BUILDER_GROUP="$( id -gn )") -fi - -#------------------------------------------------------------------------------ -# Now, finally, run the command in a container -# -docker run --rm \ - -v $PWD:/work \ - "${USER_IDS[@]}" \ - $FINAL_ARGS \ - $FINAL_IMAGE "$@" - -################################################################################ -# -# This image is not intended to be run manually. -# -# To create a dockcross helper script for the -# dockcross/linux-armv7 image, run: -# -# docker run --rm dockcross/linux-armv7 > dockcross-linux-armv7 -# chmod +x dockcross-linux-armv7 -# -# You may then wish to move the dockcross script to your PATH. -# -################################################################################ diff --git a/gradle.properties b/gradle.properties index 1cf1076..3feb490 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,7 @@ kotlin.incremental.multiplatform = true kotlin.parallel.tasks.in.project = true #kotlin.mpp.enableGranularSourceSetsMetadata = true kotlin.native.enableDependencyPropagation = false +kotlin.native.ignoreDisabledTargets = true # https://github.com/gradle/gradle/issues/11412 systemProp.org.gradle.internal.publish.checksums.insecure = true diff --git a/jni/build.gradle.kts b/jni/build.gradle.kts index a984915..33ac6d6 100644 --- a/jni/build.gradle.kts +++ b/jni/build.gradle.kts @@ -3,8 +3,6 @@ plugins { `maven-publish` } -val currentOs = org.gradle.internal.os.OperatingSystem.current() - kotlin { explicitApi() } @@ -14,7 +12,7 @@ dependencies { implementation(kotlin("stdlib-jdk8")) } -val generateJniHeaders by tasks.creating(JavaCompile::class) { +val generateHeaders by tasks.creating(JavaCompile::class) { group = "build" classpath = sourceSets["main"].compileClasspath destinationDir = file("${buildDir}/generated/jni") @@ -29,52 +27,6 @@ val generateJniHeaders by tasks.creating(JavaCompile::class) { } } -sealed class Cross { - abstract fun cmd(target: String, project: Project): List - class DockCross(val cross: String) : Cross() { - override fun cmd(target: String, project: Project): List = listOf("${project.rootDir}/cross-scripts/dockcross-$cross", "bash", "-c", "CROSS=1 TARGET=$target jni/build.sh") - } - class MultiArch(val crossTriple: String) : Cross() { - override fun cmd(target: String, project: Project): List { - val uid = Runtime.getRuntime().exec("id -u").inputStream.use { it.reader().readText() }.trim().toInt() - return listOf( - "docker", "run", "--rm", "-v", "${project.rootDir.absolutePath}:/workdir", - "-e", "CROSS_TRIPLE=$crossTriple", "-e", "TARGET=$target", "-e", "TO_UID=$uid", "-e", "CROSS=1", - "multiarch/crossbuild", "jni/build.sh" - ) - } - } -} - -val buildNativeJni by tasks.creating { - group = "build" -} -val noCrossCompile: String? by project -fun creatingBuildNativeJni(target: String, cross: Cross?) = tasks.creating(Exec::class) { - group = "build" - dependsOn(generateJniHeaders) - dependsOn(":native:buildSecp256k1${target.capitalize()}") - buildNativeJni.dependsOn(this) - - if (noCrossCompile == "true") onlyIf { cross == null } - - inputs.files(projectDir.resolve("build.sh")) - outputs.dir(buildDir.resolve("build/cmake/$target")) - - workingDir = rootDir - environment("TARGET", target) - commandLine((cross?.cmd(target, project) ?: emptyList()) + "jni/build.sh") -} -val buildNativeJniDarwin by creatingBuildNativeJni("darwin", if (currentOs.isMacOsX) null else Cross.MultiArch("x86_64-apple-darwin")) -val buildNativeJniLinux by creatingBuildNativeJni("linux", if (currentOs.isLinux) null else Cross.DockCross("linux-x64")) -val buildNativeJniMingw by creatingBuildNativeJni("mingw", if (currentOs.isWindows) null else Cross.DockCross("windows-x64")) - -afterEvaluate { - tasks["clean"].doLast { - delete(buildDir.resolve("build/cmake")) - } -} - publishing { publications { create("jvm") { diff --git a/jni/c/headers/mingw/jni_md.h b/jni/c/headers/mingw/jni_md.h index 783d597..305eb9e 100644 --- a/jni/c/headers/mingw/jni_md.h +++ b/jni/c/headers/mingw/jni_md.h @@ -12,6 +12,8 @@ #define JNIIMPORT __declspec(dllimport) #define JNICALL __stdcall +#include + typedef long jint; typedef int64_t jlong; typedef signed char jbyte; diff --git a/jni/jvm/all/build.gradle.kts b/jni/jvm/all/build.gradle.kts new file mode 100644 index 0000000..8aeb8a5 --- /dev/null +++ b/jni/jvm/all/build.gradle.kts @@ -0,0 +1,20 @@ +plugins { + `java-library` +// `maven-publish` + id("ru.vyarus.pom") version "2.1.0" +} + +dependencies { + api(project(":jni:jvm:darwin")) + api(project(":jni:jvm:linux")) + api(project(":jni:jvm:mingw")) +} + +publishing { + publications { + create("jvm") { + artifactId = "secp256k1-jni-jvm" + from(components["java"]) + } + } +} diff --git a/jni/jvm/build.gradle.kts b/jni/jvm/build.gradle.kts index 127098c..0379156 100644 --- a/jni/jvm/build.gradle.kts +++ b/jni/jvm/build.gradle.kts @@ -3,8 +3,27 @@ plugins { `maven-publish` } -kotlin { - explicitApi() +val currentOs = org.gradle.internal.os.OperatingSystem.current() +val bash = if (currentOs.isWindows) "bash.exe" else "bash" + +val buildNativeHost by tasks.creating(Exec::class) { + group = "build" + dependsOn(":jni:generateHeaders") + dependsOn(":native:buildSecp256k1Host") + + val target = when { + currentOs.isLinux -> "linux" + currentOs.isMacOsX -> "darwin" + currentOs.isWindows -> "mingw" + else -> error("Unsupported OS $currentOs") + } + + inputs.files(projectDir.resolve("build.sh")) + outputs.dir(buildDir.resolve(target)) + + workingDir = projectDir + environment("TARGET", target) + commandLine(bash, "build.sh") } dependencies { @@ -12,26 +31,17 @@ dependencies { implementation(kotlin("stdlib-jdk8")) } -val copyJni by tasks.creating(Sync::class) { - dependsOn(":jni:buildNativeJni") - from(rootDir.resolve("jni/build/jni/linux/libsecp256k1-jni.so")) { rename { "libsecp256k1-jni-linux-x86_64.so" } } - from(rootDir.resolve("jni/build/jni/darwin/libsecp256k1-jni.dylib")) { rename { "libsecp256k1-jni-darwin-x86_64.dylib" } } - from(rootDir.resolve("jni/build/jni/mingw/secp256k1-jni.dll")) { rename { "secp256k1-jni-mingw-x86_64.dll" } } - into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native")) -} - -(tasks["processResources"] as ProcessResources).apply { - dependsOn("copyJni") - from(buildDir.resolve("jniResources")) -} - -java.withSourcesJar() - publishing { publications { create("jvm") { - artifactId = "secp256k1-jni-jvm" + artifactId = "secp256k1-jni-jvm-extract" from(components["java"]) } } } + +afterEvaluate { + tasks["clean"].doLast { + delete("$buildDir/build/cmake") + } +} diff --git a/jni/build.sh b/jni/jvm/build.sh similarity index 62% rename from jni/build.sh rename to jni/jvm/build.sh index 1ecf546..c31b6bb 100755 --- a/jni/build.sh +++ b/jni/jvm/build.sh @@ -14,7 +14,6 @@ JNI_HEADERS=$TARGET if [ "$TARGET" == "linux" ]; then OUTFILE=libsecp256k1-jni.so - [ "$CROSS" == "1" ] && sudo apt -y install libgmp-dev ADD_LIB=-lgmp CC_OPTS="-fPIC" elif [ "$TARGET" == "darwin" ]; then @@ -22,14 +21,12 @@ elif [ "$TARGET" == "darwin" ]; then ADD_LIB=-lgmp elif [ "$TARGET" == "mingw" ]; then OUTFILE=secp256k1-jni.dll - CC=/usr/src/mxe/usr/bin/x86_64-w64-mingw32.static-gcc - JNI_HEADERS=linux - CC_OPTS="-fPIC" + CC=x86_64-w64-mingw32-gcc fi mkdir -p build/jni/$TARGET -$CC -shared $CC_OPTS -o build/jni/$TARGET/$OUTFILE c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c -Ic/headers/ -Ic/headers/java -Ic/headers/$JNI_HEADERS/ -I../native/secp256k1/ -lsecp256k1 -L../native/build/$TARGET/ $ADD_LIB +$CC -shared $CC_OPTS -o build/$TARGET/$OUTFILE ../c/src/fr_acinq_secp256k1_Secp256k1CFunctions.c -I../c/headers/ -I../c/headers/java -I../c/headers/$JNI_HEADERS/ -I../../native/secp256k1/ -lsecp256k1 -L../../native/build/$TARGET/ $ADD_LIB [[ ! -z "$TO_UID" ]] && chown -R $TO_UID:$TO_UID . diff --git a/jni/jvm/darwin/build.gradle.kts b/jni/jvm/darwin/build.gradle.kts new file mode 100644 index 0000000..dc92282 --- /dev/null +++ b/jni/jvm/darwin/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + implementation(project(":jni:jvm")) +} + +val copyJni by tasks.creating(Sync::class) { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX } + dependsOn(":jni:jvm:buildNativeHost") + from(rootDir.resolve("jni/jvm/build/darwin/libsecp256k1-jni.dylib")) + into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/darwin-x86_64")) +} + +(tasks["processResources"] as ProcessResources).apply { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isMacOsX } + dependsOn(copyJni) + from(buildDir.resolve("jniResources")) +} + +publishing { + publications { + val pub = create("jvm") { + artifactId = "secp256k1-jni-jvm-darwin" + from(components["java"]) + } + if (!org.gradle.internal.os.OperatingSystem.current().isMacOsX) { + tasks.withType().all { onlyIf { publication != pub } } + } + } +} diff --git a/jni/jvm/linux/build.gradle.kts b/jni/jvm/linux/build.gradle.kts new file mode 100644 index 0000000..a332df8 --- /dev/null +++ b/jni/jvm/linux/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + implementation(project(":jni:jvm")) +} + +val copyJni by tasks.creating(Sync::class) { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isLinux } + dependsOn(":jni:jvm:buildNativeHost") + from(rootDir.resolve("jni/jvm/build/linux/libsecp256k1-jni.so")) + into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/linux-x86_64")) +} + +(tasks["processResources"] as ProcessResources).apply { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isLinux } + dependsOn(copyJni) + from(buildDir.resolve("jniResources")) +} + +publishing { + publications { + val pub = create("jvm") { + artifactId = "secp256k1-jni-jvm-linux" + from(components["java"]) + } + if (!org.gradle.internal.os.OperatingSystem.current().isLinux) { + tasks.withType().all { onlyIf { publication != pub } } + } + } +} diff --git a/jni/jvm/mingw/build.gradle.kts b/jni/jvm/mingw/build.gradle.kts new file mode 100644 index 0000000..b48b65b --- /dev/null +++ b/jni/jvm/mingw/build.gradle.kts @@ -0,0 +1,33 @@ +plugins { + kotlin("jvm") + `maven-publish` +} + +dependencies { + implementation(project(":jni:jvm")) +} + +val copyJni by tasks.creating(Sync::class) { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isWindows } + dependsOn(":jni:jvm:buildNativeHost") + from(rootDir.resolve("jni/jvm/build/mingw/secp256k1-jni.dll")) + into(buildDir.resolve("jniResources/fr/acinq/secp256k1/jni/native/mingw-x86_64")) +} + +(tasks["processResources"] as ProcessResources).apply { + onlyIf { org.gradle.internal.os.OperatingSystem.current().isWindows } + dependsOn(copyJni) + from(buildDir.resolve("jniResources")) +} + +publishing { + publications { + val pub = create("jvm") { + artifactId = "secp256k1-jni-jvm-mingw" + from(components["java"]) + } + if (!org.gradle.internal.os.OperatingSystem.current().isWindows) { + tasks.withType().all { onlyIf { publication != pub } } + } + } +} diff --git a/jni/jvm/src/main/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt b/jni/jvm/src/main/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt index e9e4efd..4758ceb 100644 --- a/jni/jvm/src/main/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt +++ b/jni/jvm/src/main/kotlin/fr/acinq/secp256k1/jni/NativeSecp256k1Loader.kt @@ -187,7 +187,7 @@ public object NativeSecp256k1Loader { // Try loading library from fr.acinq.secp256k1.lib.path library path */ val libraryPath = System.getProperty("fr.acinq.secp256k1.lib.path") - val libraryName = System.getProperty("fr.acinq.secp256k1.lib.name") ?: System.mapLibraryName("secp256k1-jni-${OSInfo.nativeSuffix}") + val libraryName = System.getProperty("fr.acinq.secp256k1.lib.name") ?: System.mapLibraryName("secp256k1-jni") if (libraryPath != null) { if (loadNativeLibrary(libraryPath, libraryName)) { extracted = true @@ -197,7 +197,7 @@ public object NativeSecp256k1Loader { // Load the os-dependent library from the jar file val packagePath = NativeSecp256k1Loader::class.java.getPackage().name.replace("\\.".toRegex(), "/") - val embeddedLibraryPath = "/$packagePath/native" + val embeddedLibraryPath = "/$packagePath/native/${OSInfo.nativeSuffix}" val hasNativeLib = NativeSecp256k1Loader::class.java.getResource("$embeddedLibraryPath/$libraryName") != null if (!hasNativeLib) { error("No native library found: at $embeddedLibraryPath/$libraryName") diff --git a/native/build.gradle.kts b/native/build.gradle.kts index 09968d5..63e8ac4 100644 --- a/native/build.gradle.kts +++ b/native/build.gradle.kts @@ -1,47 +1,28 @@ evaluationDependsOn(":jni:android") val currentOs = org.gradle.internal.os.OperatingSystem.current() +val bash = if (currentOs.isWindows) "bash.exe" else "bash" val buildSecp256k1 by tasks.creating { group = "build" } -sealed class Cross { - abstract fun cmd(target: String, project: Project): List - class DockCross(val cross: String) : Cross() { - override fun cmd(target: String, project: Project): List = listOf("${project.rootDir}/cross-scripts/dockcross-$cross", "bash", "-c", "CROSS=1 TARGET=$target ./build.sh") - } - class MultiArch(val crossTriple: String) : Cross() { - override fun cmd(target: String, project: Project): List { - val uid = Runtime.getRuntime().exec("id -u").inputStream.use { it.reader().readText() }.trim().toInt() - return listOf( - "docker", "run", "--rm", "-v", "${project.projectDir.absolutePath}:/workdir", - "-e", "CROSS_TRIPLE=$crossTriple", "-e", "TARGET=$target", "-e", "TO_UID=$uid", "-e", "CROSS=1", - "multiarch/crossbuild", "./build.sh" - ) - } - } -} - -val buildSecp256k1Jvm by tasks.creating { +val buildSecp256k1Host by tasks.creating(Exec::class) { group = "build" buildSecp256k1.dependsOn(this) -} -val noCrossCompile: String? by project -fun creatingBuildSecp256k1(target: String, cross: Cross?) = tasks.creating(Exec::class) { - group = "build" - buildSecp256k1Jvm.dependsOn(this) - if (noCrossCompile == "true") onlyIf { cross == null } + val target = when { + currentOs.isLinux -> "linux" + currentOs.isMacOsX -> "darwin" + currentOs.isWindows -> "mingw" + else -> error("UnsupportedmOS $currentOs") + } inputs.files(projectDir.resolve("build.sh")) outputs.dir(projectDir.resolve("build/$target")) workingDir = projectDir environment("TARGET", target) - commandLine((cross?.cmd(target, project) ?: emptyList()) + "./build.sh") + commandLine(bash, "build.sh") } -val buildSecp256k1Darwin by creatingBuildSecp256k1("darwin", if (currentOs.isMacOsX) null else Cross.MultiArch("x86_64-apple-darwin")) -val buildSecp256k1Linux by creatingBuildSecp256k1("linux", if (currentOs.isLinux) null else Cross.DockCross("linux-x64")) -val buildSecp256k1Mingw by creatingBuildSecp256k1("mingw", if (currentOs.isWindows) null else Cross.DockCross("windows-x64")) val buildSecp256k1Ios by tasks.creating(Exec::class) { group = "build" @@ -53,7 +34,7 @@ val buildSecp256k1Ios by tasks.creating(Exec::class) { outputs.dir(projectDir.resolve("build/ios")) workingDir = projectDir - commandLine("./build-ios.sh") + commandLine(bash, "build-ios.sh") } val buildSecp256k1Android by tasks.creating { @@ -78,7 +59,7 @@ fun creatingBuildSecp256k1Android(arch: String) = tasks.creating(Exec::class) { environment("TOOLCHAIN", toolchain) environment("ARCH", arch) environment("ANDROID_NDK", (project(":jni:android").extensions["android"] as com.android.build.gradle.LibraryExtension).ndkDirectory) - commandLine("./build-android.sh") + commandLine(bash, "build-android.sh") } val buildSecp256k1AndroidX86_64 by creatingBuildSecp256k1Android("x86_64") val buildSecp256k1AndroidX86 by creatingBuildSecp256k1Android("x86") diff --git a/settings.gradle.kts b/settings.gradle.kts index 3175a7e..f814864 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,12 +6,16 @@ pluginManagement { jcenter() } } -rootProject.name = "secp256k1-kmp" +rootProject.name = "secp256k1" include( ":native", ":jni", ":jni:android", ":jni:jvm", + ":jni:jvm:darwin", + ":jni:jvm:linux", + ":jni:jvm:mingw", + ":jni:jvm:all", ":tests" ) \ No newline at end of file diff --git a/tests/build.gradle.kts b/tests/build.gradle.kts index 82225a6..89c506a 100644 --- a/tests/build.gradle.kts +++ b/tests/build.gradle.kts @@ -24,7 +24,7 @@ kotlin { } compilations["main"].dependencies { implementation(kotlin("stdlib-jdk8")) - implementation(project(":jni:jvm")) + implementation(project(":jni:jvm:all")) } compilations["test"].dependencies { implementation(kotlin("test-junit"))