From 32c31b577cc521b0f1e4af17fa07d7d0b1db4dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 15 Oct 2025 10:27:49 -0700 Subject: [PATCH 1/6] Inital scaffold for libprocessing ffi. --- app/build.gradle.kts | 170 +++--- build.gradle.kts | 13 + core/build.gradle.kts | 132 +++++ core/src/processing/core/NativeLibrary.java | 110 ++++ core/src/processing/webgpu/PWebGPU.java | 28 + core/test/processing/webgpu/PWebGPUTest.java | 15 + gradle/libs.versions.toml | 4 +- gradle/wrapper/gradle-wrapper.properties | 2 +- java/libraries/dxf/build.gradle.kts | 1 + libProcessing/Cargo.lock | 513 +++++++++++++++++++ libProcessing/ffi/Cargo.toml | 8 + libProcessing/ffi/build.rs | 23 + libProcessing/ffi/cbindgen.toml | 12 + libProcessing/ffi/include/processing.h | 17 + libProcessing/ffi/src/lib.rs | 18 +- libProcessing/renderer/src/lib.rs | 14 +- 16 files changed, 973 insertions(+), 107 deletions(-) create mode 100644 core/src/processing/core/NativeLibrary.java create mode 100644 core/src/processing/webgpu/PWebGPU.java create mode 100644 core/test/processing/webgpu/PWebGPUTest.java create mode 100644 libProcessing/ffi/build.rs create mode 100644 libProcessing/ffi/cbindgen.toml create mode 100644 libProcessing/ffi/include/processing.h diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0d3fcbd12d..f2615ce142 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,15 +1,94 @@ import org.gradle.internal.jvm.Jvm import org.gradle.internal.os.OperatingSystem import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform +import org.gradle.process.ExecOperations import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download import java.io.FileOutputStream import java.util.zip.ZipEntry import java.util.zip.ZipOutputStream +import javax.inject.Inject // TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload +abstract class SignResourcesTask : DefaultTask() { + @get:Inject + abstract val execOperations: ExecOperations + + @get:InputDirectory + abstract val resourcesPath: DirectoryProperty + + @TaskAction + fun signResources() { + val resourcesDir = resourcesPath.get().asFile + val jars = mutableListOf() + + // Copy Info.plist if present + project.fileTree(resourcesDir) + .matching { include("**/Info.plist") } + .singleOrNull() + ?.let { file -> + project.copy { + from(file) + into(resourcesDir) + } + } + + project.fileTree(resourcesDir) { + include("**/*.jar") + exclude("**/*.jar.tmp/**") + }.forEach { file -> + val tempDir = file.parentFile.resolve("${file.name}.tmp") + project.copy { + from(project.zipTree(file)) + into(tempDir) + } + file.delete() + jars.add(tempDir) + } + + project.fileTree(resourcesDir) { + include("**/bin/**") + include("**/*.jnilib") + include("**/*.dylib") + include("**/*aarch64*") + include("**/*x86_64*") + include("**/*ffmpeg*") + include("**/ffmpeg*/**") + exclude("jdk/**") + exclude("*.jar") + exclude("*.so") + exclude("*.dll") + }.forEach { file -> + execOperations.exec { + commandLine("codesign", "--timestamp", "--force", "--deep", "--options=runtime", "--sign", "Developer ID Application", file) + } + } + + jars.forEach { file -> + FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos -> + ZipOutputStream(fos).use { zos -> + file.walkTopDown().forEach { fileEntry -> + if (fileEntry.isFile) { + val zipEntryPath = fileEntry.relativeTo(file).path + val entry = ZipEntry(zipEntryPath) + zos.putNextEntry(entry) + fileEntry.inputStream().use { input -> + input.copyTo(zos) + } + zos.closeEntry() + } + } + } + } + file.deleteRecursively() + } + + File(resourcesDir, "Info.plist").delete() + } +} + plugins{ id("java") kotlin("jvm") version libs.versions.kotlin @@ -49,14 +128,17 @@ compose.desktop { application { mainClass = "processing.app.ProcessingKt" - jvmArgs(*listOf( - Pair("processing.version", rootProject.version), - Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE), - Pair("processing.contributions.source", "https://contributions.processing.org/contribs"), - Pair("processing.download.page", "https://processing.org/download/"), - Pair("processing.download.latest", "https://processing.org/download/latest.txt"), - Pair("processing.tutorials", "https://processing.org/tutorials/"), - ).map { "-D${it.first}=${it.second}" }.toTypedArray()) + jvmArgs( + "--enable-native-access=ALL-UNNAMED", // Required for Java 25 native library access + *listOf( + Pair("processing.version", rootProject.version), + Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE), + Pair("processing.contributions.source", "https://contributions.processing.org/contribs"), + Pair("processing.download.page", "https://processing.org/download/"), + Pair("processing.download.latest", "https://processing.org/download/latest.txt"), + Pair("processing.tutorials", "https://processing.org/tutorials/"), + ).map { "-D${it.first}=${it.second}" }.toTypedArray() + ) nativeDistributions{ modules("jdk.jdi", "java.compiler", "jdk.accessibility", "java.management.rmi", "java.scripting", "jdk.httpserver") @@ -421,82 +503,14 @@ tasks.register("includeProcessingResources"){ finalizedBy("signResources") } -tasks.register("signResources"){ +tasks.register("signResources") { onlyIf { OperatingSystem.current().isMacOsX && compose.desktop.application.nativeDistributions.macOS.signing.sign.get() } group = "compose desktop" - val resourcesPath = composeResources("") - - // find jars in the resources directory - val jars = mutableListOf() - doFirst{ - fileTree(resourcesPath) - .matching { include("**/Info.plist") } - .singleOrNull() - ?.let { file -> - copy { - from(file) - into(resourcesPath) - } - } - fileTree(resourcesPath) { - include("**/*.jar") - exclude("**/*.jar.tmp/**") - }.forEach { file -> - val tempDir = file.parentFile.resolve("${file.name}.tmp") - copy { - from(zipTree(file)) - into(tempDir) - } - file.delete() - jars.add(tempDir) - } - fileTree(resourcesPath){ - include("**/bin/**") - include("**/*.jnilib") - include("**/*.dylib") - include("**/*aarch64*") - include("**/*x86_64*") - include("**/*ffmpeg*") - include("**/ffmpeg*/**") - exclude("jdk/**") - exclude("*.jar") - exclude("*.so") - exclude("*.dll") - }.forEach{ file -> - exec { - commandLine("codesign", "--timestamp", "--force", "--deep","--options=runtime", "--sign", "Developer ID Application", file) - } - } - jars.forEach { file -> - FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos -> - ZipOutputStream(fos).use { zos -> - file.walkTopDown().forEach { fileEntry -> - if (fileEntry.isFile) { - // Calculate the relative path for the zip entry - val zipEntryPath = fileEntry.relativeTo(file).path - val entry = ZipEntry(zipEntryPath) - zos.putNextEntry(entry) - - // Copy file contents to the zip - fileEntry.inputStream().use { input -> - input.copyTo(zos) - } - zos.closeEntry() - } - } - } - } - - file.deleteRecursively() - } - file(composeResources("Info.plist")).delete() - } - - + resourcesPath.set(composeResources("")) } tasks.register("setExecutablePermissions") { description = "Sets executable permissions on binaries in Processing.app resources" diff --git a/build.gradle.kts b/build.gradle.kts index 8e7ad44a7a..06137398a7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,19 @@ plugins { // Can be deleted after the migration to Gradle is complete layout.buildDirectory = file(".build") +allprojects { + tasks.withType().configureEach { + sourceCompatibility = "24" + targetCompatibility = "24" + } + + tasks.withType().configureEach { + compilerOptions { + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24) + } + } +} + // Configure the dependencyUpdates task tasks { dependencyUpdates { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 8f7211b131..41d3de6bd5 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -35,6 +35,138 @@ dependencies { testImplementation(libs.junit) } +val osName = System.getProperty("os.name").lowercase() +val osArch = System.getProperty("os.arch").lowercase() + +val platformName = when { + osName.contains("mac") || osName.contains("darwin") -> "macos" + osName.contains("win") -> "windows" + osName.contains("linux") -> "linux" + else -> throw GradleException("Unsupported OS: $osName") +} + +val archName = when { + osArch.contains("aarch64") || osArch.contains("arm") -> "aarch64" + osArch.contains("x86_64") || osArch.contains("amd64") -> "x86_64" + else -> throw GradleException("Unsupported architecture: $osArch") +} + +val libExtension = when (platformName) { + "macos" -> "dylib" + "windows" -> "dll" + "linux" -> "so" + else -> throw GradleException("Unknown platform: $platformName") +} + +val libName = when (platformName) { + "windows" -> "processing.$libExtension" + else -> "libprocessing.$libExtension" +} + +val platformTarget = "$platformName-$archName" +val libProcessingDir = file("${project.rootDir}/libProcessing") +val rustTargetDir = file("$libProcessingDir/target") +val nativeOutputDir = file("${layout.buildDirectory.get()}/native/$platformTarget") + +val cargoPath = System.getenv("CARGO_HOME")?.let { "$it/bin/cargo" } + ?: "${System.getProperty("user.home")}/.cargo/bin/cargo" + +val buildRustRelease by tasks.registering(Exec::class) { + group = "rust" + description = "Build Rust FFI library in release mode for current platform" + + workingDir = libProcessingDir + commandLine = listOf(cargoPath, "build", "--release", "--manifest-path", "ffi/Cargo.toml") + + inputs.files(fileTree("$libProcessingDir/ffi/src")) + inputs.file("$libProcessingDir/ffi/Cargo.toml") + inputs.file("$libProcessingDir/Cargo.toml") + inputs.file("$libProcessingDir/ffi/build.rs") + inputs.file("$libProcessingDir/ffi/cbindgen.toml") + + outputs.file("$rustTargetDir/release/$libName") + outputs.file("$libProcessingDir/ffi/include/processing.h") + + doFirst { + logger.lifecycle("Building Rust library for $platformTarget...") + } +} + +val copyNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Copy processing library to build directory" + + dependsOn(buildRustRelease) + + from("$rustTargetDir/release") { + include("libprocessing.a") + include("libprocessing.$libExtension") + } + + into(nativeOutputDir) + + doFirst { + logger.lifecycle("Copying native libraries to $nativeOutputDir") + } +} + +val bundleNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Bundle native library into resources" + + dependsOn(copyNativeLibs) + + from(nativeOutputDir) + into("${sourceSets.main.get().output.resourcesDir}/native/$platformTarget") + + doFirst { + logger.lifecycle("Bundling libraries for $platformTarget into resources") + } +} + +val jextractPath = "${System.getProperty("user.home")}/jextract-22/bin/jextract" +val generatedJavaDir = file("${layout.buildDirectory.get()}/generated/sources/jextract/java") +val headerFile = file("$libProcessingDir/ffi/include/processing.h") + +sourceSets.main { + java.srcDirs(generatedJavaDir) +} + +val generateJavaBindings by tasks.registering(Exec::class) { + group = "rust" + description = "Generate Java bindings from libProcessing headers using jextract" + + dependsOn(buildRustRelease) + + inputs.file(headerFile) + + outputs.dir(generatedJavaDir) + + doFirst { + generatedJavaDir.mkdirs() + logger.lifecycle("Generating Java bindings from $headerFile...") + } + + commandLine = listOf( + jextractPath, + "--output", generatedJavaDir.absolutePath, + "--target-package", "processing.ffi", + headerFile.absolutePath + ) +} + +tasks.named("compileJava") { + dependsOn(generateJavaBindings) +} + +tasks.named("compileKotlin") { + dependsOn(generateJavaBindings) +} + +tasks.named("processResources") { + dependsOn(bundleNativeLibs) +} + mavenPublishing{ publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL) signAllPublications() diff --git a/core/src/processing/core/NativeLibrary.java b/core/src/processing/core/NativeLibrary.java new file mode 100644 index 0000000000..15b7331c2b --- /dev/null +++ b/core/src/processing/core/NativeLibrary.java @@ -0,0 +1,110 @@ +package processing.core; + +import java.io.*; +import java.nio.file.*; + +/** + * Handles loading of Processing's native Rust library (libprocessing). + */ +public class NativeLibrary { + private static boolean loaded = false; + private static Throwable loadError = null; + + private static final String LIBRARY_NAME = "processing"; + + // Platform + private static final String OS_NAME = System.getProperty("os.name").toLowerCase(); + private static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(); + + private static final String platform; + private static final String architecture; + private static final String libraryExtension; + + static { + // platform + if (OS_NAME.contains("mac") || OS_NAME.contains("darwin")) { + platform = "macos"; + libraryExtension = "dylib"; + } else if (OS_NAME.contains("win")) { + platform = "windows"; + libraryExtension = "dll"; + } else if (OS_NAME.contains("linux")) { + platform = "linux"; + libraryExtension = "so"; + } else { + throw new UnsupportedOperationException("Unsupported OS: " + OS_NAME); + } + + // architecture + if (OS_ARCH.contains("aarch64") || OS_ARCH.contains("arm")) { + architecture = "aarch64"; + } else if (OS_ARCH.contains("x86_64") || OS_ARCH.contains("amd64")) { + architecture = "x86_64"; + } else { + throw new UnsupportedOperationException("Unsupported architecture: " + OS_ARCH); + } + + // Load the dll + try { + loadNativeLibrary(); + loaded = true; + } catch (Throwable e) { + loadError = e; + System.err.println("Warning: Failed to load Processing native library: " + e.getMessage()); + } + } + + /** + * Ensures the native library is loaded. Throws if loading failed. + */ + public static void ensureLoaded() { + if (!loaded) { + throw new RuntimeException("Native library failed to load", loadError); + } + } + + /** + * Returns whether the native library was successfully loaded. + */ + public static boolean isLoaded() { + return loaded; + } + + /** + * Returns the platform string (e.g., "macos-aarch64"). + */ + public static String getPlatform() { + return platform + "-" + architecture; + } + + /** + * Extracts and loads the native library from JAR resources. + */ + private static void loadNativeLibrary() throws IOException { + String platformTarget = platform + "-" + architecture; + String libraryFileName = "lib" + LIBRARY_NAME + "." + libraryExtension; + String resourcePath = "/native/" + platformTarget + "/" + libraryFileName; + + // check classloader for resource in jar + InputStream libraryStream = NativeLibrary.class.getResourceAsStream(resourcePath); + if (libraryStream == null) { + throw new FileNotFoundException( + "Native library not found in JAR: " + resourcePath + + " (platform: " + platformTarget + ")" + ); + } + + // extract + Path tempDir = Files.createTempDirectory("processing-native-"); + tempDir.toFile().deleteOnExit(); + + Path libraryPath = tempDir.resolve(libraryFileName); + Files.copy(libraryStream, libraryPath, StandardCopyOption.REPLACE_EXISTING); + libraryStream.close(); + + libraryPath.toFile().deleteOnExit(); + + // load! + System.load(libraryPath.toAbsolutePath().toString()); + } +} diff --git a/core/src/processing/webgpu/PWebGPU.java b/core/src/processing/webgpu/PWebGPU.java new file mode 100644 index 0000000000..304b5b26d1 --- /dev/null +++ b/core/src/processing/webgpu/PWebGPU.java @@ -0,0 +1,28 @@ +package processing.webgpu; + +import processing.core.NativeLibrary; +import processing.ffi.processing_h; + +/** + * PWebGPU provides the native interface layer for libProcessing's WebGPU support. + */ +public class PWebGPU { + + static { + NativeLibrary.ensureLoaded(); + } + + /** + * Ensure the native library is loaded. + */ + public static void ensureLoaded() { + NativeLibrary.ensureLoaded(); + } + + /** + * It's just math, silly! + */ + public static long add(long left, long right) { + return processing_h.processing_add(left, right); + } +} diff --git a/core/test/processing/webgpu/PWebGPUTest.java b/core/test/processing/webgpu/PWebGPUTest.java new file mode 100644 index 0000000000..4b77d7aa74 --- /dev/null +++ b/core/test/processing/webgpu/PWebGPUTest.java @@ -0,0 +1,15 @@ +package processing.webgpu; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * Tests for the PWebGPU native interface. + */ +public class PWebGPUTest { + @Test + public void testAddFunction() { + long result = PWebGPU.add(2, 2); + assertEquals("2 + 2 should equal 4", 4L, result); + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 050502f4ca..3b7e92605f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -kotlin = "2.0.20" -compose-plugin = "1.7.1" +kotlin = "2.3.0-Beta1" +compose-plugin = "1.9.0" jogl = "2.5.0" antlr = "4.13.2" jupiter = "5.12.0" diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 94113f200e..2e1113280e 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-8.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/java/libraries/dxf/build.gradle.kts b/java/libraries/dxf/build.gradle.kts index cf4e3f5074..eb8326b5d5 100644 --- a/java/libraries/dxf/build.gradle.kts +++ b/java/libraries/dxf/build.gradle.kts @@ -12,6 +12,7 @@ sourceSets { repositories{ mavenCentral() maven("https://jogamp.org/deployment/maven/") + maven("https://maven.pkg.jetbrains.space/public/p/kotlin/p/kotlin/bootstrap") // Kotlin EAP repository } dependencies{ diff --git a/libProcessing/Cargo.lock b/libProcessing/Cargo.lock index 331701f444..8611d649c2 100644 --- a/libProcessing/Cargo.lock +++ b/libProcessing/Cargo.lock @@ -2,14 +2,527 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "cbindgen" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975982cdb7ad6a142be15bdf84aea7ec6a9e5d4d797c004d43185b24cfe4e684" +dependencies = [ + "clap", + "heck", + "indexmap", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "tempfile", + "toml", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "clap" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "ffi" version = "0.1.0" +dependencies = [ + "cbindgen", + "renderer", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libProcessing" version = "0.1.0" +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "renderer" version = "0.1.0" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/libProcessing/ffi/Cargo.toml b/libProcessing/ffi/Cargo.toml index 68c7917cd9..243f499d19 100644 --- a/libProcessing/ffi/Cargo.toml +++ b/libProcessing/ffi/Cargo.toml @@ -3,4 +3,12 @@ name = "ffi" version = "0.1.0" edition = "2024" +[lib] +name = "processing" +crate-type = ["cdylib"] + [dependencies] +renderer = { path = "../renderer" } + +[build-dependencies] +cbindgen = "0.29" diff --git a/libProcessing/ffi/build.rs b/libProcessing/ffi/build.rs new file mode 100644 index 0000000000..b9dcb3d616 --- /dev/null +++ b/libProcessing/ffi/build.rs @@ -0,0 +1,23 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let output_dir = PathBuf::from(&crate_dir).join("include"); + + std::fs::create_dir_all(&output_dir).expect("Failed to create include directory"); + + let output_file = output_dir.join("processing.h"); + let config_path = PathBuf::from(&crate_dir).join("cbindgen.toml"); + + cbindgen::Builder::new() + .with_config(cbindgen::Config::from_file(&config_path).expect("Failed to load cbindgen.toml")) + .with_crate(&crate_dir) + .generate() + .expect("Unable to generate bindings") + .write_to_file(&output_file); + + println!("cargo:rerun-if-changed=src/lib.rs"); + println!("cargo:rerun-if-changed=cbindgen.toml"); + println!("cargo:warning=Generated header at: {}", output_file.display()); +} diff --git a/libProcessing/ffi/cbindgen.toml b/libProcessing/ffi/cbindgen.toml new file mode 100644 index 0000000000..923b8ac566 --- /dev/null +++ b/libProcessing/ffi/cbindgen.toml @@ -0,0 +1,12 @@ +language = "C" +pragma_once = true +include_guard = "PROCESSING_H" +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +include_version = true +documentation = true +documentation_style = "c99" + +[export] +# Export all + +[export.rename] \ No newline at end of file diff --git a/libProcessing/ffi/include/processing.h b/libProcessing/ffi/include/processing.h new file mode 100644 index 0000000000..32b7ab01e0 --- /dev/null +++ b/libProcessing/ffi/include/processing.h @@ -0,0 +1,17 @@ +#ifndef PROCESSING_H +#define PROCESSING_H + +#pragma once + +/* Generated with cbindgen:0.29.0 */ + +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + +#include +#include +#include +#include + +uint64_t processing_add(uint64_t left, uint64_t right); + +#endif /* PROCESSING_H */ diff --git a/libProcessing/ffi/src/lib.rs b/libProcessing/ffi/src/lib.rs index b93cf3ffd9..9381e76b59 100644 --- a/libProcessing/ffi/src/lib.rs +++ b/libProcessing/ffi/src/lib.rs @@ -1,14 +1,4 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +#[unsafe(no_mangle)] +pub extern "C" fn processing_add(left: u64, right: u64) -> u64 { + renderer::add(left, right) +} \ No newline at end of file diff --git a/libProcessing/renderer/src/lib.rs b/libProcessing/renderer/src/lib.rs index b93cf3ffd9..048c97f076 100644 --- a/libProcessing/renderer/src/lib.rs +++ b/libProcessing/renderer/src/lib.rs @@ -1,14 +1,4 @@ pub fn add(left: u64, right: u64) -> u64 { + println!("Adding {} and {} in Rust", left, right); left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +} \ No newline at end of file From a596ad2f0639bb8c5670dc3535864632d706d9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 15 Oct 2025 10:33:32 -0700 Subject: [PATCH 2/6] Remove EAP. --- java/libraries/dxf/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/java/libraries/dxf/build.gradle.kts b/java/libraries/dxf/build.gradle.kts index eb8326b5d5..cf4e3f5074 100644 --- a/java/libraries/dxf/build.gradle.kts +++ b/java/libraries/dxf/build.gradle.kts @@ -12,7 +12,6 @@ sourceSets { repositories{ mavenCentral() maven("https://jogamp.org/deployment/maven/") - maven("https://maven.pkg.jetbrains.space/public/p/kotlin/p/kotlin/bootstrap") // Kotlin EAP repository } dependencies{ From 9ae1d017bda2bd7aee43957edd3bbe7a90225eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 15 Oct 2025 10:49:31 -0700 Subject: [PATCH 3/6] Update docs. --- BUILD.md | 52 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/BUILD.md b/BUILD.md index a7176776a2..e44112537a 100644 --- a/BUILD.md +++ b/BUILD.md @@ -12,9 +12,9 @@ First, [download the IntelliJ IDEA Community Edition](https://www.jetbrains.com/ 1. Clone the Processing4 repository to your machine locally 1. Open the cloned repository in IntelliJ IDEA CE 1. When prompted, select **Trust Project**. You can preview the project in Safe Mode but you won't be able to build Processing. -1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 17. +1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 25. 1. In the main menu, go to File > Project Structure > Project Settings > Project. -1. In the SDK Dropdown option, select a JDK version 17 or Download the jdk +1. In the SDK Dropdown option, select a JDK version 25 or Download the jdk 1. Click the green Run Icon in the top right of the window. This is also where you can find the option to debug Processing. 1. Logs can be found in the `Build` or `Debug` pane on the bottom left of the window @@ -46,18 +46,43 @@ If you don't have them installed, you will need to install [Git](https://git-scm cd processing4 ``` -2. **Install Temurin JDK 17:** - - Download and install the appropriate version for your platform: +2. **Install Temurin JDK 25:** + +Processing requires the Temurin distribution of OpenJDK. - - [Linux (x86)](https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_x64_linux_hotspot_17.0.15_6.tar.gz) - - [macOS (Apple Silicon)](https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.15%2B6/OpenJDK17U-jdk_aarch64_mac_hotspot_17.0.15_6.pkg) - - [Other platforms](https://adoptium.net/temurin/releases/?package=jdk&version=17&os=any&arch=any) +You can download it from [Adoptium](https://adoptium.net/), from [GitHub releases](https://github.com/adoptium/temurin25-binaries/releases), +or find it in the package manager for your platform. + +### macOS: +```bash +brew install --cask temurin@25 +```` + +### Windows (using winget): +```bash +winget install --id=EclipseAdoptium.Temurin.25.JDK -e +``` + +### SDKMAN! + +[SDKMAN!](https://sdkman.io/) is a useful tool for developers working on multiple versions of the JVM. + +## Install `jextract` + +`jextract` is a tool included in the JDK that generates Java bindings from C header files. +It is required to build Processing when using WebGPU. You can download it [here](https://jdk.java.net/jextract/) +or install it using SDKMAN!: + +```bash +sdk install jextract +```` 3. **Set the `JAVA_HOME` environment variable:** +It may be necessary to set the `JAVA_HOME` environment variable to point to your Temurin JDK 25 installation. + ```bash - export JAVA_HOME=/path/to/temurin/jdk-17.0.15+6/ + export JAVA_HOME=/path/to/temurin/jdk-25/ ``` ### Build, Run, and Package Processing @@ -136,18 +161,18 @@ If you are specifically trying to run the `Processing CLI`, you can test command If you’re building Processing using IntelliJ IDEA and something’s not working, here are a few things that might help: -### Use the Correct JDK (temurin-17) +### Use the Correct JDK (temurin-25) -Make sure IntelliJ is using **temurin-17**, not another version. Some users have reported issues with ms-17. +Make sure IntelliJ is using **temurin-25**, not another version. 1. Go to **File > Project Structure > Project** -2. Set the **Project SDK** to: `temurin-17 java version "17.0.15"` +2. Set the **Project SDK** to: `temurin-25"` ![JDK Selection](.github/media/troubleshooting-Intellij-setting-djk-version-manually.png) If it is not already installed, you can download it by: 1. Clicking the SDK input field and then selecting the `Download JDK...` option from the menu -2. Select Version: `17`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)` +2. Select Version: `25`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)` ![JDK Download](.github/media/troubleshooting-Intellij-download-jdk.png) @@ -155,7 +180,6 @@ If it is not already installed, you can download it by: Now go back to your main window and 1. Click the green Run Icon in the top right of the window. - ### “Duplicate content roots detected” You may see this warning in IntelliJ: From 8f2542b84941899d440a0ea68a0ab1c2f519ac87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Thu, 16 Oct 2025 13:01:44 -0700 Subject: [PATCH 4/6] Factor out gradle utils. Add flag for disabling webgpu and enforcing android source level compat. --- .gitignore | 2 + app/build.gradle.kts | 83 +------- build.gradle.kts | 14 +- buildSrc/build.gradle.kts | 7 + .../processing/gradle/CargoBuildTask.kt | 56 +++++ .../processing/gradle/CargoCleanTask.kt | 38 ++++ .../processing/gradle/DownloadJextractTask.kt | 60 ++++++ .../gradle/GenerateJextractBindingsTask.kt | 49 +++++ .../kotlin/processing/gradle/JextractUtils.kt | 29 +++ .../kotlin/processing/gradle/PlatformUtils.kt | 53 +++++ .../processing/gradle/SignResourcesTask.kt | 108 ++++++++++ core/build.gradle.kts | 191 +++++++++--------- 12 files changed, 505 insertions(+), 185 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/DownloadJextractTask.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/GenerateJextractBindingsTask.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/JextractUtils.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/PlatformUtils.kt create mode 100644 buildSrc/src/main/kotlin/processing/gradle/SignResourcesTask.kt diff --git a/.gitignore b/.gitignore index 67057f9425..6a81e3cf74 100644 --- a/.gitignore +++ b/.gitignore @@ -124,3 +124,5 @@ generated/ /app/windows/obj /java/gradle/build /java/gradle/example/.processing + +libProcessing/ffi/include/* \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f2615ce142..0dd13783ca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,94 +1,13 @@ import org.gradle.internal.jvm.Jvm import org.gradle.internal.os.OperatingSystem import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform -import org.gradle.process.ExecOperations import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download -import java.io.FileOutputStream -import java.util.zip.ZipEntry -import java.util.zip.ZipOutputStream -import javax.inject.Inject +import processing.gradle.SignResourcesTask // TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload -abstract class SignResourcesTask : DefaultTask() { - @get:Inject - abstract val execOperations: ExecOperations - - @get:InputDirectory - abstract val resourcesPath: DirectoryProperty - - @TaskAction - fun signResources() { - val resourcesDir = resourcesPath.get().asFile - val jars = mutableListOf() - - // Copy Info.plist if present - project.fileTree(resourcesDir) - .matching { include("**/Info.plist") } - .singleOrNull() - ?.let { file -> - project.copy { - from(file) - into(resourcesDir) - } - } - - project.fileTree(resourcesDir) { - include("**/*.jar") - exclude("**/*.jar.tmp/**") - }.forEach { file -> - val tempDir = file.parentFile.resolve("${file.name}.tmp") - project.copy { - from(project.zipTree(file)) - into(tempDir) - } - file.delete() - jars.add(tempDir) - } - - project.fileTree(resourcesDir) { - include("**/bin/**") - include("**/*.jnilib") - include("**/*.dylib") - include("**/*aarch64*") - include("**/*x86_64*") - include("**/*ffmpeg*") - include("**/ffmpeg*/**") - exclude("jdk/**") - exclude("*.jar") - exclude("*.so") - exclude("*.dll") - }.forEach { file -> - execOperations.exec { - commandLine("codesign", "--timestamp", "--force", "--deep", "--options=runtime", "--sign", "Developer ID Application", file) - } - } - - jars.forEach { file -> - FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos -> - ZipOutputStream(fos).use { zos -> - file.walkTopDown().forEach { fileEntry -> - if (fileEntry.isFile) { - val zipEntryPath = fileEntry.relativeTo(file).path - val entry = ZipEntry(zipEntryPath) - zos.putNextEntry(entry) - fileEntry.inputStream().use { input -> - input.copyTo(zos) - } - zos.closeEntry() - } - } - } - } - file.deleteRecursively() - } - - File(resourcesDir, "Info.plist").delete() - } -} - plugins{ id("java") kotlin("jvm") version libs.versions.kotlin diff --git a/build.gradle.kts b/build.gradle.kts index 06137398a7..90920c22e3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,15 +12,23 @@ plugins { // Can be deleted after the migration to Gradle is complete layout.buildDirectory = file(".build") +val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: true + allprojects { tasks.withType().configureEach { - sourceCompatibility = "24" - targetCompatibility = "24" + val javaVersion = if (project.name == "core" && enableWebGPU) "24" else "17" + sourceCompatibility = javaVersion + targetCompatibility = javaVersion } tasks.withType().configureEach { compilerOptions { - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24) + val kotlinTarget = if (project.name == "core" && enableWebGPU) { + org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24 + } else { + org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 + } + jvmTarget.set(kotlinTarget) } } } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000000..876c922b22 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt b/buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt new file mode 100644 index 0000000000..0b73d75ac6 --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt @@ -0,0 +1,56 @@ +package processing.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations +import javax.inject.Inject + +abstract class CargoBuildTask : DefaultTask() { + + @get:Inject + abstract val execOperations: ExecOperations + + @get:InputDirectory + abstract val cargoWorkspaceDir: DirectoryProperty + + @get:Input + abstract val manifestPath: Property + + @get:Input + abstract val release: Property + + @get:Input + abstract val cargoPath: Property + + @get:OutputFile + abstract val outputLibrary: RegularFileProperty + + init { + group = "rust" + description = "Builds Rust library using cargo" + + // release by default + release.convention(true) + } + + @TaskAction + fun build() { + val buildType = if (release.get()) "release" else "debug" + logger.lifecycle("Building Rust library ($buildType mode)...") + + val args = mutableListOf("build") + if (release.get()) { + args.add("--release") + } + args.add("--manifest-path") + args.add(manifestPath.get()) + + execOperations.exec { + workingDir = cargoWorkspaceDir.get().asFile + commandLine = listOf(cargoPath.get()) + args + } + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt b/buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt new file mode 100644 index 0000000000..1caf9133bf --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt @@ -0,0 +1,38 @@ +package processing.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations +import javax.inject.Inject + +abstract class CargoCleanTask : DefaultTask() { + + @get:Inject + abstract val execOperations: ExecOperations + + @get:InputDirectory + abstract val cargoWorkspaceDir: DirectoryProperty + + @get:Input + abstract val manifestPath: Property + + @get:Input + abstract val cargoPath: Property + + init { + group = "rust" + description = "Cleans Rust build artifacts" + } + + @TaskAction + fun clean() { + logger.lifecycle("Cleaning Rust build artifacts...") + + execOperations.exec { + workingDir = cargoWorkspaceDir.get().asFile + commandLine(cargoPath.get(), "clean", "--manifest-path", manifestPath.get()) + } + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/DownloadJextractTask.kt b/buildSrc/src/main/kotlin/processing/gradle/DownloadJextractTask.kt new file mode 100644 index 0000000000..254195a38d --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/DownloadJextractTask.kt @@ -0,0 +1,60 @@ +package processing.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import java.net.URI + +abstract class DownloadJextractTask : DefaultTask() { + + @get:Input + abstract val jextractVersion: Property + + @get:Input + abstract val platform: Property + + @get:OutputDirectory + abstract val jextractDir: DirectoryProperty + + @get:Internal + abstract val downloadTarball: RegularFileProperty + + init { + group = "rust" + description = "Downloads and extracts jextract for the current platform" + } + + @TaskAction + fun download() { + val version = jextractVersion.get() + val plat = platform.get() + val fileName = "openjdk-$version" + "_${plat}_bin.tar.gz" + val downloadUrl = "https://download.java.net/java/early_access/jextract/22/6/$fileName" + val tarFile = downloadTarball.get().asFile + + if (!tarFile.exists()) { + logger.lifecycle("Downloading jextract from $downloadUrl") + try { + tarFile.outputStream().use { output -> + URI.create(downloadUrl).toURL().openStream().use { input -> + input.copyTo(output) + } + } + } catch (e: Exception) { + throw GradleException("Failed to download jextract: ${e.message}", e) + } + } + + val extractDir = jextractDir.get().asFile + logger.lifecycle("Extracting jextract to ${extractDir.parent}") + project.copy { + from(project.tarTree(tarFile)) + into(extractDir.parent) + } + + logger.lifecycle("jextract extracted to: $extractDir") + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/GenerateJextractBindingsTask.kt b/buildSrc/src/main/kotlin/processing/gradle/GenerateJextractBindingsTask.kt new file mode 100644 index 0000000000..22fc9c240c --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/GenerateJextractBindingsTask.kt @@ -0,0 +1,49 @@ +package processing.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations +import javax.inject.Inject + +abstract class GenerateJextractBindingsTask : DefaultTask() { + + @get:Inject + abstract val execOperations: ExecOperations + + @get:InputFile + abstract val headerFile: RegularFileProperty + + @get:OutputDirectory + abstract val outputDirectory: DirectoryProperty + + @get:Input + abstract val targetPackage: Property + + @get:Input + abstract val jextractPath: Property + + init { + group = "rust" + description = "Generates Java Panama FFM bindings from C headers" + } + + @TaskAction + fun generate() { + val outDir = outputDirectory.get().asFile + outDir.mkdirs() + + logger.lifecycle("Generating Java bindings from ${headerFile.get().asFile}...") + + execOperations.exec { + commandLine( + jextractPath.get(), + "--output", outDir.absolutePath, + "--target-package", targetPackage.get(), + headerFile.get().asFile.absolutePath + ) + } + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/JextractUtils.kt b/buildSrc/src/main/kotlin/processing/gradle/JextractUtils.kt new file mode 100644 index 0000000000..505a222a59 --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/JextractUtils.kt @@ -0,0 +1,29 @@ +package processing.gradle + +object JextractUtils { + fun findUserJextract(): String? { + val jextractHome = System.getenv("JEXTRACT_HOME") ?: return null + + val isWindows = System.getProperty("os.name").lowercase().contains("windows") + val path = if (isWindows) { + "$jextractHome/bin/jextract.bat" + } else { + "$jextractHome/bin/jextract" + } + + val file = java.io.File(path) + if (file.exists()) { + return path + } + + return null + } + + fun getExecutableName(): String { + return if (System.getProperty("os.name").lowercase().contains("windows")) { + "jextract.bat" + } else { + "jextract" + } + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/PlatformUtils.kt b/buildSrc/src/main/kotlin/processing/gradle/PlatformUtils.kt new file mode 100644 index 0000000000..f442dba985 --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/PlatformUtils.kt @@ -0,0 +1,53 @@ +package processing.gradle + +import org.gradle.api.GradleException + +object PlatformUtils { + data class Platform( + val os: String, + val arch: String, + val libExtension: String, + val target: String + ) { + val libName: String + get() = if (os == "windows") "processing.$libExtension" else "libprocessing.$libExtension" + + val jextractPlatform: String + get() { + val jextractArch = if (arch == "x86_64") "x64" else arch + return "$os-$jextractArch" + } + } + + fun detect(): Platform { + val osName = System.getProperty("os.name").lowercase() + val osArch = System.getProperty("os.arch").lowercase() + + val os = when { + osName.contains("mac") || osName.contains("darwin") -> "macos" + osName.contains("win") -> "windows" + osName.contains("linux") -> "linux" + else -> throw GradleException("Unsupported OS: $osName") + } + + val arch = when { + osArch.contains("aarch64") || osArch.contains("arm") -> "aarch64" + osArch.contains("x86_64") || osArch.contains("amd64") -> "x86_64" + else -> throw GradleException("Unsupported architecture: $osArch") + } + + val libExtension = when (os) { + "macos" -> "dylib" + "windows" -> "dll" + "linux" -> "so" + else -> throw GradleException("Unknown platform: $os") + } + + return Platform(os, arch, libExtension, "$os-$arch") + } + + fun getCargoPath(): String { + return System.getenv("CARGO_HOME")?.let { "$it/bin/cargo" } + ?: "${System.getProperty("user.home")}/.cargo/bin/cargo" + } +} diff --git a/buildSrc/src/main/kotlin/processing/gradle/SignResourcesTask.kt b/buildSrc/src/main/kotlin/processing/gradle/SignResourcesTask.kt new file mode 100644 index 0000000000..91be783ea3 --- /dev/null +++ b/buildSrc/src/main/kotlin/processing/gradle/SignResourcesTask.kt @@ -0,0 +1,108 @@ +package processing.gradle + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.process.ExecOperations +import java.io.File +import java.io.FileOutputStream +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream +import javax.inject.Inject + +abstract class SignResourcesTask : DefaultTask() { + + @get:Inject + abstract val execOperations: ExecOperations + + @get:InputDirectory + abstract val resourcesPath: DirectoryProperty + + init { + group = "compose desktop" + description = "Signs macOS resources (binaries and libraries) for distribution" + } + + @TaskAction + fun signResources() { + val resourcesDir = resourcesPath.get().asFile + val jars = mutableListOf() + + // Copy Info.plist if present + project.fileTree(resourcesDir) + .matching { include("**/Info.plist") } + .singleOrNull() + ?.let { file -> + project.copy { + from(file) + into(resourcesDir) + } + } + + // Extract JARs to temporary directories for signing + project.fileTree(resourcesDir) { + include("**/*.jar") + exclude("**/*.jar.tmp/**") + }.forEach { file -> + val tempDir = file.parentFile.resolve("${file.name}.tmp") + project.copy { + from(project.zipTree(file)) + into(tempDir) + } + file.delete() + jars.add(tempDir) + } + + // Sign all binaries and native libraries + project.fileTree(resourcesDir) { + include("**/bin/**") + include("**/*.jnilib") + include("**/*.dylib") + include("**/*aarch64*") + include("**/*x86_64*") + include("**/*ffmpeg*") + include("**/ffmpeg*/**") + exclude("jdk/**") + exclude("*.jar") + exclude("*.so") + exclude("*.dll") + }.forEach { file -> + execOperations.exec { + commandLine( + "codesign", + "--timestamp", + "--force", + "--deep", + "--options=runtime", + "--sign", + "Developer ID Application", + file + ) + } + } + + // Repackage JARs after signing + jars.forEach { file -> + FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos -> + ZipOutputStream(fos).use { zos -> + file.walkTopDown().forEach { fileEntry -> + if (fileEntry.isFile) { + val zipEntryPath = fileEntry.relativeTo(file).path + val entry = ZipEntry(zipEntryPath) + zos.putNextEntry(entry) + fileEntry.inputStream().use { input -> + input.copyTo(zos) + } + zos.closeEntry() + } + } + } + } + file.deleteRecursively() + } + + // Clean up Info.plist + File(resourcesDir, "Info.plist").delete() + } +} diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 41d3de6bd5..30a79fcc44 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,4 +1,5 @@ import com.vanniktech.maven.publish.SonatypeHost +import processing.gradle.* plugins { id("java") @@ -11,10 +12,16 @@ repositories { maven { url = uri("https://jogamp.org/deployment/maven") } } +val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: true + sourceSets{ main{ java{ srcDirs("src") + if (!enableWebGPU) { + exclude("processing/webgpu/**") + exclude("processing/ffi/**") + } } resources{ srcDirs("src") @@ -35,136 +42,120 @@ dependencies { testImplementation(libs.junit) } -val osName = System.getProperty("os.name").lowercase() -val osArch = System.getProperty("os.arch").lowercase() - -val platformName = when { - osName.contains("mac") || osName.contains("darwin") -> "macos" - osName.contains("win") -> "windows" - osName.contains("linux") -> "linux" - else -> throw GradleException("Unsupported OS: $osName") -} - -val archName = when { - osArch.contains("aarch64") || osArch.contains("arm") -> "aarch64" - osArch.contains("x86_64") || osArch.contains("amd64") -> "x86_64" - else -> throw GradleException("Unsupported architecture: $osArch") -} - -val libExtension = when (platformName) { - "macos" -> "dylib" - "windows" -> "dll" - "linux" -> "so" - else -> throw GradleException("Unknown platform: $platformName") -} - -val libName = when (platformName) { - "windows" -> "processing.$libExtension" - else -> "libprocessing.$libExtension" -} +if (enableWebGPU) { + val currentPlatform = PlatformUtils.detect() + val libProcessingDir = file("${project.rootDir}/libProcessing") + val rustTargetDir = file("$libProcessingDir/target") + val nativeOutputDir = file("${layout.buildDirectory.get()}/native/${currentPlatform.target}") + + val buildRustRelease by tasks.registering(CargoBuildTask::class) { + cargoWorkspaceDir.set(libProcessingDir) + manifestPath.set("ffi/Cargo.toml") + release.set(true) + cargoPath.set(PlatformUtils.getCargoPath()) + outputLibrary.set(file("$rustTargetDir/release/${currentPlatform.libName}")) + + inputs.files(fileTree("$libProcessingDir/ffi/src")) + inputs.file("$libProcessingDir/ffi/Cargo.toml") + inputs.file("$libProcessingDir/ffi/build.rs") + inputs.file("$libProcessingDir/ffi/cbindgen.toml") + inputs.files(fileTree("$libProcessingDir/renderer/src")) + inputs.file("$libProcessingDir/renderer/Cargo.toml") + inputs.file("$libProcessingDir/Cargo.toml") + outputs.file("$libProcessingDir/ffi/include/processing.h") + } -val platformTarget = "$platformName-$archName" -val libProcessingDir = file("${project.rootDir}/libProcessing") -val rustTargetDir = file("$libProcessingDir/target") -val nativeOutputDir = file("${layout.buildDirectory.get()}/native/$platformTarget") + val copyNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Copy processing library to build directory" -val cargoPath = System.getenv("CARGO_HOME")?.let { "$it/bin/cargo" } - ?: "${System.getProperty("user.home")}/.cargo/bin/cargo" + dependsOn(buildRustRelease) -val buildRustRelease by tasks.registering(Exec::class) { - group = "rust" - description = "Build Rust FFI library in release mode for current platform" + from("$rustTargetDir/release") { + include(currentPlatform.libName) + } - workingDir = libProcessingDir - commandLine = listOf(cargoPath, "build", "--release", "--manifest-path", "ffi/Cargo.toml") + into(nativeOutputDir) + } - inputs.files(fileTree("$libProcessingDir/ffi/src")) - inputs.file("$libProcessingDir/ffi/Cargo.toml") - inputs.file("$libProcessingDir/Cargo.toml") - inputs.file("$libProcessingDir/ffi/build.rs") - inputs.file("$libProcessingDir/ffi/cbindgen.toml") + val bundleNativeLibs by tasks.registering(Copy::class) { + group = "rust" + description = "Bundle native library into resources" - outputs.file("$rustTargetDir/release/$libName") - outputs.file("$libProcessingDir/ffi/include/processing.h") + dependsOn(copyNativeLibs) - doFirst { - logger.lifecycle("Building Rust library for $platformTarget...") + from(nativeOutputDir) + into("${sourceSets.main.get().output.resourcesDir}/native/${currentPlatform.target}") } -} -val copyNativeLibs by tasks.registering(Copy::class) { - group = "rust" - description = "Copy processing library to build directory" + val cleanRust by tasks.registering(CargoCleanTask::class) { + cargoWorkspaceDir.set(libProcessingDir) + manifestPath.set("ffi/Cargo.toml") + cargoPath.set(PlatformUtils.getCargoPath()) - dependsOn(buildRustRelease) + mustRunAfter(buildRustRelease) + } - from("$rustTargetDir/release") { - include("libprocessing.a") - include("libprocessing.$libExtension") + tasks.named("clean") { + dependsOn(cleanRust) } - into(nativeOutputDir) + val generatedJavaDir = file("${layout.buildDirectory.get()}/generated/sources/jextract/java") - doFirst { - logger.lifecycle("Copying native libraries to $nativeOutputDir") + sourceSets.main { + java.srcDirs(generatedJavaDir) } -} -val bundleNativeLibs by tasks.registering(Copy::class) { - group = "rust" - description = "Bundle native library into resources" + val jextractVersionString = "22-jextract+6-47" + val jextractDirectory = file("${gradle.gradleUserHomeDir}/jextract-22") + val jextractTarballFile = file("${gradle.gradleUserHomeDir}/jextract-$jextractVersionString.tar.gz") - dependsOn(copyNativeLibs) + val downloadJextract by tasks.registering(DownloadJextractTask::class) { + jextractVersion.set(jextractVersionString) + platform.set(currentPlatform.jextractPlatform) + jextractDir.set(jextractDirectory) + downloadTarball.set(jextractTarballFile) - from(nativeOutputDir) - into("${sourceSets.main.get().output.resourcesDir}/native/$platformTarget") - - doFirst { - logger.lifecycle("Bundling libraries for $platformTarget into resources") + onlyIf { !jextractDirectory.exists() } } -} -val jextractPath = "${System.getProperty("user.home")}/jextract-22/bin/jextract" -val generatedJavaDir = file("${layout.buildDirectory.get()}/generated/sources/jextract/java") -val headerFile = file("$libProcessingDir/ffi/include/processing.h") + val makeJextractExecutable by tasks.registering(Exec::class) { + group = "rust" + description = "Make jextract binary executable on Unix systems" -sourceSets.main { - java.srcDirs(generatedJavaDir) -} + dependsOn(downloadJextract) + onlyIf { !System.getProperty("os.name").lowercase().contains("windows") } -val generateJavaBindings by tasks.registering(Exec::class) { - group = "rust" - description = "Generate Java bindings from libProcessing headers using jextract" + val jextractBin = file("$jextractDirectory/bin/jextract") + commandLine("chmod", "+x", jextractBin.absolutePath) + } - dependsOn(buildRustRelease) + val generateJavaBindings by tasks.registering(GenerateJextractBindingsTask::class) { + dependsOn(buildRustRelease) - inputs.file(headerFile) + val userJextract = JextractUtils.findUserJextract() + if (userJextract == null) { + dependsOn(downloadJextract, makeJextractExecutable) + } - outputs.dir(generatedJavaDir) + headerFile.set(file("$libProcessingDir/ffi/include/processing.h")) + outputDirectory.set(generatedJavaDir) + targetPackage.set("processing.ffi") - doFirst { - generatedJavaDir.mkdirs() - logger.lifecycle("Generating Java bindings from $headerFile...") + jextractPath.set(userJextract ?: "$jextractDirectory/bin/${JextractUtils.getExecutableName()}") } - commandLine = listOf( - jextractPath, - "--output", generatedJavaDir.absolutePath, - "--target-package", "processing.ffi", - headerFile.absolutePath - ) -} - -tasks.named("compileJava") { - dependsOn(generateJavaBindings) -} + tasks.named("compileJava") { + dependsOn(generateJavaBindings) + } -tasks.named("compileKotlin") { - dependsOn(generateJavaBindings) -} + tasks.named("compileKotlin") { + dependsOn(generateJavaBindings) + } -tasks.named("processResources") { - dependsOn(bundleNativeLibs) + tasks.named("processResources") { + dependsOn(bundleNativeLibs) + } } mavenPublishing{ From 0078714a71187632b7485c7ef4967519c181f3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Thu, 16 Oct 2025 13:10:55 -0700 Subject: [PATCH 5/6] Remove processing.h --- libProcessing/ffi/include/processing.h | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 libProcessing/ffi/include/processing.h diff --git a/libProcessing/ffi/include/processing.h b/libProcessing/ffi/include/processing.h deleted file mode 100644 index 32b7ab01e0..0000000000 --- a/libProcessing/ffi/include/processing.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef PROCESSING_H -#define PROCESSING_H - -#pragma once - -/* Generated with cbindgen:0.29.0 */ - -/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ - -#include -#include -#include -#include - -uint64_t processing_add(uint64_t left, uint64_t right); - -#endif /* PROCESSING_H */ From 56627168b6bd80d36da664caf46734b5a7b3b658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Thu, 16 Oct 2025 13:16:32 -0700 Subject: [PATCH 6/6] Set java version for all projects. --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 90920c22e3..55e128bfc4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,14 +16,14 @@ val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: true allprojects { tasks.withType().configureEach { - val javaVersion = if (project.name == "core" && enableWebGPU) "24" else "17" + val javaVersion = if (enableWebGPU) "24" else "17" sourceCompatibility = javaVersion targetCompatibility = javaVersion } tasks.withType().configureEach { compilerOptions { - val kotlinTarget = if (project.name == "core" && enableWebGPU) { + val kotlinTarget = if (enableWebGPU) { org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24 } else { org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17