openjfx / javafx-gradle-plugin

Gradle plugin that makes it easy to work with JavaFX 11+
https://openjfx.io/
BSD 3-Clause "New" or "Revised" License
352 stars 62 forks source link

Can we allow setting JavaFXPlatform? #99

Open shahzaibj opened 3 years ago

shahzaibj commented 3 years ago

It seems platform is currently detected here: https://github.com/openjfx/javafx-gradle-plugin/blob/master/src/main/java/org/openjfx/gradle/JavaFXOptions.java#L60

Is setting this / overriding this currently supported? Didn't seem so from documentation.

Basically instead of detecting, can we make an option in the plugin configuration similar to how modules and version is configurable?

The idea is that a developer may be developing on platform A but wants to produce artifact for platform B.

For instance, someone may be writing code on Windows, but when they actually are about to produce an artifact by calling a gradle task such as assemble then they may change this to Linux or MacOs.

abhinayagarwal commented 3 years ago

Can you add a use-case for this request?

shahzaibj commented 3 years ago

@abhinayagarwal Added use-case in the description:

The idea is that a developer may be developing on platform A but wants to produce artifact for platform B.

For instance, someone may be writing code on Windows, but when they actually are about to produce an artifact by calling a gradle task such as assemble then they may change this to Linux or MacOs.

shahzaibj commented 3 years ago

@abhinayagarwal I've tried to address it myself here: https://github.com/openjfx/javafx-gradle-plugin/pull/103

(I wasn't able to request review from anyone...I believe some permissions are needed to be able to do that)

swende commented 3 years ago

The possibility to configure the platform itself is really an essential feature.

For example, we want to build our JavaFX application automatically for different platforms. Since the whole thing is built via a cloud infrastructure on Linux servers, we would have to have a way to configure the target platform (mac, win, lin) for the individual builds.

What else would be needed to review and integrate that PULL request?

nanodeath commented 3 years ago

Want to +1 this with the same use case as others. I want to use something like TravisCI to generate artifacts for my application, but their Windows support is experimental, and their Windows+Java support is nonexistent; thus, it's impractical, and also somewhat pointless, to get my project to build inside a Windows virt.

But we're not actually compiling native code anyway, so I could just as easily generate the Windows build on the much-better supported Linux systems, except...there's no way to tell this plugin to actually build for a different OS.

nanodeath commented 3 years ago

For the extra impatient, this atrocity seems to work for me -- lets me specify an environment variable to change the platform. Note that it's written in build.gradle.kts, but I tried to keep it simple:

import org.openjfx.gradle.*

plugins {
    id("org.openjfx.javafxplugin") version "0.0.10"
    // ...
}

configure<JavaFXOptions> {
    version = "16"
    modules = listOf("javafx.controls", "javafx.swing")

    // Set JAVAFX_PLATFORM to "linux", "win", or "mac"
    val javafxPlatformOverride = System.getenv("JAVAFX_PLATFORM")
    if (javafxPlatformOverride != null) {
        val javafxPlatform: JavaFXPlatform = JavaFXPlatform.values()
            .firstOrNull { it.classifier == javafxPlatformOverride }
            ?: throw IllegalArgumentException("JAVAFX_PLATFORM $javafxPlatformOverride not in list:" +
                    " ${JavaFXPlatform.values().map { it.classifier }}")

        logger.info("Overriding JavaFX platform to {}", javafxPlatform)

        // Override the private platform field
        val platformField: Field = JavaFXOptions::class.java.getDeclaredField("platform")
        platformField.isAccessible = true
        platformField.set(this, javafxPlatform)

        // Invoke the private updateJavaFXDependencies() method
        val updateDeps: Method = JavaFXOptions::class.java.getDeclaredMethod("updateJavaFXDependencies")
        updateDeps.isAccessible = true
        updateDeps.invoke(this)
    }
}
majerm commented 3 years ago

My solution before this is merged is to clone repository, publish to maven local repository and use modified version of plugin:

git clone git@github.com:openjfx/javafx-gradle-plugin.git
# after clone I change version in build.gradle to '0.0.11-LOCAL' and apply changes from pullrequest
cd javafx-gradle-plugin
./gradlew clean build
./gradlew publishToMavenLocal

and in target project in settings.gradle:

pluginManagement {
    plugins {
        id 'org.openjfx.javafxplugin' version '0.0.11-LOCAL'
        ....
    }
    repositories {
        mavenLocal()
        mavenCentral()
        gradlePluginPortal()
    }
}
nanodeath commented 3 years ago

I did run into a fundamental problem with this ask, unfortunately. As far as this plugin is concerned, the only difference between platforms is which native JARs get bundled in. If you're actually trying to ship nice installer-wrapped software, you might have to build on the native platform anyway.

I haven't used it before, but I was planning on using jpackage, the new self-contained application package that shipped with JDK 14. It says this on its docs:

Packaging Pre-Reqs

Application packages must be built on the target platform. The system used for packaging must contain the application, a JDK, and software needed by the packaging tool.

To package your application for multiple platforms, you must run the packaging tool on each platform. If you want more than one format for a platform, you must run the tool once for each format.

So, getting this plugin to built cross-platform might be moot if the next step has to be run on a particular platform. I'd expect most installer-generators to have to be run on their native platform, but I'd love to be proven wrong there.

shahzaibj commented 3 years ago

@nanodeath We can specify targetPlatform using the Runtime Plugin (which internally uses JPackage). However, since it allows us to specify targetPlatform, therefore we can build the installer for any platform from any platform.