jeka-dev / jeka

Build and Run Java code for Everywhere
https://jeka.dev
Apache License 2.0
110 stars 15 forks source link

Unable to build javafx application due to missing scope in compile scope set #169

Closed treilhes closed 3 years ago

treilhes commented 3 years ago

Hello,

I'm currently giving a try to Jeka on a simple javafx application in Eclipse. All was starting fine, Eclipse classpath was generated successfuly and my project was building fine in the IDE but when trying to build my app using Jeka i got a lot of compilation errors due to missing javafx libs.

After a close look it seems due to a missing runtime scope in:

JkJavaProjectCompilation.java

    private JkJavaCompileSpec computeProdCompileSpec() {
        JkScope[] scopes = new JkScope[] {JkScope.COMPILE, JkScope.PROVIDED};

Updating the code to

JkJavaProjectCompilation.java

    private JkJavaCompileSpec computeProdCompileSpec() {
        JkScope[] scopes = new JkScope[] {JkScope.COMPILE, JkScope.PROVIDED, JkScope.RUNTIME};

For the why:

Javafx libraries are empty jars with os dependent runtime dependencies using os classifiers

so on windows when using the dependency org.openjfx:javafx-base:11.0.2 you will get in classpath javafx-base-11.0.2.jar (empty jar) javafx-base-11.0.2-win.jar (runtime jar with class and native )

The eclipse plugin resolves the os dependent jar but the java plugin don't due to the missing runtime

Javadoc step also fails for the same reason

djeang commented 3 years ago

Thank you for your feedback,

Please can you provide a snippet of your build class please ?

treilhes commented 3 years ago

You can find it below

import dev.jeka.core.api.depmanagement.JkDependencySet;
import dev.jeka.core.api.depmanagement.JkScope;
import dev.jeka.core.api.java.JkJavaVersion;
import dev.jeka.core.api.tooling.JkGitWrapper;
import dev.jeka.core.tool.JkClass;
import dev.jeka.core.tool.JkInit;
import dev.jeka.core.tool.builtins.eclipse.JkPluginEclipse;
import dev.jeka.core.tool.builtins.java.JkPluginJava;

class Build extends JkClass {

    final JkPluginJava java = getPlugin(JkPluginJava.class);
    final JkPluginEclipse eclipse = getPlugin(JkPluginEclipse.class);

    /*
     * Configures plugins to be bound to this command class. When this method is called, option
     * fields have already been injected from command line.
     */
    @Override
    protected void setup() {
        java.getProject().simpleFacade()
            .setJavaVersion(JkJavaVersion.V11)
            .addDependencies(JkDependencySet.of()
                .and("org.openjfx:javafx-base:11.0.2")
                .and("org.openjfx:javafx-controls:11.0.2")
                .and("org.openjfx:javafx-media:11.0.2")
                .and("org.openjfx:javafx-web:11.0.2")
                .and("org.openjfx:javafx-swing:11.0.2")
                .and("org.openjfx:javafx-fxml:11.0.2")
                .and("de.jensd:fontawesomefx-fontawesome:4.7.0-9.1.2")
                .and("org.controlsfx:controlsfx:11.0.2")
                .and("net.raumzeitfalle.fx:scenic-view:11.0.2")
                .and("com.sun.xml.bind:jaxb-impl:2.3.3")
                //.and("com.google.guava:guava:21.0")
                .and("org.junit.jupiter:junit-jupiter:5.6.2", JkScope.TEST))
            //.addTestIncludeFilterOnStandardNaming(true)
            // On ly necessary if your project is published in a binary repository.
            .setPublishedModuleId("your.group:your.project")
            .setPublishedVersion(JkGitWrapper.of(getBaseDir()).getVersionFromTags());  // Version inferred from Git
    }

    public void cleanPack() {
        clean(); 
        java.pack();
    }

    public void eclipseFile() {
        eclipse.files();
    }

    public static void main(String[] args) {
        JkInit.instanceOf(Build.class, args).cleanPack();
        //JkInit.instanceOf(Build.class, args).eclipseFile();
    }

}
treilhes commented 3 years ago

@djeang, Please stop looking into this issue, i've digged into maven and gradle build of javafx app and found that javafx plugins used in those builds were doing exactly that : adding javafx runtime lib into the compilation path

Not including runtime dependencies in compilation classpath is exactly what must be done by default.

So now my question is, how can i add runtime dependencies into the compilation path in my Build.java

Sorry for wasting your time, i'm ashamed

djeang commented 3 years ago

I think the underlying problem lies in scope mapping. Your dependency is declared with the default scope (COMPILE_AND_RUNTIME) so normally it should fall under JkScope[] scopes = new JkScope[] {JkScope.COMPILE, JkScope.PROVIDED};.

Apparently it does not for un unknown reason.

I am currently reworking deeply the dependency management in Jeka a specific branch : the concept of 'scope' will be replaced by the concept of 'transitivity' in next version... so I don't want to investigate more on this.

Your patch is ok to solve your case but it may embedded runtime dependencies that you may not want in your compile classpath (which is generally not an issue).

Hope you can live with this until the next version is ready. I will include your case in my test suite to validate the new dependency management.

djeang commented 3 years ago

@treilhes

Sorry for wasting your time, i'm ashamed

That's fine 👍 You're helping me to make it better.

djeang commented 3 years ago

@treilhes Ho, got it. I think you just need to declare explicitly the classifier (which make sense for independent platform builds). .and("org.openjfx:javafx-base:win:11.0.2")

treilhes commented 3 years ago

Just to let you know

Using classifiers did fail due to ivy resolving the classifier to an url not compliant with maven pattern

https://repo.maven.apache.org/maven2/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.win

instead of

https://repo.maven.apache.org/maven2/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2-win

[Ivy] :: problems summary ::
         [Ivy] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS
         [Ivy] :::: WARNINGS
         [Ivy] [NOT FOUND  ] org.openjfx#javafx-base;11.0.2!javafx-base.win (676ms)
         [Ivy] ==== https://repo.maven.apache.org/maven2: tried
         [Ivy] https://repo.maven.apache.org/maven2/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.win
         [Ivy] ::::::::::::::::::::::::::::::::::::::::::::::
         [Ivy] ::              FAILED DOWNLOADS            ::
         [Ivy] :: ^ see resolution messages for details  ^ ::
         [Ivy] ::::::::::::::::::::::::::::::::::::::::::::::
         [Ivy] :: org.openjfx#javafx-base;11.0.2!javafx-base.win
         [Ivy] ::::::::::::::::::::::::::::::::::::::::::::::
         File for org.openjfx#javafx-base;11.0.2!javafx-base.win hasn't been downloaded.
         13 modules[com.sun.xml.bind:jaxb-impl:2.3.3, org.openjfx:javafx-graphics:11.0.2, org.openjfx:javafx-base:11.0.2, org.controlsfx:controlsfx:11.0.2, jakarta.xml.bind:jakarta.xml.bind-api:2.3.3, org.openjfx:javafx-fxml:11.0.2, de.jensd:fontawesomefx-commons:9.1.2, org.openjfx:javafx-web:11.0.2, de.jensd:fontawesomefx-fontawesome:4.7.0-9.1.2, org.openjfx:javafx-controls:11.0.2, org.openjfx:javafx-swing:11.0.2, net.raumzeitfalle.fx:scenic-view:11.0.2, org.openjfx:javafx-media:11.0.2]
         13 artifacts.
      Exception in thread "main" java.lang.IllegalStateException: 
        at dev.jeka.core.api.depmanagement.JkDependencyManagement.resolveDependencies(JkDependencyManagement.java:109)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1133)
        at dev.jeka.core.api.depmanagement.JkDependencyManagement.fetchDependencies(JkDependencyManagement.java:100)
        at dev.jeka.core.api.java.project.JkJavaProjectCompilation.computeProdCompileSpec(JkJavaProjectCompilation.java:264)
        at dev.jeka.core.api.java.project.JkJavaProjectCompilation.lambda$ofProd$0(JkJavaProjectCompilation.java:85)
        at dev.jeka.core.api.java.project.JkJavaProjectCompilation.runCompile(JkJavaProjectCompilation.java:252)
        at dev.jeka.core.api.java.project.JkJavaProjectCompilation.run(JkJavaProjectCompilation.java:124)
        at dev.jeka.core.api.java.project.JkJavaProjectCompilation.runIfNecessary(JkJavaProjectCompilation.java:136)
        at dev.jeka.core.api.java.project.JkJavaProjectConstruction.createBinJar(JkJavaProjectConstruction.java:98)
        at dev.jeka.core.api.depmanagement.JkStandardFileArtifactProducer.makeArtifact(JkStandardFileArtifactProducer.java:51)
        at dev.jeka.core.api.depmanagement.JkArtifactProducer.makeArtifacts(JkArtifactProducer.java:35)
        at dev.jeka.core.api.depmanagement.JkArtifactProducer.makeAllMissingArtifacts(JkArtifactProducer.java:80)
        at dev.jeka.core.tool.builtins.java.JkPluginJava.pack(JkPluginJava.java:187)
        at Build.cleanPack(Build.java:95)
        at Build.main(Build.java:103)

Your new branch "rework-dep-scopes" did build the project successfully

djeang commented 3 years ago

Sorry this is the pattern to use : group:name:type:artifact:version. You can get it from JkModuleDedendency#of(String) javadoc. So in your case, use .and("org.openjfx:javafx-base::win:11.0.2") so the type will be empty and the 'win' will stand for classifier I will try to make it more explicit/intuitiive in the next version.