Skip to content

Commit 7152360

Browse files
authored
Merge pull request #1287 from tychedelia/1270-ffi-scaffold
Initial FFI setup
2 parents ebd4df6 + 5662716 commit 7152360

File tree

24 files changed

+1316
-124
lines changed

24 files changed

+1316
-124
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,5 @@ generated/
124124
/app/windows/obj
125125
/java/gradle/build
126126
/java/gradle/example/.processing
127+
128+
libProcessing/ffi/include/*

BUILD.md

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ First, [download the IntelliJ IDEA Community Edition](https://www.jetbrains.com/
1212
1. Clone the Processing4 repository to your machine locally
1313
1. Open the cloned repository in IntelliJ IDEA CE
1414
1. When prompted, select **Trust Project**. You can preview the project in Safe Mode but you won't be able to build Processing.
15-
1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 17.
15+
1. IntelliJ may ask if you want to load Gradle project. If you allow this, make sure you are using JDK version 25.
1616
1. In the main menu, go to File > Project Structure > Project Settings > Project.
17-
1. In the SDK Dropdown option, select a JDK version 17 or Download the jdk
17+
1. In the SDK Dropdown option, select a JDK version 25 or Download the jdk
1818
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.
1919
1. Logs can be found in the `Build` or `Debug` pane on the bottom left of the window
2020

@@ -46,18 +46,43 @@ If you don't have them installed, you will need to install [Git](https://git-scm
4646
cd processing4
4747
```
4848

49-
2. **Install Temurin JDK 17:**
50-
51-
Download and install the appropriate version for your platform:
49+
2. **Install Temurin JDK 25:**
50+
51+
Processing requires the Temurin distribution of OpenJDK.
5252

53-
- [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)
54-
- [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)
55-
- [Other platforms](https://adoptium.net/temurin/releases/?package=jdk&version=17&os=any&arch=any)
53+
You can download it from [Adoptium](https://adoptium.net/), from [GitHub releases](https://github.com/adoptium/temurin25-binaries/releases),
54+
or find it in the package manager for your platform.
55+
56+
### macOS:
57+
```bash
58+
brew install --cask temurin@25
59+
````
60+
61+
### Windows (using winget):
62+
```bash
63+
winget install --id=EclipseAdoptium.Temurin.25.JDK -e
64+
```
65+
66+
### SDKMAN!
67+
68+
[SDKMAN!](https://sdkman.io/) is a useful tool for developers working on multiple versions of the JVM.
69+
70+
## Install `jextract`
71+
72+
`jextract` is a tool included in the JDK that generates Java bindings from C header files.
73+
It is required to build Processing when using WebGPU. You can download it [here](https://jdk.java.net/jextract/)
74+
or install it using SDKMAN!:
75+
76+
```bash
77+
sdk install jextract
78+
````
5679

5780
3. **Set the `JAVA_HOME` environment variable:**
5881

82+
It may be necessary to set the `JAVA_HOME` environment variable to point to your Temurin JDK 25 installation.
83+
5984
```bash
60-
export JAVA_HOME=/path/to/temurin/jdk-17.0.15+6/
85+
export JAVA_HOME=/path/to/temurin/jdk-25/
6186
```
6287

6388
### Build, Run, and Package Processing
@@ -136,26 +161,25 @@ If you are specifically trying to run the `Processing CLI`, you can test command
136161
137162
If you’re building Processing using IntelliJ IDEA and something’s not working, here are a few things that might help:
138163
139-
### Use the Correct JDK (temurin-17)
164+
### Use the Correct JDK (temurin-25)
140165
141-
Make sure IntelliJ is using **temurin-17**, not another version. Some users have reported issues with ms-17.
166+
Make sure IntelliJ is using **temurin-25**, not another version.
142167
143168
1. Go to **File > Project Structure > Project**
144-
2. Set the **Project SDK** to: `temurin-17 java version "17.0.15"`
169+
2. Set the **Project SDK** to: `temurin-25"`
145170
146171
![JDK Selection](.github/media/troubleshooting-Intellij-setting-djk-version-manually.png)
147172
148173
If it is not already installed, you can download it by:
149174
1. Clicking the SDK input field and then selecting the `Download JDK...` option from the menu
150-
2. Select Version: `17`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)`
175+
2. Select Version: `25`, Vendor: `Eclipse Temurin (AdoptOpenJDK HotSpot)`
151176
152177
153178
![JDK Download](.github/media/troubleshooting-Intellij-download-jdk.png)
154179
155180
Now go back to your main window and
156181
1. Click the green Run Icon in the top right of the window.
157182
158-
159183
### “Duplicate content roots detected”
160184
161185
You may see this warning in IntelliJ:

app/build.gradle.kts

Lines changed: 14 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
44
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
55
import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
66
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
7-
import java.io.FileOutputStream
8-
import java.util.zip.ZipEntry
9-
import java.util.zip.ZipOutputStream
7+
import processing.gradle.SignResourcesTask
108

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

@@ -49,14 +47,17 @@ compose.desktop {
4947
application {
5048
mainClass = "processing.app.ProcessingKt"
5149

52-
jvmArgs(*listOf(
53-
Pair("processing.version", rootProject.version),
54-
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
55-
Pair("processing.contributions.source", "https://contributions.processing.org/contribs"),
56-
Pair("processing.download.page", "https://processing.org/download/"),
57-
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
58-
Pair("processing.tutorials", "https://processing.org/tutorials/"),
59-
).map { "-D${it.first}=${it.second}" }.toTypedArray())
50+
jvmArgs(
51+
"--enable-native-access=ALL-UNNAMED", // Required for Java 25 native library access
52+
*listOf(
53+
Pair("processing.version", rootProject.version),
54+
Pair("processing.revision", findProperty("revision") ?: Int.MAX_VALUE),
55+
Pair("processing.contributions.source", "https://contributions.processing.org/contribs"),
56+
Pair("processing.download.page", "https://processing.org/download/"),
57+
Pair("processing.download.latest", "https://processing.org/download/latest.txt"),
58+
Pair("processing.tutorials", "https://processing.org/tutorials/"),
59+
).map { "-D${it.first}=${it.second}" }.toTypedArray()
60+
)
6061

6162
nativeDistributions{
6263
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "java.management.rmi", "java.scripting", "jdk.httpserver")
@@ -421,82 +422,14 @@ tasks.register("includeProcessingResources"){
421422
finalizedBy("signResources")
422423
}
423424

424-
tasks.register("signResources"){
425+
tasks.register<SignResourcesTask>("signResources") {
425426
onlyIf {
426427
OperatingSystem.current().isMacOsX
427428
&&
428429
compose.desktop.application.nativeDistributions.macOS.signing.sign.get()
429430
}
430431
group = "compose desktop"
431-
val resourcesPath = composeResources("")
432-
433-
// find jars in the resources directory
434-
val jars = mutableListOf<File>()
435-
doFirst{
436-
fileTree(resourcesPath)
437-
.matching { include("**/Info.plist") }
438-
.singleOrNull()
439-
?.let { file ->
440-
copy {
441-
from(file)
442-
into(resourcesPath)
443-
}
444-
}
445-
fileTree(resourcesPath) {
446-
include("**/*.jar")
447-
exclude("**/*.jar.tmp/**")
448-
}.forEach { file ->
449-
val tempDir = file.parentFile.resolve("${file.name}.tmp")
450-
copy {
451-
from(zipTree(file))
452-
into(tempDir)
453-
}
454-
file.delete()
455-
jars.add(tempDir)
456-
}
457-
fileTree(resourcesPath){
458-
include("**/bin/**")
459-
include("**/*.jnilib")
460-
include("**/*.dylib")
461-
include("**/*aarch64*")
462-
include("**/*x86_64*")
463-
include("**/*ffmpeg*")
464-
include("**/ffmpeg*/**")
465-
exclude("jdk/**")
466-
exclude("*.jar")
467-
exclude("*.so")
468-
exclude("*.dll")
469-
}.forEach{ file ->
470-
exec {
471-
commandLine("codesign", "--timestamp", "--force", "--deep","--options=runtime", "--sign", "Developer ID Application", file)
472-
}
473-
}
474-
jars.forEach { file ->
475-
FileOutputStream(File(file.parentFile, file.nameWithoutExtension)).use { fos ->
476-
ZipOutputStream(fos).use { zos ->
477-
file.walkTopDown().forEach { fileEntry ->
478-
if (fileEntry.isFile) {
479-
// Calculate the relative path for the zip entry
480-
val zipEntryPath = fileEntry.relativeTo(file).path
481-
val entry = ZipEntry(zipEntryPath)
482-
zos.putNextEntry(entry)
483-
484-
// Copy file contents to the zip
485-
fileEntry.inputStream().use { input ->
486-
input.copyTo(zos)
487-
}
488-
zos.closeEntry()
489-
}
490-
}
491-
}
492-
}
493-
494-
file.deleteRecursively()
495-
}
496-
file(composeResources("Info.plist")).delete()
497-
}
498-
499-
432+
resourcesPath.set(composeResources(""))
500433
}
501434
tasks.register("setExecutablePermissions") {
502435
description = "Sets executable permissions on binaries in Processing.app resources"

build.gradle.kts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,27 @@ plugins {
1212
// Can be deleted after the migration to Gradle is complete
1313
layout.buildDirectory = file(".build")
1414

15+
val enableWebGPU = findProperty("enableWebGPU")?.toString()?.toBoolean() ?: true
16+
17+
allprojects {
18+
tasks.withType<JavaCompile>().configureEach {
19+
val javaVersion = if (enableWebGPU) "24" else "17"
20+
sourceCompatibility = javaVersion
21+
targetCompatibility = javaVersion
22+
}
23+
24+
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
25+
compilerOptions {
26+
val kotlinTarget = if (enableWebGPU) {
27+
org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_24
28+
} else {
29+
org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
30+
}
31+
jvmTarget.set(kotlinTarget)
32+
}
33+
}
34+
}
35+
1536
// Configure the dependencyUpdates task
1637
tasks {
1738
dependencyUpdates {

buildSrc/build.gradle.kts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
plugins {
2+
`kotlin-dsl`
3+
}
4+
5+
repositories {
6+
mavenCentral()
7+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package processing.gradle
2+
3+
import org.gradle.api.DefaultTask
4+
import org.gradle.api.file.DirectoryProperty
5+
import org.gradle.api.file.RegularFileProperty
6+
import org.gradle.api.provider.Property
7+
import org.gradle.api.tasks.*
8+
import org.gradle.process.ExecOperations
9+
import javax.inject.Inject
10+
11+
abstract class CargoBuildTask : DefaultTask() {
12+
13+
@get:Inject
14+
abstract val execOperations: ExecOperations
15+
16+
@get:InputDirectory
17+
abstract val cargoWorkspaceDir: DirectoryProperty
18+
19+
@get:Input
20+
abstract val manifestPath: Property<String>
21+
22+
@get:Input
23+
abstract val release: Property<Boolean>
24+
25+
@get:Input
26+
abstract val cargoPath: Property<String>
27+
28+
@get:OutputFile
29+
abstract val outputLibrary: RegularFileProperty
30+
31+
init {
32+
group = "rust"
33+
description = "Builds Rust library using cargo"
34+
35+
// release by default
36+
release.convention(true)
37+
}
38+
39+
@TaskAction
40+
fun build() {
41+
val buildType = if (release.get()) "release" else "debug"
42+
logger.lifecycle("Building Rust library ($buildType mode)...")
43+
44+
val args = mutableListOf("build")
45+
if (release.get()) {
46+
args.add("--release")
47+
}
48+
args.add("--manifest-path")
49+
args.add(manifestPath.get())
50+
51+
execOperations.exec {
52+
workingDir = cargoWorkspaceDir.get().asFile
53+
commandLine = listOf(cargoPath.get()) + args
54+
}
55+
}
56+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package processing.gradle
2+
3+
import org.gradle.api.DefaultTask
4+
import org.gradle.api.file.DirectoryProperty
5+
import org.gradle.api.provider.Property
6+
import org.gradle.api.tasks.*
7+
import org.gradle.process.ExecOperations
8+
import javax.inject.Inject
9+
10+
abstract class CargoCleanTask : DefaultTask() {
11+
12+
@get:Inject
13+
abstract val execOperations: ExecOperations
14+
15+
@get:InputDirectory
16+
abstract val cargoWorkspaceDir: DirectoryProperty
17+
18+
@get:Input
19+
abstract val manifestPath: Property<String>
20+
21+
@get:Input
22+
abstract val cargoPath: Property<String>
23+
24+
init {
25+
group = "rust"
26+
description = "Cleans Rust build artifacts"
27+
}
28+
29+
@TaskAction
30+
fun clean() {
31+
logger.lifecycle("Cleaning Rust build artifacts...")
32+
33+
execOperations.exec {
34+
workingDir = cargoWorkspaceDir.get().asFile
35+
commandLine(cargoPath.get(), "clean", "--manifest-path", manifestPath.get())
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)