ChatGPT解决这个技术问题 Extra ChatGPT

Gradle - no main manifest attribute

I'm building a JAR file with Gradle. When I try to run it I get the following error

no main manifest attribute, in RxJavaDemo.jar

I tried manipulating the manifest property but I think I'm forgetting to add the dependencies or something to it. What exactly am I doing wrong?

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'demo.MainDashboard'

dependencies {
    compile files ("H:/Processes/Development/libraries/hikari-cp/HikariCP-2.4.1.jar")
    compile files ("H:/Processes/Development/libraries/controls-fx/controlsfx.jar")
    compile files ("H:/Processes/Development/libraries/database_connections/sqlite-jdbc-3.8.6.jar")
    compile files ("H:/Processes/Development/libraries/guava/guava-18.0.jar")
    compile files ("H:/Processes/Development/libraries/rxjava/rxjava-1.0.12.jar")
    compile files ("H:/Processes/Development/libraries/rxjava-extras/rxjava-extras-0.5.15.jar")
    compile files ("H:/Processes/Development/libraries/rxjavafx/RxJavaFX-1.0.0-RC1-SNAPSHOT.jar")
    compile files ("H:/Processes/Development/libraries/rxjavaguava/rxjava-guava-1.0.3.jar")
    compile files ("H:/Processes/Development/libraries/rxjava-jdbc/rxjava-jdbc-0.6.3.jar")
    compile files ("H:/Processes/Development/libraries/slf4j/slf4j-api-1.7.12.jar")
    compile files ("H:/Processes/Development/libraries/tom-commons/tom-commons.jar")
}

sourceSets {
    main.java.srcDir "src/main/java"
    main.resources.srcDir "src/main/resources"
}

jar { 
    manifest {
    attributes(
        "Class-Path": configurations.compile.collect { it.getName() }.join(' '))
    }
    from configurations.compile.collect { entry -> zipTree(entry) }
}

a
a.t.

Try to change your manifest attributes like:

jar {
  manifest {
    attributes(
      'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
      'Main-Class': 'hello.HelloWorld'
    )
  }
}

And then just change 'hello.helloWorld' to '<your packagename>.<the name of your Main class>' (where your Main class has a main method). In this case, you make in your manifest an attribute, which point to this class, then a jar is running.


@Stanislav 'Main-Class' value is the main class? What are hello and helloWorld in your example?
@DanielaMaia it's just a full qualified class name, sure it has to be written as hello.HelloWorld, where hello is the package where the HelloWorld class is located
I needed to remove the collect {} portion to get it to work for me. Your code assumes that all dependencies are in the same folder as your main class.
@AutonomousApps How exactly did you do that?
The lastest Gradle version has replaced compile. Instead use: 'Class-Path': configurations.runtimeClasspath.files.collect { it.getName() }.join(' ')
D
Denis Zavedeev

To make the jar file executable (so that the java -jar command works), specify the Main-Class attribute in MANIFEST.MF.

In Gradle, you can do it by configuring the jar task.

for Groovy DSL see these answers ([1], [2])

for Kotlin DSL you can use the following code snippet:

tasks.withType<Jar> {
    manifest {
        attributes["Main-Class"] = "com.caco3.Main"
    }
}

Why mainClassName does not work as expected?

Or why mainClassName does not specify the attribute in the manifest?

The mainClassName property comes from the application plugin. The plugin:

makes it easy to start the application locally during development, and to package the application as a TAR and/or ZIP including operating system specific start scripts.

So the application plugin does not aim at producing executable jars

When a mainClassName property set, then:

$ ./gradlew run will launch the main method in the class specified in the attribute the zip/tar archive built using distZip/distTar tasks will contain a script, which will launch the main method of the specified previously class.

Here is the line of shell script setting the main class:

$ grep Main2 gradletest
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLETEST_OPTS -classpath "\"$CLASSPATH\"" com.caco3.gradletest.Main2 "$APP_ARGS"

E
Eric Hallander

FWIW - I used the following jar task to assemble all my compile dependencies into the jar file, and used the above recommendation to get the class-path properly set

apply plugin: 'java-library'

jar {
  manifest {
    attributes(
      'Class-Path': configurations.compile.collect { it.getName() }.join(' '),
      'Main-Class': 'your.main.class.goes.here'
    )
  }

  // You can reference any part of the dependency configurations,
  // and you can have as many from statements as you need
  from configurations.compile  
  // I just copied them into the top of the jar, so it looks like the eclipse exported 
  // runnable jar, but you could designate a lib directory, and reference that in the 
  // classpath as "lib/$it.name" instead of it.getName()
  into ''   
}

M
Mahozad

To complement Denis Zavedeev answer, here are more ways for Kotlin DSL (build.gradle.kts):

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
}
tasks.jar {
    manifest {
        attributes["Main-Class"] = "com.example.MyMainClass"
    }
}

Side note: to create a runnable fat JAR (also called uber JAR), see this post.