66

我希望我的 Gradle 构建脚本将完整的 Classpath 添加到构建后创建的 JAR 文件中包含的清单文件中。

例子:

Manifest-Version: 1.0
Class-Path: MyProject.jar SomeLibrary.jar AnotherLib.jar

我的构建脚本已经通过这种方式向清单中添加了一些信息:

jar {
    manifest {
        attributes("Implementation-Title": project.name,
            "Implementation-Version": version,
            "Main-Class": mainClassName,
    }
}

如何获取要添加到清单的依赖项列表?


这个 Java 教程页面更详细地描述了如何以及为什么将类路径添加到清单中:将类添加到 JAR 文件的类路径中

4

10 回答 10

82

在 Gradle 的论坛上找到了解决方案:

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

来源:子项目的 Jar 任务中的类路径清单

于 2014-03-31T10:45:32.353 回答
32

在最新版本的 gradle 中,compileruntime弃用。相反,请runtimeClasspath按如下方式使用:

'Class-Path': configurations.runtimeClasspath.files.collect { it.getName() }.join(' ')

编辑:

请注意,如果您使用的是 Kotlin DSL,则可以按如下方式配置清单:

configure<JavaPluginConvention> {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
    manifest {
        attributes(
                "Manifest-Version" to "1.0",
                "Main-Class" to "io.fouad.AppLauncher")
    }
}

tasks.withType(Jar::class) {
    manifest {
        attributes["Manifest-Version"] = "1.0"
        attributes["Main-Class"] = "io.fouad.AppLauncher"
    }
}
于 2017-07-05T12:02:26.443 回答
7

把它放在buid.gradle文件的末尾。将 更改com.example.Main为您自己的 Main 类。

jar {
    doFirst {
        manifest {
            if (!configurations.compile.isEmpty()) {
                attributes(
                        'Class-Path': configurations.compile.collect{it.toURI().toString()}.join(' '),
                        'Main-Class': 'com.example.Main')
            }
        }
    }
}
于 2017-08-07T15:50:40.123 回答
6

最佳答案对我帮助很大。这对我有用:

jar {
    manifest {
        attributes "Main-Class": "your.package.classWithMain"
        attributes "Class-Path": configurations.compile.collect { it.absolutePath }.join(" ")
    }
}

所以,我不得不使用absolutePath而不是name。这可能适合您,也可能不适合您。有些人建议使用运行时而不是编译。我使用了编译,因为我的 build.gradle 中有一个依赖项中的编译部分。因此,jar 步骤从那里获取依赖项。最好的办法是选择你认为可行的东西,进行 gradle 构建,然后找到 JAR 文件并展开它以找到 META-INF/MANIFEST.MF 文件。您应该能够看到以空格分隔的所有目录。如果没有,你应该尝试一些不同的东西。IDE 的自动完成功能应该有助于查看配置/编译等下所有可用的方法或字段。所有这些都可以在 IntelliJ 中轻松完成。

哦..如果您想查看库 JAR 在磁盘上的物理位置,请右键单击您的项目->打开模块设置->库,然后单击任何库。

于 2017-12-14T23:18:02.387 回答
2

我知道这对于这里的 groovy 人来说可能是微不足道的,但就我而言,我想Class-Path根据我是要在生产环境还是本地环境中运行来更改清单文件中的位置。我通过使我build.gradle的 jar 部分看起来像这样来做到这一点:

jar {
  from configurations.runtime
  manifest {
    attributes ('Main-Class': 'com.me.Main',
                'Class-Path': configurations.runtime.files.collect { jarDir+"/$it.name" }.join(' ')
               )
  }
}

在这种情况下,参数 togradle build是这样传递的:

$ gradle build -PjarDir="/opt/silly/path/"
于 2015-10-22T14:00:55.690 回答
2

我设法使用自己的清单文件创建了一个自定义 Jar 文件,如下所示:

task createJar(type : Jar) {
    manifest {
        attributes(
            'Manifest-Version': "1.0",
            'Main-Class': "org.springframework.boot.loader.JarLauncher",
            'Start-Class': "com.my.app.AppApplication",
            'Spring-Boot-Version': "2.2.4.RELEASE",
            'Spring-Boot-Classes': "BOOT-INF/classes/",
            'Spring-Boot-Lib': "BOOT-INF/lib/"
        )
    }
    def originDir = file("${buildDir}/unpacked")
    def destinationFile = "${buildDir}/repackaged/${project.name}-${version}"
    entryCompression ZipEntryCompression.STORED // no compression in case there are files in BOOT-INF/lib
    archiveName destinationFile
    from originDir
    archiveFile
}
于 2020-11-11T19:20:07.913 回答
1

如果您的项目具有外部库依赖项,您可以将 jar 复制到一个文件夹并在清单中添加类路径条目。

 def dependsDir = "${buildDir}/libs/dependencies/"
    task copyDependencies(type: Copy) {
    from configurations.compile
    into "${dependsDir}"
   }
task createJar(dependsOn: copyDependencies, type: Jar) {
  
    manifest {
        attributes('Main-Class': 'com.example.gradle.App',
                'Class-Path': configurations.compile.collect { 'dependencies/' + it.getName() }.join(' ')
        )
    }
    with jar
}

更多细节可以在 这里阅读

于 2020-10-15T15:31:04.083 回答
0

我有一个类似但不相同的问题。我在工件中发布了我的 lib jar L,然后将它作为模块 M 的依赖项获取,但是传递依赖项,即 L 编译和运行时所需的依赖项,并没有随它一起到达。我花了一些时间才意识到我的 jar 是用一个空的 pom 文件发布到工件中的,因此 gradle 无法知道要获取哪些 L 的传递依赖项。缺少的部分是 L 的 build.gradle 中的一条指令,用于发布 pom。与 gradle 一样,指令的名称与其含义之间的联系完全是:

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
} 

来源:uploading_to_maven_repositories

于 2015-04-12T12:08:12.390 回答
0

看起来 gradle 已经进化了。这是另一个看起来与其他答案相似的答案,但有一个关键区别:如果您在 中使用 new 关键字implementationdependencies则其他答案都不起作用,您将获得一个空的类路径

dependencies {
    // ensure the keyword here matches what 
    // you have in the jar->manifest->attributes
    // that is "implementation"
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
    // ...
}

// by default, implementation cannot be referenced, 
// this allows us to use it below
project.configurations.implementation.setCanBeResolved(true)

jar{
    manifest {
        attributes(
                "Main-Class": "app.Program",                
                "Class-Path":  configurations.implementation.collect { it.name }.join(' ')              
        )
    }
    dependsOn ('dependencies')
}
于 2020-03-06T10:27:29.520 回答
0

这是 Kotlin DSL (build.gradle.kts) 的另一种解决方案。
运行您的应用程序时,库文件应该libs/位于应用程序的子目录中。

tasks.jar {
    manifest.attributes["Main-Class"] = "com.example.MyMainClass"
    manifest.attributes["Class-Path"] = configurations
        .runtimeClasspath
        .get()
        .joinToString(separator = " ") { file ->
            "libs/${file.name}"
        }
}
于 2022-02-09T13:47:53.997 回答