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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ generated/
/app/windows/obj
/java/gradle/build
/java/gradle/example/.processing

libProcessing/ffi/include/*
52 changes: 38 additions & 14 deletions BUILD.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -136,26 +161,25 @@ 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)

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:
Expand Down
95 changes: 14 additions & 81 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
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 processing.gradle.SignResourcesTask

// TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload

Expand Down Expand Up @@ -49,14 +47,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")
Expand Down Expand Up @@ -421,82 +422,14 @@ tasks.register("includeProcessingResources"){
finalizedBy("signResources")
}

tasks.register("signResources"){
tasks.register<SignResourcesTask>("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<File>()
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"
Expand Down
21 changes: 21 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@ plugins {
// Can be deleted after the migration to Gradle is complete
layout.buildDirectory = file(".build")

val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: true

allprojects {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a workaround until kotlin 2.3.0 is released with jdk 25 support.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we leave a little TODO saying that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's more complicated now as it enforces android source level compat

tasks.withType<JavaCompile>().configureEach {
val javaVersion = if (enableWebGPU) "24" else "17"
sourceCompatibility = javaVersion
targetCompatibility = javaVersion
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
compilerOptions {
val kotlinTarget = if (enableWebGPU) {
org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24
} else {
org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
jvmTarget.set(kotlinTarget)
}
}
}

// Configure the dependencyUpdates task
tasks {
dependencyUpdates {
Expand Down
7 changes: 7 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
}
56 changes: 56 additions & 0 deletions buildSrc/src/main/kotlin/processing/gradle/CargoBuildTask.kt
Original file line number Diff line number Diff line change
@@ -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<String>

@get:Input
abstract val release: Property<Boolean>

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

@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
}
}
}
38 changes: 38 additions & 0 deletions buildSrc/src/main/kotlin/processing/gradle/CargoCleanTask.kt
Original file line number Diff line number Diff line change
@@ -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<String>

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

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())
}
}
}
Loading