Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions jni-wrappers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
scripts
**/build
!privmx-libs/**/.gitkeep
!privmx-libs/**/.gitignore
privmx-libs
51 changes: 51 additions & 0 deletions jni-wrappers/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Set the minimum required version of CMake
cmake_minimum_required(VERSION 3.10)

# Set the project name
project("jni-wrappers")

set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")

if (NOT DEFINED CMAKE_DESTINATION_OS)
set(CMAKE_DESTINATION_OS ${CMAKE_SYSTEM_NAME})
endif ()

if (NOT DEFINED CMAKE_DESTINATION_ARCHITECTURE)
if (CMAKE_DESTINATION_OS STREQUAL "Android" AND DEFINED CMAKE_ANDROID_ARCH_ABI)
set(CMAKE_DESTINATION_ARCHITECTURE ${CMAKE_ANDROID_ARCH_ABI})
else ()
set(CMAKE_DESTINATION_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
endif ()
endif ()

if ("${CMAKE_DESTINATION_OS}" STREQUAL "Darwin")
set(file_extension "dylib")
set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "@loader_path")
elseif ("${CMAKE_DESTINATION_OS}" STREQUAL "Windows")
set(file_extension "dll")
else ()
set(file_extension "so")
endif ()

set(PRIVMX_INCLUDES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/privmx-libs/${CMAKE_DESTINATION_OS}/${CMAKE_DESTINATION_ARCHITECTURE}/include")
set(PRIVMX_LIBS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/privmx-libs/${CMAKE_DESTINATION_OS}/${CMAKE_DESTINATION_ARCHITECTURE}/lib")

message(DEBUG "CMAKE DEST OS ${CMAKE_DESTINATION_OS}")
message(DEBUG "CMAKE DEST PROCESSOR ${CMAKE_DESTINATION_ARCHITECTURE}")

include_directories(${JAVA_HOME}/include ${JAVA_HOME}/include/darwin)

# Add the subdirectories that contain the libraries
if(BUILD_ANDROID_STREAM STREQUAL "ON")
add_subdirectory(privmx-endpoint-streams/android)
endif ()

if(BUILD_JVM_STREAM STREQUAL "ON")
add_subdirectory(privmx-endpoint-streams/jvm)
endif ()

if(BUILD_ENDPOINT STREQUAL "ON")
add_subdirectory(privmx-endpoint)
endif ()
208 changes: 208 additions & 0 deletions jni-wrappers/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
//
// PrivMX Endpoint Java.
// Copyright © 2025 Simplito sp. z o.o.
//
// This file is part of the PrivMX Platform (https://privmx.dev).
// This software is Licensed under the MIT License.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import org.gradle.internal.jvm.Jvm
import org.gradle.kotlin.dsl.register
import java.util.Properties

import javax.inject.Inject

//This task add native libraries to Android Studio IDE to enable cxx code writing features
plugins {
alias(libs.plugins.androidLibrary)
}

android {
namespace = "com.simplito.privmx_endpoint_jni"
compileSdk = 36
ndkVersion = "29.0.13599879"
defaultConfig {
minSdk = 24
externalNativeBuild {
cmake {
cppFlags("-std=c++17")
}
}
}

externalNativeBuild {
cmake {
path = file("CMakeLists.txt")
version = "3.22.1"
}
}
}

abstract class NativeBuild @Inject constructor(
@Input
val exec: ExecOperations
) : DefaultTask() {

private val archs = mutableSetOf<Arch>()
private lateinit var target: NativePrivMXTarget

@get:Input
abstract val androidNdkPath: Property<String>

@get:Input
abstract val androidToolChainPath: Property<String>

@get:Input
abstract val androidAPILevel: Property<String>

@get:Input
abstract val privmxEndpointJavaVersion: Property<String>

private val compileDir = project.layout.buildDirectory.dir("native/compile").get()
private val installDir = project.layout.buildDirectory.dir("native/install").get()

@TaskAction
fun execute() {
println(Jvm.current().javaHome)
for (arch in archs) {
println("Build ${arch.getSystemName()} - ${arch.getArchName()}")
val platformCompileDir =
compileDir.dir("${arch.getSystemName()}/${privmxEndpointJavaVersion.get()}/${arch.getArchName()}").asFile
val platformInstallDir =
installDir.dir("${arch.getSystemName()}/${privmxEndpointJavaVersion.get()}/${arch.getArchName()}").asFile

exec.exec {
workingDir = project.layout.projectDirectory.asFile
commandLine = buildList {
add("sh")
add("-c")
add(buildCommand(arch,platformCompileDir,platformInstallDir))
}
}
exec.exec {
workingDir = platformCompileDir
commandLine("sh", "-c", "make -s -j8")
}
exec.exec {
workingDir = platformCompileDir
commandLine("sh", "-c", "make -s install")
}
}
}

fun buildCommand(
arch: Arch,
platformCompileDir: File,
platformInstallDir: File

): String = buildString {
append("cmake")
append(" -B${platformCompileDir.absolutePath}")
append(" -DCMAKE_INSTALL_PREFIX=\"${platformInstallDir.absolutePath}\"")
append(" -DCMAKE_BUILD_TYPE=Release")
append(" -DCMAKE_CXX_FLAGS=-std=c++17")
append(" -DCMAKE_DESTINATION_OS=${arch.getSystemName()}")
append(" -DCMAKE_DESTINATION_ARCHITECTURE=\"${arch.getArchName()}\"")
append(" -DJAVA_HOME=\"${Jvm.current().javaHome}\"")
append(" -D${target.buildOption}=ON")
if (arch is Arch.AndroidArch) {
append(" -DANDROID_NDK=\"${androidNdkPath.get()}\"")
append(" -DCMAKE_TOOLCHAIN_FILE=\"${androidToolChainPath.get()}\"")
append(" -DANDROID_PLATFORM=\"android-${androidAPILevel.get()}\"")
append(" -DANDROID_ABI=\"${arch.getArchName()}\"")
}
}


fun setArchs(
vararg archs: Arch
) {
this.archs.addAll(archs)
}

fun setTarget(target: NativePrivMXTarget) {
this.target = target
}

fun validateInput() {
// if(!::target.isInitialized) throw IncompleteArgumentException("Target is not specified (select one value from NativePrivMXTarget enum)")
}


sealed interface Arch {
fun getArchName(): String
fun getSystemName(): String

enum class AndroidArch : Arch {
`arm64-v8a`, `armeabi-v7a`, x86, x86_64;

override fun getArchName() = name

override fun getSystemName(): String = "Android"
}

enum class DarwinArch : Arch {
arm64;

override fun getArchName(): String = name

override fun getSystemName(): String = "Darwin"
}
}

enum class NativePrivMXTarget {
ENDPOINT, JVM_STREAM, ANDROID_STREAM;

val buildOption get() = "BUILD_${this.name}"
}

}

val Project.privmxEndpointJavaVersion get() = project(":privmx-endpoint").version.toString()

fun allPlatforms(): Array<NativeBuild.Arch> {
return arrayOf(*NativeBuild.Arch.AndroidArch.values(), *NativeBuild.Arch.DarwinArch.values())
}

class PropertiesConfig {
private val properties = Properties().apply {
load(File(rootDir, "local.properties").inputStream())
}
val sdkPath get() = properties["sdk.dir"]
val ndkVersion get() = properties["ndk.version"]
val ndkPath get() = "$sdkPath/ndk/$ndkVersion"
val androidToolChainPath get() = "$ndkPath/build/cmake/android.toolchain.cmake"
}

val PropertiesConfig = PropertiesConfig()


tasks.register<NativeBuild>("buildJNIEndpoint") {
setArchs(*allPlatforms())
setTarget(NativeBuild.NativePrivMXTarget.ENDPOINT)
androidAPILevel.set("24")
androidNdkPath.set(PropertiesConfig.ndkPath)
androidToolChainPath.set(PropertiesConfig.androidToolChainPath)
privmxEndpointJavaVersion.set(project.privmxEndpointJavaVersion)
}

tasks.register<NativeBuild>("buildJNIStreamsJVM") {
setArchs(*NativeBuild.Arch.DarwinArch.values())
setTarget(NativeBuild.NativePrivMXTarget.JVM_STREAM)
androidAPILevel.set("24")
androidNdkPath.set(PropertiesConfig.ndkPath)
androidToolChainPath.set(PropertiesConfig.androidToolChainPath)
privmxEndpointJavaVersion.set(project.privmxEndpointJavaVersion)
}

tasks.register<NativeBuild>("buildJNIStreamsAndroid") {
setArchs(*NativeBuild.Arch.AndroidArch.values())
setTarget(NativeBuild.NativePrivMXTarget.ANDROID_STREAM)
androidAPILevel.set("24")
androidNdkPath.set(PropertiesConfig.ndkPath)
androidToolChainPath.set(PropertiesConfig.androidToolChainPath)
privmxEndpointJavaVersion.set(project.privmxEndpointJavaVersion)
}
28 changes: 28 additions & 0 deletions jni-wrappers/privmx-endpoint-streams/android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.

# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)

# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("privmx-endpoint-streams-android")
set(CMAKE_PROJECT_NAME "privmx-endpoint-streams-android")

add_library(${CMAKE_PROJECT_NAME} SHARED
src/cpp/privmx/endpoint/wrapper/streams/StreamApiLow.cpp
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/includes)

add_library(privmxendpointstream SHARED IMPORTED GLOBAL)
set_target_properties(privmxendpointstream PROPERTIES IMPORTED_LOCATION ${PRIVMX_LIBS_DIR}/libprivmxendpointstream.${file_extension})

include_directories(${PRIVMX_INCLUDES_DIR})
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE privmx-endpoint-java privmxendpointstream)

install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/android/lib)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/includes DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/android/include)
install(IMPORTED_RUNTIME_ARTIFACTS privmxendpointstream DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/android/lib)
28 changes: 28 additions & 0 deletions jni-wrappers/privmx-endpoint-streams/jvm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.

# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)

# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("privmx-endpoint-streams-jvm")
set(CMAKE_PROJECT_NAME "privmx-endpoint-streams-jvm")

add_library(${CMAKE_PROJECT_NAME} SHARED
src/cpp/privmx/endpoint/wrapper/streams/StreamApi.cpp
)
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/includes)

add_library(privmxendpointstream SHARED IMPORTED GLOBAL)
set_target_properties(privmxendpointstream PROPERTIES IMPORTED_LOCATION ${PRIVMX_LIBS_DIR}/libprivmxendpointstream.${file_extension})

include_directories(${PRIVMX_INCLUDES_DIR})
target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE privmx-endpoint-java privmxendpointstream)

install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/jvm/lib)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/includes DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/jvm/include)
install(IMPORTED_RUNTIME_ARTIFACTS privmxendpointstream DESTINATION ${CMAKE_INSTALL_PREFIX}/privmx-endpoint-streams/jvm/lib)
Loading