Java 使用 Gradle 在清单中添加类路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22659463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 17:08:55  来源:igfitidea点击:

Add classpath in manifest using Gradle

javagradle

提问by Paolo Fulgoni

I would like my Gradle build script to add the complete Classpath to the manifest file contained in JAR file created after the build.

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

Example:

例子:

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

My build script already add some information to the manifest this way:

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

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

How do I get the list of dependencies to add to the manifest?

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



This page of Java tutorials describes more in detail how and why adding classpath to the manifest: Adding Classes to the JAR File's Classpath

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

采纳答案by Paolo Fulgoni

Found a solution on Gradle's forum:

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

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

Source: Manifest with Classpath in Jar Task for Subprojects

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

回答by kumetix

I had a similar yet not identical problem. I was publishing my lib jar L in the artifactory, and later fetching it as a dependency of module M, but the transitive dependencies, the ones which L need for compile and runtime, did not arrive with it. It took me sometime to realize that my jar was published into the artifactory with an empty pom file, hence gradle was not able to know which are L's transitive dependencies to be fetched. The missing piece was an instruction, in the L's build.gradle, to publish the pom. As often with gradle, the connection between the name of the insturction, and its meaning, is completely:

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

apply plugin: 'maven'

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

Source: uploading_to_maven_repositories

来源:uploading_to_maven_repositories

回答by Sonny

I know this is likely trivial for the groovy people here, but in my case, I wanted to change the location of the Class-Pathin the manifest file depending on whether I was going to run in the production environment or local environment. I did this by making my build.gradle's jar section look like this:

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

In this case, the argument to gradle buildis passed like so:

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

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

回答by Eng.Fouad

In the latest versions of gradle, compileand runtimebecomes deprecated. Instead, use runtimeClasspathas follows:

在gradle这个最新版本,compileruntime变得过时。相反,使用runtimeClasspath如下:

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


EDIT:

编辑:

Note that if you are using Kotlin DSL, you can configure the manifest as follows:

请注意,如果您使用的是 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")
    }
}
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"
    }
}

回答by fssilva

Place this at the end of the buid.gradlefile. Change the com.example.Mainto your own Main class.

把它放在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')
            }
        }
    }
}

回答by Vikas

The top answers her helped me a lot. Here is what worked for me:

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

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

So, instead of name, I had to use absolutePath. This may or may not work for you. Some suggest using runtime instead of compile. I used compile because, I have a compile section in dependencies in my build.gradle. So, the jar step picks up dependencies from there. The best thing to do is pick up something that you think will work, do a gradle build, then find the JAR file and expand it to find the META-INF/MANIFEST.MF file. You should be able to see all the directories separated by spaces. If not, you should try something different. Autocomplete feature of your IDE should be helpful in seeing what all methods or fields are available under configurations/compile etc. All this can be done easily in IntelliJ.

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

Oh.. and if you want to see where the library JARs are physically located on your disk, right click on your project->open module settings->Libraries and then click on any library.

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

回答by oleksii

Looks like gradle has evolved. This is another answer that looks similar to others, but there is a key difference: if you use a new keyword implementationin the dependencies, none of the other answers will work and you'll get an empty class path

看起来 gradle 已经进化了。这是另一种答案看起来类似于人,但有一个关键的区别:如果你使用一个新的关键词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')
}