@@ -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