Native jni build (#5)

* Each native library is in its own jar. Got rid of cross compilation. The project is `secp256k1` and not `secp256k1-kmp`.

* Updated CI to use all 3 OS VMs

Co-authored-by: Salomon BRYS <salomon@kodein.net>
This commit is contained in:
Salomon BRYS 2020-07-09 15:54:34 +03:00 committed by GitHub
parent c5dbc42496
commit 6c850eb2c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 393 additions and 694 deletions

View File

@ -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
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

View File

@ -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 }}
run: ./gradlew postBintrayPublish -PsnapshotNumber=${{ github.run_number }} -PgitRef=${{ github.ref }}

View File

@ -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

View File

@ -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`).

View File

@ -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<MavenPublication>().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<AbstractTestTask>() {
testLogging {
events("passed", "skipped", "failed", "standard_out", "standard_error")
showExceptions = true
showStackTraces = true
}
}
}

View File

@ -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
Usage: dockcross [options] [--] command [args]
By default, run the given *command* in an dockcross Docker container.
The *options* can be one of:
--args|-a Extra args to the *docker run* command
--image|-i Docker cross-compiler image to use
--config|-c Bash script to source before running this script
Additionally, there are special update commands:
update-image
update-script
update
For update command help use: $0 help <command>
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.
#
################################################################################

View File

@ -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
Usage: dockcross [options] [--] command [args]
By default, run the given *command* in an dockcross Docker container.
The *options* can be one of:
--args|-a Extra args to the *docker run* command
--image|-i Docker cross-compiler image to use
--config|-c Bash script to source before running this script
Additionally, there are special update commands:
update-image
update-script
update
For update command help use: $0 help <command>
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.
#
################################################################################

View File

@ -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

View File

@ -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<String>
class DockCross(val cross: String) : Cross() {
override fun cmd(target: String, project: Project): List<String> = 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<String> {
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<MavenPublication>("jvm") {

View File

@ -12,6 +12,8 @@
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
#include <stdint.h>
typedef long jint;
typedef int64_t jlong;
typedef signed char jbyte;

View File

@ -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<MavenPublication>("jvm") {
artifactId = "secp256k1-jni-jvm"
from(components["java"])
}
}
}

View File

@ -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<MavenPublication>("jvm") {
artifactId = "secp256k1-jni-jvm"
artifactId = "secp256k1-jni-jvm-extract"
from(components["java"])
}
}
}
afterEvaluate {
tasks["clean"].doLast {
delete("$buildDir/build/cmake")
}
}

View File

@ -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 .

View File

@ -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<MavenPublication>("jvm") {
artifactId = "secp256k1-jni-jvm-darwin"
from(components["java"])
}
if (!org.gradle.internal.os.OperatingSystem.current().isMacOsX) {
tasks.withType<AbstractPublishToMaven>().all { onlyIf { publication != pub } }
}
}
}

View File

@ -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<MavenPublication>("jvm") {
artifactId = "secp256k1-jni-jvm-linux"
from(components["java"])
}
if (!org.gradle.internal.os.OperatingSystem.current().isLinux) {
tasks.withType<AbstractPublishToMaven>().all { onlyIf { publication != pub } }
}
}
}

View File

@ -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<MavenPublication>("jvm") {
artifactId = "secp256k1-jni-jvm-mingw"
from(components["java"])
}
if (!org.gradle.internal.os.OperatingSystem.current().isWindows) {
tasks.withType<AbstractPublishToMaven>().all { onlyIf { publication != pub } }
}
}
}

View File

@ -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")

View File

@ -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<String>
class DockCross(val cross: String) : Cross() {
override fun cmd(target: String, project: Project): List<String> = 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<String> {
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")

View File

@ -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"
)

View File

@ -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"))