【问题标题】:Add classpath in manifest using Gradle使用 Gradle 在清单中添加类路径
【发布时间】:2014-03-26 11:23:38
【问题描述】:

我希望我的 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 教程页面更详细地描述了如何以及为什么将类路径添加到清单:Adding Classes to the JAR File's Classpath

【问题讨论】:

    标签: java gradle build.gradle gradle-kotlin-dsl


    【解决方案1】:

    在最新版本的 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"
        }
    }
    

    【讨论】:

    • for gradle 4.0+ for compileOnly jar { doFirst { manifest.attributes( 'Dependencies': configurations.compileOnly.files.collect { it.name }.join(' '), ) } }
    • 我必须使用it.canonicalPath
    【解决方案2】:

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

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

    来源:Manifest with Classpath in Jar Task for Subprojects

    【讨论】:

    • 这对某些人来说可能比对其他人更明显。但请确保jar 目标规则在您的dependency 规则之后调用。今天这个小细节让我困了很长时间。请参阅this gist 以获取示例。
    • ..然后如果您想将应用程序与外部依赖项一起打包,请参阅this gist。分发 zip 将转到文件夹 build\distributions
    • 我需要删除collect {} 部分以使其适合我。这假设所有依赖项都与您的主类位于同一个文件夹中,这对我来说并非如此。
    • 根据旧 Gradle 论坛中的链接帖子,它应该使用configurations.runtime 而不是configurations.compile。使用最新的 gradle 它将是configurations.runtimeClasspath
    • 如果不起作用,请尝试用 absolutePath 替换 name。
    【解决方案3】:

    我设法用自己的清单文件创建了一个自定义 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
    }
    

    【讨论】:

      【解决方案4】:

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

      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 在磁盘上的物理位置,请右键单击您的项目->打开模块设置->库,然后单击任何库。

      【讨论】:

        【解决方案5】:

        如果您的项目具有外部库依赖项,您可以将 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
        }
        

        更多详情可以阅读here

        【讨论】:

          【解决方案6】:

          将其放在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')
                      }
                  }
              }
          }
          

          【讨论】:

            【解决方案7】:

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

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

            来源:uploading_to_maven_repositories

            【讨论】:

              【解决方案8】:

              我知道这对于这里的 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(' ')
                             )
                }
              }
              

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

              $ gradle build -PjarDir="/opt/silly/path/"
              

              【讨论】:

                【解决方案9】:

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

                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')
                }
                

                【讨论】:

                  【解决方案10】:

                  这是 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}"
                          }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-07-13
                    • 2022-11-10
                    • 2016-06-03
                    • 2014-11-18
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-01-28
                    相关资源
                    最近更新 更多