This article demonstrates easy way of generating C++ stub code including Java Generation for the corresponding C++ Classes using SWIG
The Gradle KTS project contains a sub module which contains the main source code, the header file and the SWIG file
The Gradle KTS is written in such way it will call the "swig" command line and generates the wrappers and copies the files to corresponding locations
The C++ compiler is auto chosen by Gradle cpp-library plugin, there is no need to write CMake or MakeFile or batch files for that
The code uses the latest Gradle 7.1.1
GitHub: https://github.com/dickensas/kotlin-gradle-templates/tree/master/swig-jni
The Gradle SWIG Task
val swigTask: Exec by tasks.creating(Exec::class) {
commandLine (
"swig",
"-c++",
"-java",
"-cppext",
"cpp",
"-addextern",
"-module",
"${project.name}",
"src\\main\\swig\\${project.name}.i"
)
}
The Gradle CPP Compiler Arguments
tasks.withType(CppCompile::class.java).configureEach {
dependsOn(swigTask)
doFirst {
copy {
from("${project.rootDir}/${project.name}/src/main/swig")
into("${project.rootDir}/${project.name}/src/main/cpp")
exclude("*.java")
exclude("*.i")
}
}
compilerArgs.addAll(toolChain.map { toolChain ->
when (toolChain) {
is Gcc, is Clang -> listOf(
"-c",
"-v",
"-fpic",
"-I/usr/java/include",
"-I$javaHome/include",
"-I$javaHome/include/win32"
)
else -> listOf()
}
})
}
Gradle CPP Linker Arguments
tasks.withType(LinkSharedLibrary::class.java).configureEach {
linkerArgs.addAll(toolChain.map { toolChain ->
when (toolChain) {
is Gcc, is Clang -> listOf(
"-v",
"-Wl,--out-implib=${project.name}.dll.a",
"-Wl,--export-all-symbols",
"-Wl,--enable-auto-import",
"-Wl,--output-def=${project.name}.def"
)
else -> listOf()
}
})
doLast {
copy {
from("${project.rootDir}/${project.name}/build/lib/main/debug")
into("${project.rootDir}")
exclude("*.java")
exclude("*.i")
exclude("*.obj")
}
copy {
from("${project.rootDir}/${project.name}/src/main/swig")
into("${project.rootDir}/src/main/java")
exclude("*.i")
exclude("*.cpp")
}
copy {
from("${project.rootDir}/${project.name}/${project.name}.dll.a")
into("${project.rootDir}")
}
copy {
from("${project.rootDir}/${project.name}/${project.name}.def")
into("${project.rootDir}")
}
}
}
this code is written generic based on the folder name of the sub project is assumed as the DLL file name
These gradle tasks plays the important role, otherwise you need to manually copy the files
The Kotlin Code
class App {
val greeting: String
get() {
return Greeter().greeting()
}
companion object {
init {
System.loadLibrary("cpplib")
}
}
}
fun main(args: Array<String>) {
println(App().greeting)
}
The C++ code
#include <iostream>
#include <stdlib.h>
#include "cpplib.h"
std::string jniexample::Greeter::greeting() {
return std::string("Hello, World! From C++");
}
The SWIG Code
%include "std_string.i"
%{
#include "../public/cpplib.h"
%}
%include "../public/cpplib.h"
Final Output
> Task :run
Hello, World! From C++
You need to install SWIG,
I used MSYS2 and installed swig by issuing command
pacman -S base-devel
JAVA_HOME environment variable need to be set
From gradle this code will take the JAVA_HOME
val javaHome = System.getenv("JAVA_HOME")
Current target architecture is WIndows, it needs be changed for Linux or other targets
targetMachines.add(machines.windows.x86_64)
Finished!