From b9ed14ff6d360876ffd6e8621e585f2aaa6d5f93 Mon Sep 17 00:00:00 2001 From: soloturn Date: Mon, 24 Aug 2026 08:37:25 +0200 Subject: [PATCH] build: convert Gradle build scripts from Groovy to Kotlin DSL Converts the three build scripts to Kotlin DSL. No intended behavior change. - Groovy's dynamic `dependsOn swig_collision` (auto-exposed task-as-property) becomes string-form `dependsOn("swig_collision")` - Kotlin doesn't expose tasks as identifiers. - `FileTree.visit { }` closures need `closureOf { }` to convert a Kotlin lambda into the `groovy.lang.Closure` the API expects. - `pom.withXml { asNode()... }` keeps using Groovy's `Node.appendNode()` - that's a Groovy runtime API, not Gradle's, so it's callable from Kotlin unchanged (just needs an explicit `groovy.util.Node` cast, since Kotlin won't infer through the Groovy-dynamic return type). - `repositories { maven { url = ... } }` needs `uri(...)` around each string: the Groovy DSL coerces String -> URI on assignment; Kotlin's typed setter doesn't. Also bumps `gradle-wrapper.properties`' distributionUrl string to 9.7.1 - just the version number, not a `gradlew wrapper` run (that also touches gradle-wrapper.jar and gradlew/gradlew.bat, out of scope here). Verified: `gradlew help`, `gradlew listNatives` (dynamic native_* task registration + OS/arch detection), `gradlew tasks --all` (every custom task present under its original name), `compileJava --dry-run` and `publish --dry-run` (task graphs match: swig_* -> Swig -> generateSources -> compileJava; sourceJar/javadocJar/zipNatives -> publish), and an actual `generatePomFileForMavenJavaPublication` run - the generated POM's name/description/licenses/developers/scm blocks match the original Groovy Node-manipulation output exactly. SWIG/CMake aren't installed locally, so the real native compilation itself isn't exercised here - CI covers that. Co-Authored-By: soloturn --- .github/workflows/allInOne.yml | 2 +- build.gradle | 272 ---------------------- build.gradle.kts | 279 +++++++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 3 - settings.gradle.kts | 2 + swig-src/build.gradle | 66 ------ swig-src/build.gradle.kts | 69 ++++++ 8 files changed, 352 insertions(+), 343 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts delete mode 100644 swig-src/build.gradle create mode 100644 swig-src/build.gradle.kts diff --git a/.github/workflows/allInOne.yml b/.github/workflows/allInOne.yml index c673a49b2..e47b7263e 100644 --- a/.github/workflows/allInOne.yml +++ b/.github/workflows/allInOne.yml @@ -151,7 +151,7 @@ jobs: run: sudo apt-get install -y mingw-w64 - name: Install llvm-mingw (Windows arm64 cross-compiler) # Classic mingw-w64 (GCC) has no Windows/ARM64 target; only needed on the job - # that actually builds linux_windows_arm64_llvm_mingw32, see build.gradle. + # that actually builds linux_windows_arm64_llvm_mingw32, see build.gradle.kts. if: runner.os == 'Linux' && runner.arch == 'X64' run: | curl -fL -o llvm-mingw.tar.xz "https://github.com/mstorsjo/llvm-mingw/releases/download/${{ env.LLVM_MINGW_VERSION }}/llvm-mingw-${{ env.LLVM_MINGW_VERSION }}-ucrt-ubuntu-22.04-x86_64.tar.xz" diff --git a/build.gradle b/build.gradle deleted file mode 100644 index e63affc33..000000000 --- a/build.gradle +++ /dev/null @@ -1,272 +0,0 @@ -plugins { - id 'java-library' - id 'maven-publish' -} - -import org.apache.tools.ant.taskdefs.condition.Os -ext { - if(Os.isFamily(Os.FAMILY_MAC)) { - // Compilation succeeds for both targets on either Mac platform, but in both cases the output is for the platform we're on - // Therefore, we only include our own platform as target here. - if (Os.isArch("aarch64")) { - natives = ["macosx_aarch64_clang"] - } else { - natives = ["macosx_amd64_clang"] - } - } else if (Os.isFamily(Os.FAMILY_UNIX)) { - if (Os.isArch("aarch64")) { - // No MinGW-w64 cross target here: the Windows amd64 build is unrelated to and - // not reliably available when cross-compiling from an aarch64 host. - natives = ["linux_aarch64_gcc"] - } else { - // Cross-compilation with MinGW-w64 allows us to also build the Windows amd64 target - // on Linux, and with llvm-mingw (must be on PATH, see toolchains/linux_windows_arm64_llvm_mingw32.cmake) - // the Windows arm64 target too. - natives = ["linux_amd64_gcc","linux_windows_amd64_mingw32","linux_windows_arm64_llvm_mingw32"] - } - } else { - throw new GradleException("This script only works on Linux or Mac") - } - - allNatives = [ - "linux_amd64_gcc", - "linux_aarch64_gcc", - "linux_windows_amd64_mingw32", - "linux_windows_arm64_llvm_mingw32", - "macosx_aarch64_clang", - "macosx_amd64_clang" - ] - - generatedSrcDir = 'src/generated/java' -} - -java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 -} - -// We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on -repositories { - mavenCentral() - - // Terasology Artifactory instance for libs not readily available elsewhere plus our own libs - maven { - def repoViaEnv = System.getenv()["RESOLUTION_REPO"] - if (rootProject.hasProperty("alternativeResolutionRepo")) { - // If the user supplies an alternative repo via gradle.properties then use that - name = "from alternativeResolutionRepo property" - url = alternativeResolutionRepo - } else if (repoViaEnv != null && repoViaEnv != "") { - name = "from \$RESOLUTION_REPO" - url = repoViaEnv - } else { - // Our default is the main virtual repo containing everything except repos for testing Artifactory itself - name = "Terasology Artifactory" - url = "https://artifactory.terasology.io/artifactory/virtual-repo-live" - } - } -} - -group = 'org.terasology.jnbullet' - -dependencies { - api "org.joml:joml:1.9.25" - api "net.sf.trove4j:trove4j:3.0.3" - implementation "org.slf4j:slf4j-api:1.7.21" -} - -sourceSets { - main { - java { - srcDir generatedSrcDir - } - } -} - -task generateSources{ - dependsOn ":swig-src:Swig" -} - -compileJava.dependsOn generateSources - -clean { - // the clean task should delete the folder, because it is the - // output folder of generateSources, but it doesn't do it. - delete generatedSrcDir -} - -task sourceJar(type: Jar) { - description = "Create a JAR with all sources" - from sourceSets.main.allSource - from sourceSets.test.allSource - archiveClassifier = 'sources' -} - -task javadocJar(type: Jar, dependsOn: javadoc) { - description = "Create a JAR with the JavaDoc for the java sources" - from javadoc.destinationDir - archiveClassifier = 'javadoc' -} - -natives.each { module -> - tasks.create(name: "native_${module}", type: Exec) { - description = "cmake ${module} " - executable "cmake" - workingDir "$rootDir/build/natives/${module}" - args "$rootDir", "-DCMAKE_TOOLCHAIN_FILE=$rootDir/toolchains/${module}.cmake", "-DCMAKE_BUILD_TYPE=Release" - doFirst { - mkdir "$rootDir/build/natives/${module}" - } - doLast { - def process = new ProcessBuilder('make', "-j${Runtime.runtime.availableProcessors()}") - .directory(file("$rootDir/build/natives/${module}")) - .redirectErrorStream(true) - .start() - process.inputStream.eachLine { println it } - def exitCode = process.waitFor() - if (exitCode != 0) { - throw new GradleException("make failed with exit code ${exitCode}") - } - } - } -} - -task buildNatives{ - description = "Builds Natives" - natives.each { module -> - dependsOn "native_${module}" - } -} - -task listNatives{ - description = "List all supported platforms." - doLast { - println "All known natives (*supported):" - allNatives.each { module -> - // check whether module is contained in natives - if (natives.contains(module)) { - println " *native_${module}" - } else { - println " native_${module}" - } - } - } -} - -// TODO: outputs are not defined well enough yet for Gradle to skip this if already done (maybe more the natives task?) -task zipNatives(type: Zip){ - description = 'Creates a zip archive that contains all TeraBullet native files' - allNatives.each { module -> - from ("$rootDir/build/natives/${module}") { - include '*linux*' - into 'linux' - } - - from ("$rootDir/build/natives/${module}") { - include '*windows*' - into 'windows' - } - - from ("$rootDir/build/natives/${module}") { - include '*darwin*' - into 'macosx' - } - } - - destinationDirectory = file(buildDir) - archiveBaseName = 'JNBullet' -} - -buildNatives.dependsOn generateSources -// Building natives is a prerequisite for zipping them, but we don't want to re-compute them every time. -// Also, we build natives on different platforms and combine them to a single zip, so we can't just depend on the native tasks anyway. -//zipNatives.dependsOn buildNatives - -javadoc { - failOnError = false -} - -publish { - dependsOn sourceJar, javadocJar, zipNatives -} - -// Define the artifacts we want to publish (the .pom will also be included since the Maven plugin is active) -publishing { - publications { - mavenJava(MavenPublication) { - artifactId='JNBullet' - groupId = group - - from components.java - artifact sourceJar - artifact javadocJar - artifact zipNatives - - pom.withXml { - asNode().with { - appendNode('name', "JNBullet") - appendNode('description', "A Java Native Bullet Wrapper") - appendNode('url', "http://www.example.com/project") - appendNode('licenses').with { - appendNode('license').with { - appendNode('name', "The Apache License, Version 2.0") - appendNode('url', "http://www.apache.org/licenses/LICENSE-2.0.txt") - } - } - appendNode('developers').with { - appendNode('developer').with { - appendNode('id', "michaelpollind") - appendNode('name', "Michael Pollind") - appendNode('email', "mpollind@gmail.com") - } - } - appendNode('scm').with { - appendNode('connection', "https://github.com/MovingBlocks/JNBullet") - appendNode('developerConnection', "git@github.com:MovingBlocks/JNBullet.git") - appendNode('url', "https://github.com/MovingBlocks/JNBullet") - } - } - } - - repositories { - maven { - name = 'TerasologyOrg' - - if (rootProject.hasProperty("publishRepo")) { - // This first option is good for local testing, you can set a full explicit target repo in gradle.properties - url = "https://artifactory.terasology.io/artifactory/$publishRepo" - - logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) - } else { - // Support override from the environment to use a different target publish org - String deducedPublishRepo = System.getenv()["PUBLISH_ORG"] - if (deducedPublishRepo == null || deducedPublishRepo == "") { - // If not then default - deducedPublishRepo = "libs" - } - - // Base final publish repo on whether we're building a snapshot or a release - if (project.version.endsWith('SNAPSHOT')) { - deducedPublishRepo += "-snapshot-local" - } else { - deducedPublishRepo += "-release-local" - } - - logger.info("The final deduced publish repo is {}", deducedPublishRepo) - url = "https://artifactory.terasology.io/artifactory/$deducedPublishRepo" - } - - if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { - credentials { - username = "$mavenUser" - password = "$mavenPass" - } - authentication { - basic(BasicAuthentication) - } - } - } - } - } - } -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 000000000..29cc1fe12 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,279 @@ +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.authentication.http.BasicAuthentication + +plugins { + `java-library` + `maven-publish` +} + +// Compilation succeeds for both targets on either Mac platform, but in both cases the output is +// for the platform we're on. Therefore, we only include our own platform as target here. +val natives: List = if (Os.isFamily(Os.FAMILY_MAC)) { + if (Os.isArch("aarch64")) { + listOf("macosx_aarch64_clang") + } else { + listOf("macosx_amd64_clang") + } +} else if (Os.isFamily(Os.FAMILY_UNIX)) { + if (Os.isArch("aarch64")) { + // No MinGW-w64 cross target here: the Windows amd64 build is unrelated to and + // not reliably available when cross-compiling from an aarch64 host. + listOf("linux_aarch64_gcc") + } else { + // Cross-compilation with MinGW-w64 allows us to also build the Windows amd64 target + // on Linux, and with llvm-mingw (must be on PATH, see toolchains/linux_windows_arm64_llvm_mingw32.cmake) + // the Windows arm64 target too. + listOf("linux_amd64_gcc", "linux_windows_amd64_mingw32", "linux_windows_arm64_llvm_mingw32") + } +} else { + throw GradleException("This script only works on Linux or Mac") +} + +val allNatives = listOf( + "linux_amd64_gcc", + "linux_aarch64_gcc", + "linux_windows_amd64_mingw32", + "linux_windows_arm64_llvm_mingw32", + "macosx_aarch64_clang", + "macosx_amd64_clang" +) + +val generatedSrcDir = "src/generated/java" + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +// We use both Maven Central and our own Artifactory instance, which contains module builds, extra libs, and so on +repositories { + mavenCentral() + + // Terasology Artifactory instance for libs not readily available elsewhere plus our own libs + maven { + val repoViaEnv = System.getenv("RESOLUTION_REPO") + if (rootProject.hasProperty("alternativeResolutionRepo")) { + // If the user supplies an alternative repo via gradle.properties then use that + name = "from alternativeResolutionRepo property" + url = uri(rootProject.property("alternativeResolutionRepo") as String) + } else if (!repoViaEnv.isNullOrEmpty()) { + name = "from \$RESOLUTION_REPO" + url = uri(repoViaEnv) + } else { + // Our default is the main virtual repo containing everything except repos for testing Artifactory itself + name = "Terasology Artifactory" + url = uri("https://artifactory.terasology.io/artifactory/virtual-repo-live") + } + } +} + +group = "org.terasology.jnbullet" + +dependencies { + api("org.joml:joml:1.9.25") + api("net.sf.trove4j:trove4j:3.0.3") + implementation("org.slf4j:slf4j-api:1.7.21") +} + +sourceSets { + main { + java { + srcDir(generatedSrcDir) + } + } +} + +val generateSources by tasks.registering { + dependsOn(":swig-src:Swig") +} + +tasks.compileJava { + dependsOn(generateSources) +} + +tasks.named("clean") { + // the clean task should delete the folder, because it is the + // output folder of generateSources, but it doesn't do it. + delete(generatedSrcDir) +} + +val sourceJar by tasks.registering(Jar::class) { + description = "Create a JAR with all sources" + from(sourceSets.main.get().allSource) + from(sourceSets.test.get().allSource) + archiveClassifier.set("sources") +} + +val javadocJar by tasks.registering(Jar::class) { + description = "Create a JAR with the JavaDoc for the java sources" + dependsOn(tasks.javadoc) + from(tasks.javadoc.get().destinationDir) + archiveClassifier.set("javadoc") +} + +natives.forEach { module -> + tasks.register("native_$module") { + description = "cmake $module " + executable = "cmake" + workingDir = file("$rootDir/build/natives/$module") + args(rootDir, "-DCMAKE_TOOLCHAIN_FILE=$rootDir/toolchains/$module.cmake", "-DCMAKE_BUILD_TYPE=Release") + + doFirst { + mkdir("$rootDir/build/natives/$module") + } + doLast { + val process = ProcessBuilder("make", "-j${Runtime.getRuntime().availableProcessors()}") + .directory(file("$rootDir/build/natives/$module")) + .redirectErrorStream(true) + .start() + process.inputStream.bufferedReader().forEachLine { println(it) } + val exitCode = process.waitFor() + if (exitCode != 0) { + throw GradleException("make failed with exit code $exitCode") + } + } + } +} + +val buildNatives by tasks.registering { + description = "Builds Natives" + natives.forEach { module -> + dependsOn("native_$module") + } +} + +val listNatives by tasks.registering { + description = "List all supported platforms." + doLast { + println("All known natives (*supported):") + allNatives.forEach { module -> + // check whether module is contained in natives + if (natives.contains(module)) { + println(" *native_$module") + } else { + println(" native_$module") + } + } + } +} + +// TODO: outputs are not defined well enough yet for Gradle to skip this if already done (maybe more the natives task?) +val zipNatives by tasks.registering(Zip::class) { + description = "Creates a zip archive that contains all TeraBullet native files" + allNatives.forEach { module -> + from("$rootDir/build/natives/$module") { + include("*linux*") + into("linux") + } + + from("$rootDir/build/natives/$module") { + include("*windows*") + into("windows") + } + + from("$rootDir/build/natives/$module") { + include("*darwin*") + into("macosx") + } + } + + destinationDirectory.set(buildDir) + archiveBaseName.set("JNBullet") +} + +buildNatives { + dependsOn(generateSources) +} +// Building natives is a prerequisite for zipping them, but we don't want to re-compute them every time. +// Also, we build natives on different platforms and combine them to a single zip, so we can't just depend on the native tasks anyway. +//zipNatives.dependsOn(buildNatives) + +tasks.javadoc { + isFailOnError = false +} + +tasks.named("publish") { + dependsOn(sourceJar, javadocJar, zipNatives) +} + +// Define the artifacts we want to publish (the .pom will also be included since the Maven plugin is active) +publishing { + publications { + create("mavenJava") { + artifactId = "JNBullet" + groupId = project.group.toString() + + from(components["java"]) + artifact(sourceJar) + artifact(javadocJar) + artifact(zipNatives) + + pom.withXml { + asNode().apply { + appendNode("name", "JNBullet") + appendNode("description", "A Java Native Bullet Wrapper") + appendNode("url", "http://www.example.com/project") + (appendNode("licenses") as groovy.util.Node).apply { + (appendNode("license") as groovy.util.Node).apply { + appendNode("name", "The Apache License, Version 2.0") + appendNode("url", "http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + (appendNode("developers") as groovy.util.Node).apply { + (appendNode("developer") as groovy.util.Node).apply { + appendNode("id", "michaelpollind") + appendNode("name", "Michael Pollind") + appendNode("email", "mpollind@gmail.com") + } + } + (appendNode("scm") as groovy.util.Node).apply { + appendNode("connection", "https://github.com/MovingBlocks/JNBullet") + appendNode("developerConnection", "git@github.com:MovingBlocks/JNBullet.git") + appendNode("url", "https://github.com/MovingBlocks/JNBullet") + } + } + } + + repositories { + maven { + name = "TerasologyOrg" + + if (rootProject.hasProperty("publishRepo")) { + // This first option is good for local testing, you can set a full explicit target repo in gradle.properties + val publishRepo = rootProject.property("publishRepo") as String + url = uri("https://artifactory.terasology.io/artifactory/$publishRepo") + + logger.info("Changing PUBLISH repoKey set via Gradle property to {}", publishRepo) + } else { + // Support override from the environment to use a different target publish org + var deducedPublishRepo = System.getenv("PUBLISH_ORG") + if (deducedPublishRepo.isNullOrEmpty()) { + // If not then default + deducedPublishRepo = "libs" + } + + // Base final publish repo on whether we're building a snapshot or a release + deducedPublishRepo += if (project.version.toString().endsWith("SNAPSHOT")) { + "-snapshot-local" + } else { + "-release-local" + } + + logger.info("The final deduced publish repo is {}", deducedPublishRepo) + url = uri("https://artifactory.terasology.io/artifactory/$deducedPublishRepo") + } + + if (rootProject.hasProperty("mavenUser") && rootProject.hasProperty("mavenPass")) { + credentials { + username = rootProject.property("mavenUser") as String + password = rootProject.property("mavenPass") as String + } + authentication { + create("basic") + } + } + } + } + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1e922f407..c42672d95 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 6244baf9a..000000000 --- a/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -import groovy.io.FileType -rootProject.name = 'JNBullet' -include 'swig-src' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 000000000..8895d7e82 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "JNBullet" +include("swig-src") diff --git a/swig-src/build.gradle b/swig-src/build.gradle deleted file mode 100644 index 7461b8a2b..000000000 --- a/swig-src/build.gradle +++ /dev/null @@ -1,66 +0,0 @@ -ext { - swigTarget = ["linearmath","collision","dynamics","softbody","extras","inversedynamics"] -} - -swigTarget.each { module -> - tasks.create(name: "swig_"+"${module}", type: Exec) { - description = 'Swigging collision' - executable "swig" - args ("-java", - "-c++", - "-Wall", - "-Wextra", - "-fvirtual", - "-fastdispatch", - "-macroerrors", - "-package", - "com.badlogic.gdx.physics.bullet.${module}", - "-I$rootDir/natives/bullet3/src", - "-I$rootDir/natives/custom", - "-I$rootDir/natives/bullet3/Extras", - "-I$rootDir/natives/bullet3/Extras/Serialize", - "-o", "$rootDir/build/swig/${module}_wrap.cpp", - "-outdir", - "$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/${module}", - "$rootDir/swig-src/${module}/${module}.i") - - doFirst { - mkdir "$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/${module}" - mkdir "$rootDir/build/swig" - } - } -} - -task Swig{ - description = "Builds C++ bindings from java to Bullet3" - dependsOn swig_collision - dependsOn swig_dynamics - dependsOn swig_softbody - dependsOn swig_extras - dependsOn swig_inversedynamics - dependsOn swig_linearmath - doLast { - FileTree swig_tree = fileTree(dir: "$rootDir/build/swig", include: '*.cpp') - swig_tree.visit {element -> - println "$element.relativePath => $element.file" - String fileContents = element.file.text - } - } - -} - -task BuildClasses { - swigTarget.each { module -> - FileTree swig_visit = fileTree(dir: "$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/${module}", include: '*.java') - File outputFile = new File("$rootDir/swig-src/${module}", "classes.i"); - BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile,false)); - - swig_visit.visit { element -> - String classTarget = "$element.file.name".split("\\.")[0] - writer.write("SPECIFY_CLASS($classTarget, com.badlogic.gdx.physics.bullet.${module})\n") - } - writer.close() - } -} - - diff --git a/swig-src/build.gradle.kts b/swig-src/build.gradle.kts new file mode 100644 index 000000000..029accb83 --- /dev/null +++ b/swig-src/build.gradle.kts @@ -0,0 +1,69 @@ +import org.gradle.api.file.FileVisitDetails +import java.io.BufferedWriter +import java.io.File +import java.io.FileWriter + +val swigTarget = listOf("linearmath", "collision", "dynamics", "softbody", "extras", "inversedynamics") + +swigTarget.forEach { module -> + tasks.register("swig_$module") { + description = "Swigging collision" + executable = "swig" + args( + "-java", + "-c++", + "-Wall", + "-Wextra", + "-fvirtual", + "-fastdispatch", + "-macroerrors", + "-package", + "com.badlogic.gdx.physics.bullet.$module", + "-I$rootDir/natives/bullet3/src", + "-I$rootDir/natives/custom", + "-I$rootDir/natives/bullet3/Extras", + "-I$rootDir/natives/bullet3/Extras/Serialize", + "-o", "$rootDir/build/swig/${module}_wrap.cpp", + "-outdir", + "$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/$module", + "$rootDir/swig-src/$module/$module.i" + ) + + doFirst { + mkdir("$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/$module") + mkdir("$rootDir/build/swig") + } + } +} + +tasks.register("Swig") { + description = "Builds C++ bindings from java to Bullet3" + dependsOn("swig_collision") + dependsOn("swig_dynamics") + dependsOn("swig_softbody") + dependsOn("swig_extras") + dependsOn("swig_inversedynamics") + dependsOn("swig_linearmath") + doLast { + val swigTree = fileTree("$rootDir/build/swig") { include("*.cpp") } + swigTree.visit(closureOf { + println("$relativePath => $file") + @Suppress("UNUSED_VARIABLE") + val fileContents = file.readText() + }) + } +} + +tasks.register("BuildClasses") { + swigTarget.forEach { module -> + val swigVisit = fileTree("$rootDir/src/generated/java/com/badlogic/gdx/physics/bullet/$module") { include("*.java") } + val outputFile = File("$rootDir/swig-src/$module", "classes.i") + val writer = BufferedWriter(FileWriter(outputFile, false)) + + swigVisit.visit(closureOf { + val classTarget = file.name.split(".")[0] + writer.write("SPECIFY_CLASS($classTarget, com.badlogic.gdx.physics.bullet.$module)\n") + }) + writer.close() + } +}