Convert Gradle script plugin for generating UniFfi bindings into a composite build.

This commit is contained in:
Kirill Zhukov 2022-07-29 15:23:23 -07:00
parent d00813e1d6
commit 989b7339a0
No known key found for this signature in database
GPG Key ID: D9D0E1C70935D5E0
11 changed files with 318 additions and 261 deletions

View File

@ -1,8 +0,0 @@
plugins {
`kotlin-dsl`
// id("org.gradle.kotlin.kotlin-dsl") version "2.2.0"
}
repositories {
mavenCentral()
}

View File

@ -1,153 +0,0 @@
package org.bitcoindevkit.plugins
import org.gradle.kotlin.dsl.register
val llvmArchPath = when (operatingSystem) {
OS.MAC -> "darwin-x86_64"
OS.LINUX -> "linux-x86_64"
OS.OTHER -> throw Error("Cannot build Android library from current architecture")
}
// arm64-v8a is the most popular hardware architecture for Android
val buildAndroidAarch64Binary by tasks.register<Exec>("buildAndroidAarch64Binary") {
workingDir("${project.projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> = mutableListOf("build", "--release", "--target", "aarch64-linux-android")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER", "aarch64-linux-android21-clang"),
Pair("CC", "aarch64-linux-android21-clang")
)
doLast {
println("Native library for bdk-android on aarch64 built successfully")
}
}
// the x86_64 version of the library is mostly used by emulators
val buildAndroidX86_64Binary by tasks.register<Exec>("buildAndroidX86_64Binary") {
workingDir("${project.projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> = mutableListOf("build", "--release", "--target", "x86_64-linux-android")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER", "x86_64-linux-android21-clang"),
Pair("CC", "x86_64-linux-android21-clang")
)
doLast {
println("Native library for bdk-android on x86_64 built successfully")
}
}
// armeabi-v7a version of the library for older 32-bit Android hardware
val buildAndroidArmv7Binary by tasks.register<Exec>("buildAndroidArmv7Binary") {
workingDir("${project.projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> = mutableListOf("build", "--release", "--target", "armv7-linux-androideabi")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH", "${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER", "armv7a-linux-androideabi21-clang"),
Pair("CC", "armv7a-linux-androideabi21-clang")
)
doLast {
println("Native library for bdk-android on armv7 built successfully")
}
}
// move the native libs build by cargo from bdk-ffi/target/<architecture>/release/
// to their place in the bdk-android library
// the task only copies the available binaries built using the buildAndroid<architecture>Binary tasks
val moveNativeAndroidLibs by tasks.register<Copy>("moveNativeAndroidLibs") {
dependsOn(buildAndroidAarch64Binary)
into("${project.projectDir}/../android/src/main/jniLibs/")
into("arm64-v8a") {
from("${project.projectDir}/../bdk-ffi/target/aarch64-linux-android/release/libbdkffi.so")
}
into("x86_64") {
from("${project.projectDir}/../bdk-ffi/target/x86_64-linux-android/release/libbdkffi.so")
}
into("armeabi-v7a") {
from("${project.projectDir}/../bdk-ffi/target/armv7-linux-androideabi/release/libbdkffi.so")
}
doLast {
println("Native binaries for Android moved to ./android/src/main/jniLibs/")
}
}
// generate the bindings using the bdk-ffi-bindgen tool located in the bdk-ffi submodule
val generateAndroidBindings by tasks.register<Exec>("generateAndroidBindings") {
dependsOn(moveNativeAndroidLibs)
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
args("run", "--package", "bdk-ffi-bindgen", "--", "--language", "kotlin", "--out-dir", "../android/src/main/kotlin")
doLast {
println("Android bindings file successfully created")
}
}
// create an aggregate task which will run the required tasks to build the Android libs in order
// the task will also appear in the printout of the ./gradlew tasks task with group and description
tasks.register("buildAndroidLib") {
group = "Bitcoindevkit"
description = "Aggregate task to build Android library"
dependsOn(
buildAndroidAarch64Binary,
buildAndroidX86_64Binary,
buildAndroidArmv7Binary,
moveNativeAndroidLibs,
generateAndroidBindings
)
}

View File

@ -1,100 +0,0 @@
package org.bitcoindevkit.plugins
// register a task called buildJvmBinaries which will run something like
// cargo build --release --target aarch64-apple-darwin
val buildJvmBinaries by tasks.register<DefaultTask>("buildJvmBinaries") {
if (operatingSystem == OS.MAC) {
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "x86_64-apple-darwin")
args(cargoArgs)
}
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "aarch64-apple-darwin")
args(cargoArgs)
}
} else if(operatingSystem == OS.LINUX) {
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "x86_64-unknown-linux-gnu")
args(cargoArgs)
}
}
}
// move the native libs build by cargo from bdk-ffi/target/.../release/
// to their place in the bdk-jvm library
val moveNativeJvmLibs by tasks.register<DefaultTask>("moveNativeJvmLibs") {
// dependsOn(buildJvmBinaryX86_64MacOS, buildJvmBinaryAarch64MacOS, buildJvmBinaryLinux)
dependsOn(buildJvmBinaries)
data class CopyMetadata(val targetDir: String, val resDir: String, val ext: String)
val libsToCopy: MutableList<CopyMetadata> = mutableListOf()
if (operatingSystem == OS.MAC) {
libsToCopy.add(
CopyMetadata(
targetDir = "aarch64-apple-darwin",
resDir = "darwin-aarch64",
ext = "dylib"
)
)
libsToCopy.add(
CopyMetadata(
targetDir = "x86_64-apple-darwin",
resDir = "darwin-x86-64",
ext = "dylib"
)
)
} else if (operatingSystem == OS.LINUX) {
libsToCopy.add(
CopyMetadata(
targetDir = "x86_64-unknown-linux-gnu",
resDir = "linux-x86-64",
ext = "so"
)
)
}
libsToCopy.forEach {
doFirst {
copy {
with(it) {
from("${project.projectDir}/../bdk-ffi/target/${this.targetDir}/release/libbdkffi.${this.ext}")
into("${project.projectDir}/../jvm/src/main/resources/${this.resDir}/")
}
}
}
}
}
// generate the bindings using the bdk-ffi-bindgen tool created in the bdk-ffi submodule
val generateJvmBindings by tasks.register<Exec>("generateJvmBindings") {
dependsOn(moveNativeJvmLibs)
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
args("run", "--package", "bdk-ffi-bindgen", "--", "--language", "kotlin", "--out-dir", "../jvm/src/main/kotlin")
doLast {
println("JVM bindings file successfully created")
}
}
// we need an aggregate task which will run the 3 required tasks to build the JVM libs in order
// the task will also appear in the printout of the ./gradlew tasks task with a group and description
tasks.register("buildJvmLib") {
group = "Bitcoindevkit"
description = "Aggregate task to build JVM library"
dependsOn(
buildJvmBinaries,
moveNativeJvmLibs,
generateJvmBindings
)
}

17
plugins/build.gradle.kts Normal file
View File

@ -0,0 +1,17 @@
plugins {
id("java-gradle-plugin")
`kotlin-dsl`
}
gradlePlugin {
plugins {
create("uniFfiJvmBindings") {
id = "org.bitcoindevkit.plugins.generate-jvm-bindings"
implementationClass = "org.bitcoindevkit.plugins.UniFfiJvmPlugin"
}
create("uniFfiAndroidBindings") {
id = "org.bitcoindevkit.plugins.generate-android-bindings"
implementationClass = "org.bitcoindevkit.plugins.UniFfiAndroidPlugin"
}
}
}

View File

@ -0,0 +1,8 @@
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
}
}
include(":plugins")

View File

@ -0,0 +1,178 @@
package org.bitcoindevkit.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Exec
import org.gradle.kotlin.dsl.environment
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register
internal class UniFfiAndroidPlugin : Plugin<Project> {
override fun apply(target: Project): Unit = target.run {
val llvmArchPath = when (operatingSystem) {
OS.MAC -> "darwin-x86_64"
OS.LINUX -> "linux-x86_64"
OS.OTHER -> throw Error("Cannot build Android library from current architecture")
}
// arm64-v8a is the most popular hardware architecture for Android
val buildAndroidAarch64Binary by tasks.register<Exec>("buildAndroidAarch64Binary") {
workingDir("${projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> =
mutableListOf("build", "--release", "--target", "aarch64-linux-android")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH",
"${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER", "aarch64-linux-android21-clang"),
Pair("CC", "aarch64-linux-android21-clang")
)
doLast {
println("Native library for bdk-android on aarch64 built successfully")
}
}
// the x86_64 version of the library is mostly used by emulators
val buildAndroidX86_64Binary by tasks.register<Exec>("buildAndroidX86_64Binary") {
workingDir("${project.projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> =
mutableListOf("build", "--release", "--target", "x86_64-linux-android")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH",
"${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER", "x86_64-linux-android21-clang"),
Pair("CC", "x86_64-linux-android21-clang")
)
doLast {
println("Native library for bdk-android on x86_64 built successfully")
}
}
// armeabi-v7a version of the library for older 32-bit Android hardware
val buildAndroidArmv7Binary by tasks.register<Exec>("buildAndroidArmv7Binary") {
workingDir("${project.projectDir}/../bdk-ffi")
val cargoArgs: MutableList<String> =
mutableListOf("build", "--release", "--target", "armv7-linux-androideabi")
executable("cargo")
args(cargoArgs)
// if ANDROID_NDK_ROOT is not set then set it to github actions default
if (System.getenv("ANDROID_NDK_ROOT") == null) {
environment(
Pair("ANDROID_NDK_ROOT", "${System.getenv("ANDROID_SDK_ROOT")}/ndk-bundle")
)
}
environment(
// add build toolchain to PATH
Pair("PATH",
"${System.getenv("PATH")}:${System.getenv("ANDROID_NDK_ROOT")}/toolchains/llvm/prebuilt/$llvmArchPath/bin"),
Pair("CFLAGS", "-D__ANDROID_API__=21"),
Pair("CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER",
"armv7a-linux-androideabi21-clang"),
Pair("CC", "armv7a-linux-androideabi21-clang")
)
doLast {
println("Native library for bdk-android on armv7 built successfully")
}
}
// move the native libs build by cargo from bdk-ffi/target/<architecture>/release/
// to their place in the bdk-android library
// the task only copies the available binaries built using the buildAndroid<architecture>Binary tasks
val moveNativeAndroidLibs by tasks.register<Copy>("moveNativeAndroidLibs") {
dependsOn(buildAndroidAarch64Binary)
into("${project.projectDir}/../android/src/main/jniLibs/")
into("arm64-v8a") {
from("${project.projectDir}/../bdk-ffi/target/aarch64-linux-android/release/libbdkffi.so")
}
into("x86_64") {
from("${project.projectDir}/../bdk-ffi/target/x86_64-linux-android/release/libbdkffi.so")
}
into("armeabi-v7a") {
from("${project.projectDir}/../bdk-ffi/target/armv7-linux-androideabi/release/libbdkffi.so")
}
doLast {
println("Native binaries for Android moved to ./android/src/main/jniLibs/")
}
}
// generate the bindings using the bdk-ffi-bindgen tool located in the bdk-ffi submodule
val generateAndroidBindings by tasks.register<Exec>("generateAndroidBindings") {
dependsOn(moveNativeAndroidLibs)
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
args("run",
"--package",
"bdk-ffi-bindgen",
"--",
"--language",
"kotlin",
"--out-dir",
"../android/src/main/kotlin")
doLast {
println("Android bindings file successfully created")
}
}
// create an aggregate task which will run the required tasks to build the Android libs in order
// the task will also appear in the printout of the ./gradlew tasks task with group and description
tasks.register("buildAndroidLib") {
group = "Bitcoindevkit"
description = "Aggregate task to build Android library"
dependsOn(
buildAndroidAarch64Binary,
buildAndroidX86_64Binary,
buildAndroidArmv7Binary,
moveNativeAndroidLibs,
generateAndroidBindings
)
}
}
}

View File

@ -0,0 +1,114 @@
package org.bitcoindevkit.plugins
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.Exec
import org.gradle.kotlin.dsl.getValue
import org.gradle.kotlin.dsl.provideDelegate
import org.gradle.kotlin.dsl.register
internal class UniFfiJvmPlugin : Plugin<Project> {
override fun apply(target: Project): Unit = target.run {
// register a task called buildJvmBinaries which will run something like
// cargo build --release --target aarch64-apple-darwin
val buildJvmBinaries by tasks.register<DefaultTask>("buildJvmBinaries") {
if (operatingSystem == OS.MAC) {
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "x86_64-apple-darwin")
args(cargoArgs)
}
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "aarch64-apple-darwin")
args(cargoArgs)
}
} else if(operatingSystem == OS.LINUX) {
exec {
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
val cargoArgs: List<String> = listOf("build", "--release", "--target", "x86_64-unknown-linux-gnu")
args(cargoArgs)
}
}
}
// move the native libs build by cargo from bdk-ffi/target/.../release/
// to their place in the bdk-jvm library
val moveNativeJvmLibs by tasks.register<DefaultTask>("moveNativeJvmLibs") {
// dependsOn(buildJvmBinaryX86_64MacOS, buildJvmBinaryAarch64MacOS, buildJvmBinaryLinux)
dependsOn(buildJvmBinaries)
data class CopyMetadata(val targetDir: String, val resDir: String, val ext: String)
val libsToCopy: MutableList<CopyMetadata> = mutableListOf()
if (operatingSystem == OS.MAC) {
libsToCopy.add(
CopyMetadata(
targetDir = "aarch64-apple-darwin",
resDir = "darwin-aarch64",
ext = "dylib"
)
)
libsToCopy.add(
CopyMetadata(
targetDir = "x86_64-apple-darwin",
resDir = "darwin-x86-64",
ext = "dylib"
)
)
} else if (operatingSystem == OS.LINUX) {
libsToCopy.add(
CopyMetadata(
targetDir = "x86_64-unknown-linux-gnu",
resDir = "linux-x86-64",
ext = "so"
)
)
}
libsToCopy.forEach {
doFirst {
copy {
with(it) {
from("${project.projectDir}/../bdk-ffi/target/${this.targetDir}/release/libbdkffi.${this.ext}")
into("${project.projectDir}/../jvm/src/main/resources/${this.resDir}/")
}
}
}
}
}
// generate the bindings using the bdk-ffi-bindgen tool created in the bdk-ffi submodule
val generateJvmBindings by tasks.register<Exec>("generateJvmBindings") {
dependsOn(moveNativeJvmLibs)
workingDir("${project.projectDir}/../bdk-ffi")
executable("cargo")
args("run", "--package", "bdk-ffi-bindgen", "--", "--language", "kotlin", "--out-dir", "../jvm/src/main/kotlin")
doLast {
println("JVM bindings file successfully created")
}
}
// we need an aggregate task which will run the 3 required tasks to build the JVM libs in order
// the task will also appear in the printout of the ./gradlew tasks task with a group and description
tasks.register("buildJvmLib") {
group = "Bitcoindevkit"
description = "Aggregate task to build JVM library"
dependsOn(
buildJvmBinaries,
moveNativeJvmLibs,
generateJvmBindings
)
}
}
}

View File

@ -1,3 +1,4 @@
rootProject.name = "bdk-kotlin"
include(":jvm", ":android")
includeBuild("plugins")