├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── jvmMain └── kotlin │ └── jvm.kt ├── nativeInterop └── cinterop │ └── jni.def └── nativeMain └── kotlin └── kni.kt /.gitattributes: -------------------------------------------------------------------------------- 1 | gradlew binary 2 | gradlew.bat binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | *.iml 4 | out/ 5 | .DS_Store 6 | .idea/ 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Eugene Petrenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Loading Kotlin/Native binary as JNI library 2 | ============ 3 | 4 | The idea of that project is to experiment with both JVM (11 in my case) 5 | and Kotlin/Native. 6 | 7 | What we do 8 | - we run Java application 9 | - we build shared library with Kotlin/Native to implement JNI contracts 10 | - we load Kotlin/Native library into JVM application 11 | 12 | Hack with pleasure! 13 | 14 | License 15 | ======= 16 | 17 | MIT, see the LICENSE file in the repository 18 | 19 | 20 | Building and Running 21 | ==================== 22 | 23 | Execute `./gradlew build` task. 24 | Fix path to the library in Java sources. 25 | Start Java application 26 | 27 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithTests 2 | import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem 3 | import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension 4 | 5 | fun KotlinMultiplatformExtension.setupNative(name: String, 6 | configure: KotlinNativeTargetWithTests.() -> Unit): KotlinNativeTargetWithTests { 7 | val os = getCurrentOperatingSystem() 8 | return when { 9 | os.isLinux -> linuxX64(name, configure) 10 | os.isWindows -> mingwX64(name, configure) 11 | os.isMacOsX -> macosX64(name, configure) 12 | else -> error("OS $os is not supported") 13 | } 14 | } 15 | 16 | plugins { 17 | kotlin("multiplatform") version "1.3.61" 18 | id("me.filippov.gradle.jvm.wrapper") version "0.9.2" 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | kotlin { 26 | val jvm = jvm() 27 | 28 | jvm.compilations["main"].dependencies { 29 | implementation(kotlin("stdlib-jdk8")) 30 | } 31 | 32 | val native = setupNative("native") { 33 | binaries { 34 | sharedLib() 35 | } 36 | 37 | compilations["main"].cinterops.create("jni") { 38 | // JDK is required here, JRE is not enough 39 | val javaHome = File(System.getenv("JAVA_HOME") ?: System.getProperty("java.home")) 40 | packageName = "org.jonnyzzz.jni" 41 | includeDirs( 42 | Callable { File(javaHome, "include") }, 43 | Callable { File(javaHome, "include/darwin") }, 44 | Callable { File(javaHome, "include/linux") }, 45 | Callable { File(javaHome, "include/win32") } 46 | ) 47 | } 48 | } 49 | 50 | val run by tasks.creating(JavaExec::class) { 51 | main = "org.jonnyzzz.jni.java.JvmKt" 52 | group = "application" 53 | 54 | dependsOn(jvm.compilations.map { it.compileAllTaskName }) 55 | dependsOn(native.compilations.map { it.compileAllTaskName }) 56 | dependsOn(native.binaries.map { it.linkTaskName }) 57 | 58 | systemProperty("jonnyzzz.demo", "set") 59 | 60 | doFirst { 61 | classpath( 62 | jvm.compilations["main"].output.allOutputs.files, 63 | configurations["jvmRuntimeClasspath"] 64 | ) 65 | 66 | ///disable app icon on macOS 67 | systemProperty("java.awt.headless", "true") 68 | systemProperty("java.library.path", native.binaries.findSharedLib("debug")!!.outputDirectory) 69 | } 70 | } 71 | } 72 | 73 | tasks.wrapper { 74 | distributionType = Wrapper.DistributionType.ALL 75 | } 76 | 77 | jvmWrapper { 78 | linuxJvmUrl = "https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-linux-x64.tar.gz" 79 | macJvmUrl = "https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-macosx-x64.tar.gz" 80 | windowsJvmUrl ="https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-windows-x86-jdk.zip" 81 | } 82 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonnyzzz/kotlin-jni-mix/94ca9a01efec003d35fea96a3de87c517b88e5be/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | # GRADLE JVM WRAPPER START MARKER 86 | BUILD_DIR=$APP_HOME/build 87 | 88 | if [ "$darwin" = "true" ]; then 89 | JVM_TEMP_FILE=$BUILD_DIR/jvm-macosx-x64.tar.gz 90 | JVM_URL=https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-macosx-x64.tar.gz 91 | JVM_TARGET_DIR=$BUILD_DIR/gradle-jvm/amazon-corretto-8.232.09.1-macosx-x64-2f9972 92 | else 93 | JVM_TEMP_FILE=$BUILD_DIR/jvm-linux-x64.tar.gz 94 | JVM_URL=https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-linux-x64.tar.gz 95 | JVM_TARGET_DIR=$BUILD_DIR/gradle-jvm/amazon-corretto-8.232.09.1-linux-x64-e72124 96 | fi 97 | 98 | set -e 99 | 100 | if [ -e "$JVM_TARGET_DIR/.flag" ] && [ -n "$(ls "$JVM_TARGET_DIR")" ] && [ "x$(cat "$JVM_TARGET_DIR/.flag")" = "x${JVM_URL}" ]; then 101 | # Everything is up-to-date in $JVM_TARGET_DIR, do nothing 102 | true 103 | else 104 | warn "Downloading $JVM_URL to $JVM_TEMP_FILE" 105 | 106 | rm -f "$JVM_TEMP_FILE" 107 | mkdir -p "$BUILD_DIR" 108 | if command -v curl >/dev/null 2>&1; then 109 | if [ -t 1 ]; then CURL_PROGRESS="--progress-bar"; else CURL_PROGRESS="--silent --show-error"; fi 110 | # shellcheck disable=SC2086 111 | curl $CURL_PROGRESS --output "${JVM_TEMP_FILE}" "$JVM_URL" 112 | elif command -v wget >/dev/null 2>&1; then 113 | if [ -t 1 ]; then WGET_PROGRESS=""; else WGET_PROGRESS="-nv"; fi 114 | wget $WGET_PROGRESS -O "${JVM_TEMP_FILE}" "$JVM_URL" 115 | else 116 | die "ERROR: Please install wget or curl" 117 | fi 118 | 119 | warn "Extracting $JVM_TEMP_FILE to $JVM_TARGET_DIR" 120 | rm -rf "$JVM_TARGET_DIR" 121 | mkdir -p "$JVM_TARGET_DIR" 122 | 123 | tar -x -f "$JVM_TEMP_FILE" -C "$JVM_TARGET_DIR" 124 | rm -f "$JVM_TEMP_FILE" 125 | 126 | echo "$JVM_URL" >"$JVM_TARGET_DIR/.flag" 127 | fi 128 | 129 | JAVA_HOME= 130 | for d in "$JVM_TARGET_DIR" "$JVM_TARGET_DIR"/* "$JVM_TARGET_DIR"/Contents/Home "$JVM_TARGET_DIR"/*/Contents/Home; do 131 | if [ -e "$d/bin/java" ]; then 132 | JAVA_HOME="$d" 133 | fi 134 | done 135 | 136 | if [ '!' -e "$JAVA_HOME/bin/java" ]; then 137 | die "Unable to find bin/java under $JVM_TARGET_DIR" 138 | fi 139 | 140 | # Make it available for child processes 141 | export JAVA_HOME 142 | 143 | set +e 144 | 145 | # GRADLE JVM WRAPPER END MARKER 146 | 147 | # Determine the Java command to use to start the JVM. 148 | if [ -n "$JAVA_HOME" ] ; then 149 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 150 | # IBM's JDK on AIX uses strange locations for the executables 151 | JAVACMD="$JAVA_HOME/jre/sh/java" 152 | else 153 | JAVACMD="$JAVA_HOME/bin/java" 154 | fi 155 | if [ ! -x "$JAVACMD" ] ; then 156 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 157 | 158 | Please set the JAVA_HOME variable in your environment to match the 159 | location of your Java installation." 160 | fi 161 | else 162 | JAVACMD="java" 163 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 164 | 165 | Please set the JAVA_HOME variable in your environment to match the 166 | location of your Java installation." 167 | fi 168 | 169 | # Increase the maximum file descriptors if we can. 170 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 171 | MAX_FD_LIMIT=`ulimit -H -n` 172 | if [ $? -eq 0 ] ; then 173 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 174 | MAX_FD="$MAX_FD_LIMIT" 175 | fi 176 | ulimit -n $MAX_FD 177 | if [ $? -ne 0 ] ; then 178 | warn "Could not set maximum file descriptor limit: $MAX_FD" 179 | fi 180 | else 181 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 182 | fi 183 | fi 184 | 185 | # For Darwin, add options to specify how the application appears in the dock 186 | if $darwin; then 187 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 188 | fi 189 | 190 | # For Cygwin or MSYS, switch paths to Windows format before running java 191 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 192 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 193 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 194 | JAVACMD=`cygpath --unix "$JAVACMD"` 195 | 196 | # We build the pattern for arguments to be converted via cygpath 197 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 198 | SEP="" 199 | for dir in $ROOTDIRSRAW ; do 200 | ROOTDIRS="$ROOTDIRS$SEP$dir" 201 | SEP="|" 202 | done 203 | OURCYGPATTERN="(^($ROOTDIRS))" 204 | # Add a user-defined pattern to the cygpath arguments 205 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 206 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 207 | fi 208 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 209 | i=0 210 | for arg in "$@" ; do 211 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 212 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 213 | 214 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 215 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 216 | else 217 | eval `echo args$i`="\"$arg\"" 218 | fi 219 | i=`expr $i + 1` 220 | done 221 | case $i in 222 | 0) set -- ;; 223 | 1) set -- "$args0" ;; 224 | 2) set -- "$args0" "$args1" ;; 225 | 3) set -- "$args0" "$args1" "$args2" ;; 226 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 227 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 228 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 229 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 230 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 231 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 232 | esac 233 | fi 234 | 235 | # Escape application args 236 | save () { 237 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 238 | echo " " 239 | } 240 | APP_ARGS=`save "$@"` 241 | 242 | # Collect all arguments for the java command, following the shell quoting and substitution rules 243 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 244 | 245 | exec "$JAVACMD" "$@" 246 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem GRADLE JVM WRAPPER START MARKER 36 | 37 | setlocal 38 | 39 | set BUILD_DIR=%APP_HOME%build\ 40 | set JVM_TARGET_DIR=%BUILD_DIR%gradle-jvm\amazon-corretto-8.232.09.1-windows-x86-jdk-514d36\ 41 | 42 | set JVM_TEMP_FILE=jvm-windows-x64.zip 43 | set JVM_URL=https://d3pxv6yz143wms.cloudfront.net/8.232.09.1/amazon-corretto-8.232.09.1-windows-x86-jdk.zip 44 | 45 | set POWERSHELL=%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe 46 | 47 | if not exist "%JVM_TARGET_DIR%" MD "%JVM_TARGET_DIR%" 48 | 49 | if not exist "%JVM_TARGET_DIR%.flag" goto downloadAndExtractJvm 50 | 51 | set /p CURRENT_FLAG=<"%JVM_TARGET_DIR%.flag" 52 | if "%CURRENT_FLAG%" == "%JVM_URL%" goto continueWithJvm 53 | 54 | :downloadAndExtractJvm 55 | 56 | CD "%BUILD_DIR%" 57 | if errorlevel 1 goto fail 58 | 59 | echo Downloading %JVM_URL% to %BUILD_DIR%%JVM_TEMP_FILE% 60 | if exist "%JVM_TEMP_FILE%" DEL /F "%JVM_TEMP_FILE%" 61 | "%POWERSHELL%" -nologo -noprofile -Command "Set-StrictMode -Version 3.0; $ErrorActionPreference = \"Stop\"; (New-Object Net.WebClient).DownloadFile('%JVM_URL%', '%JVM_TEMP_FILE%')" 62 | if errorlevel 1 goto fail 63 | 64 | RMDIR /S /Q "%JVM_TARGET_DIR%" 65 | if errorlevel 1 goto fail 66 | 67 | MKDIR "%JVM_TARGET_DIR%" 68 | if errorlevel 1 goto fail 69 | 70 | CD "%JVM_TARGET_DIR%" 71 | if errorlevel 1 goto fail 72 | 73 | echo Extracting %BUILD_DIR%%JVM_TEMP_FILE% to %JVM_TARGET_DIR% 74 | "%POWERSHELL%" -nologo -noprofile -command "Set-StrictMode -Version 3.0; $ErrorActionPreference = \"Stop\"; Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('..\\..\\%JVM_TEMP_FILE%', '.');" 75 | if errorlevel 1 goto fail 76 | 77 | DEL /F "..\..\%JVM_TEMP_FILE%" 78 | if errorlevel 1 goto fail 79 | 80 | echo %JVM_URL%>"%JVM_TARGET_DIR%.flag" 81 | if errorlevel 1 goto fail 82 | 83 | :continueWithJvm 84 | 85 | set JAVA_HOME= 86 | for /d %%d in ("%JVM_TARGET_DIR%"*) do if exist "%%d\bin\java.exe" set JAVA_HOME=%%d 87 | if not exist "%JAVA_HOME%\bin\java.exe" ( 88 | echo Unable to find java.exe under %JVM_TARGET_DIR% 89 | goto fail 90 | ) 91 | 92 | endlocal & set JAVA_HOME=%JAVA_HOME% 93 | 94 | @rem GRADLE JVM WRAPPER END MARKER 95 | 96 | @rem Find java.exe 97 | if defined JAVA_HOME goto findJavaFromJavaHome 98 | 99 | set JAVA_EXE=java.exe 100 | %JAVA_EXE% -version >NUL 2>&1 101 | if "%ERRORLEVEL%" == "0" goto init 102 | 103 | echo. 104 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 105 | echo. 106 | echo Please set the JAVA_HOME variable in your environment to match the 107 | echo location of your Java installation. 108 | 109 | goto fail 110 | 111 | :findJavaFromJavaHome 112 | set JAVA_HOME=%JAVA_HOME:"=% 113 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 114 | 115 | if exist "%JAVA_EXE%" goto init 116 | 117 | echo. 118 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 119 | echo. 120 | echo Please set the JAVA_HOME variable in your environment to match the 121 | echo location of your Java installation. 122 | 123 | goto fail 124 | 125 | :init 126 | @rem Get command-line arguments, handling Windows variants 127 | 128 | if not "%OS%" == "Windows_NT" goto win9xME_args 129 | 130 | :win9xME_args 131 | @rem Slurp the command line arguments. 132 | set CMD_LINE_ARGS= 133 | set _SKIP=2 134 | 135 | :win9xME_args_slurp 136 | if "x%~1" == "x" goto execute 137 | 138 | set CMD_LINE_ARGS=%* 139 | 140 | :execute 141 | @rem Setup the command line 142 | 143 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 144 | 145 | @rem Execute Gradle 146 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 147 | 148 | :end 149 | @rem End local scope for the variables with windows NT shell 150 | if "%ERRORLEVEL%"=="0" goto mainEnd 151 | 152 | :fail 153 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 154 | rem the _cmd.exe /c_ return code! 155 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 156 | exit /b 1 157 | 158 | :mainEnd 159 | if "%OS%"=="Windows_NT" endlocal 160 | 161 | :omega 162 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonnyzzz/kotlin-jni-mix/94ca9a01efec003d35fea96a3de87c517b88e5be/settings.gradle.kts -------------------------------------------------------------------------------- /src/jvmMain/kotlin/jvm.kt: -------------------------------------------------------------------------------- 1 | package org.jonnyzzz.jni.java 2 | 3 | 4 | fun main() { 5 | requireNotNull(System.getProperty("jonnyzzz.demo")) { 6 | "Please run this example via the `run` task in " + 7 | "Gradle to make sure the native part is included correctly" 8 | } 9 | 10 | Runtime.getRuntime().loadLibrary("kotlin_jni_mix") 11 | 12 | val ret = NativeHost().callInt(42) 13 | println("ret from the native: $ret") 14 | } 15 | 16 | class NativeHost { 17 | external fun callInt(x: Int) : Int 18 | } 19 | -------------------------------------------------------------------------------- /src/nativeInterop/cinterop/jni.def: -------------------------------------------------------------------------------- 1 | headers = jni.h 2 | -------------------------------------------------------------------------------- /src/nativeMain/kotlin/kni.kt: -------------------------------------------------------------------------------- 1 | package org.jonnyzzz.jni.native 2 | 3 | import kotlinx.cinterop.CPointer 4 | import org.jonnyzzz.jni.JNIEnvVar 5 | import org.jonnyzzz.jni.jclass 6 | import org.jonnyzzz.jni.jint 7 | 8 | //NOTE: build the project is your see red code here 9 | //NOTE: by calling the Gradle `build` task 10 | 11 | @Suppress("UNUSED_PARAMETER") 12 | @CName("Java_org_jonnyzzz_jni_java_NativeHost_callInt") 13 | fun callInt(env: CPointer, clazz: jclass, it: jint): jint { 14 | initRuntimeIfNeeded() 15 | Platform.isMemoryLeakCheckerActive = false 16 | 17 | println("Native function is executed with: $it") 18 | return it + 1 19 | } 20 | --------------------------------------------------------------------------------