Skip to content

Commit 7fedbcf

Browse files
committed
Get the gradle sketch runner working locally.
1 parent bc8df0b commit 7fedbcf

5 files changed

Lines changed: 79 additions & 183 deletions

File tree

gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
group=org.processing
2+
version=4.5.4

java/gradle/example/settings.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ rootProject.name = "processing-gradle-plugin-demo"
22

33
pluginManagement {
44
includeBuild("../../../")
5-
}
5+
}
6+
includeBuild("../../../")

java/gradle/src/main/kotlin/DependenciesTask.kt

Lines changed: 0 additions & 79 deletions
This file was deleted.

java/gradle/src/main/kotlin/LibrariesTask.kt

Lines changed: 0 additions & 81 deletions
This file was deleted.

java/gradle/src/main/kotlin/ProcessingPlugin.kt

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,14 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
4747
// }
4848
project.plugins.apply(JavaPlugin::class.java)
4949

50-
if (webgpu) {
51-
project.extensions.configure(JavaPluginExtension::class.java) { ext ->
52-
ext.toolchain { spec ->
53-
spec.languageVersion.set(JavaLanguageVersion.of(javaVersion))
54-
}
55-
}
56-
project.tasks.withType(KotlinCompile::class.java).configureEach { task ->
57-
task.compilerOptions.jvmTarget.set(JvmTarget.fromTarget(javaVersion.toString()))
50+
project.extensions.configure(JavaPluginExtension::class.java) { ext ->
51+
ext.toolchain { spec ->
52+
spec.languageVersion.set(JavaLanguageVersion.of(javaVersion))
5853
}
5954
}
55+
project.tasks.withType(KotlinCompile::class.java).configureEach { task ->
56+
task.compilerOptions.jvmTarget.set(JvmTarget.fromTarget(javaVersion.toString()))
57+
}
6058

6159
if(isProcessing){
6260
// Set the build directory to a temp file so it doesn't clutter up the sketch folder
@@ -151,6 +149,9 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
151149
}
152150
}
153151

152+
val javaToolchains = project.extensions.getByType(org.gradle.jvm.toolchain.JavaToolchainService::class.java)
153+
val launcher = javaToolchains.launcherFor { it.languageVersion.set(JavaLanguageVersion.of(javaVersion)) }
154+
154155
project.afterEvaluate {
155156
// Copy the result of create distributable to the project directory
156157
project.tasks.named("createDistributable") { task ->
@@ -161,6 +162,13 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
161162
}
162163
}
163164
}
165+
project.tasks.withType(JavaExec::class.java).configureEach { task ->
166+
task.executable(launcher.get().executablePath.asFile.absolutePath)
167+
task.jvmArgs("--enable-native-access=ALL-UNNAMED")
168+
if (System.getProperty("os.name").lowercase().contains("mac")) {
169+
task.jvmArgs("-XstartOnFirstThread")
170+
}
171+
}
164172
}
165173

166174
// Move the processing variables into javaexec tasks so they can be used in the sketch as well
@@ -170,6 +178,9 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
170178
.forEach { (key, value) -> task.systemProperty(key, value) }
171179

172180
task.jvmArgs("--enable-native-access=ALL-UNNAMED")
181+
if (System.getProperty("os.name").lowercase().contains("mac")) {
182+
task.jvmArgs("-XstartOnFirstThread")
183+
}
173184

174185
// Connect the stdio to the PDE if ports are specified
175186
if(logPort != null) task.standardOutput = Socket("localhost", logPort.toInt()).outputStream
@@ -200,13 +211,6 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
200211
include("/*.java")
201212
}
202213

203-
// Scan the libraries before compiling the sketches
204-
val librariesTaskName = sourceSet.getTaskName("scanLibraries", "PDE")
205-
val librariesScan = project.tasks.register(librariesTaskName, LibrariesTask::class.java) { task ->
206-
task.description = "Scans the libraries in the sketchbook"
207-
task.libraryDirectories.from(sketchbook?.let { File(it, "libraries") }, root?.let { File(it).resolve("modes/java/libraries") })
208-
}
209-
210214
// Create a task to process the .pde files before compiling the java sources
211215
val pdeTaskName = sourceSet.getTaskName("preprocess", "PDE")
212216
val pdeTask = project.tasks.register(pdeTaskName, PDETask::class.java) { task ->
@@ -218,19 +222,68 @@ class ProcessingPlugin @Inject constructor(private val objectFactory: ObjectFact
218222
sourceSet.java.srcDir(task.outputDirectory)
219223
}
220224

221-
val depsTaskName = sourceSet.getTaskName("addLegacyDependencies", "PDE")
222-
project.tasks.register(depsTaskName, DependenciesTask::class.java){ task ->
223-
// Link the output of the libraries task to the dependencies task
224-
task.librariesMetaData.set(librariesScan.get().librariesMetaData)
225-
task.dependsOn(pdeTask, librariesScan)
226-
}
225+
// Resolve sketch+library deps at config time. Adding deps from a
226+
// TaskAction fails once a downstream task has already resolved
227+
// runtimeClasspath (e.g. Compose's `run`).
228+
addLegacyDependencies(project, pdeSourceSet.srcDirs,
229+
listOfNotNull(sketchbook?.let { File(it, "libraries") },
230+
root?.let { File(it).resolve("modes/java/libraries") }))
227231

228232
// Make sure that the PDE tasks runs before the java compilation task
229233
project.tasks.named(sourceSet.compileJavaTaskName) { task ->
230-
task.dependsOn(pdeTaskName, depsTaskName)
234+
task.dependsOn(pdeTaskName)
231235
}
232236
}
233237
}
238+
private fun addLegacyDependencies(project: Project, sketchDirs: Set<File>, libraryRoots: List<File>) {
239+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:jogl-all-main:2.6.0")
240+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.6.0")
241+
242+
val os = System.getProperty("os.name").lowercase()
243+
val arch = System.getProperty("os.arch").lowercase()
244+
val variant = when {
245+
os.contains("mac") -> "macosx-universal"
246+
os.contains("win") && arch.contains("64") -> "windows-amd64"
247+
os.contains("linux") && arch.contains("aarch64") -> "linux-aarch64"
248+
os.contains("linux") && arch.contains("arm") -> "linux-arm"
249+
os.contains("linux") && arch.contains("amd64") -> "linux-amd64"
250+
else -> null
251+
}
252+
if (variant != null) {
253+
project.dependencies.add("runtimeOnly", "org.jogamp.gluegen:gluegen-rt:2.6.0:natives-$variant")
254+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:nativewindow:2.6.0:natives-$variant")
255+
project.dependencies.add("runtimeOnly", "org.jogamp.jogl:newt:2.6.0:natives-$variant")
256+
}
257+
258+
val imports = sketchDirs
259+
.flatMap { dir -> dir.walkTopDown().filter { it.extension == "pde" }.toList() }
260+
.flatMap { Regex("""^\s*import\s+([\w.]+)\s*;""", RegexOption.MULTILINE).findAll(it.readText()).map { m -> m.groupValues[1] } }
261+
.toSet()
262+
if (imports.isEmpty()) return
263+
264+
val libraryJars = libraryRoots
265+
.filter { it.exists() }
266+
.flatMap { it.listFiles { f -> f.isDirectory }?.toList() ?: emptyList() }
267+
.mapNotNull { folder -> folder.resolve("library").takeIf { it.isDirectory } }
268+
.flatMap { it.listFiles { f -> f.extension == "jar" }?.toList() ?: emptyList() }
269+
270+
val matched = mutableSetOf<File>()
271+
imports.forEach { import ->
272+
libraryJars.forEach { jar ->
273+
java.util.jar.JarFile(jar).use { jf ->
274+
val hit = jf.entries().asSequence()
275+
.filter { it.name.endsWith(".class") }
276+
.map { it.name.substringBeforeLast('/').replace('/', '.') }
277+
.any { it.startsWith(import) }
278+
if (hit) matched.add(jar)
279+
}
280+
}
281+
}
282+
if (matched.isNotEmpty()) {
283+
project.dependencies.add("implementation", project.files(matched))
284+
}
285+
}
286+
234287
abstract class DefaultPDESourceDirectorySet @Inject constructor(
235288
sourceDirectorySet: SourceDirectorySet,
236289
taskDependencyFactory: TaskDependencyFactory

0 commit comments

Comments
 (0)