【问题标题】:Building a Jar of a Frege project using Gradle使用 Gradle 构建 Frege 项目的 Jar
【发布时间】:2014-11-03 00:04:32
【问题描述】:

我想:

  1. 使用 Frege 编程语言编写一段简单的“Hello World”代码,
  2. 然后使用 Frege 编译器生成等效的 Java 源代码,
  3. 然后构建一个可执行的 Jar 文件以从命令行运行,
  4. 前面的所有步骤都应该由 Gradle “控制”。

我能够生成源代码(上一个列表中的项目 1. 和 2.),但我无法在输出中指定 Java 源代码的“包”结构,即我看不到packageJava 语句作为生成 Java 源代码中的第一行代码。我可以向 Frege 编译器指定将生成的代码放在哪里(通过 -d 参数)。

我认为这就是为什么在构建可执行 Jar 然后启动它时,我看到类似错误的原因(根据 Gradle 任务的不同尝试),例如:no main manifest attribute

Frege 源代码保存在一个名为HelloFrege.fr 的文件中,生成的Java 源代码在一个名为HelloFrege.java 的文件中(我验证该文件包含预期的main 方法)。

这里有一个 Gradle“Jar 任务”的版本:

//create a single Jar with all dependencies
task fatJar(type: Jar) {
    manifest {
        attributes  'Implementation-Title': 'Hello Frege Jar Example',
                    'Implementation-Version': version,
                    'Main-Class': 'HelloFrege'
    }
    baseName = project.name + '-all'
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

这里有另一个版本的 Gradle “Jar” 任务:

jar {
    manifest {
        attributes 'Main-Class': 'HelloFrege'
    }
}

我该如何解决这个问题?我想避免手动将包引用添加到自动生成的Java源代码文件中。

【问题讨论】:

    标签: ant gradle executable-jar frege


    【解决方案1】:

    如果您在 Frege 中的模块名称是不合格的,例如 HelloWorld,您将看不到 Java 中生成的 package 语句。模块名将成为类名,包为空或默认包。

    如果您的模块名称是限定的,例如foo.bar.HelloWorld,那么foo.bar 将是包名,HelloWorld 将是生成的Java 源代码中的类名。

    规则是模块名的最后一部分成为类名,限定符形成生成的Java源代码中的包名。

    【讨论】:

      【解决方案2】:

      我不确定 gradle 在这方面能为你做什么,但没有 gradle,至少应该可以做到以下几点:

      ... build your jar, as before ...
      jar -uvfe project-all.jar HelloFrege
      java -jar project-all.jar   # run it
      

      当然,这只是创建清单的另一种方式。如果这可行,那么是时候调查 gradle 拒绝这样做的原因了。

      后记:在考虑了问题可能是什么之后,我突然想到,您可能认为源文件名/路径与 java 包名有关。在 Frege 中情况并非如此,尽管让文件路径与包名匹配,并且文件基名与类名匹配是一种很好的做法(就像在 Java 中一样)。此外,为了消除一些混乱,请在 frege 中使用 module 关键字。正如 Marimuthu 所解释的,Java 包和类名是从 frege 模块名派生而来的。

      例子:

      $ cat Foo.fr
      module my.org.Baz where
      ...
      $ java -jar fregec.jar -d bin Foo.fr
      

      这会在包my.org中生成Baz类,并在bin/my/org/Baz.class中创建类文件

      【讨论】:

        【解决方案3】:

        到目前为止,我在这里发布我的发现。对我有用的 Gradle 命令组合如下(从命令行输入 gradle clean generateJavaSrcFromFregeSrc fatJar 调用它):

        task generateJavaSrcFromFregeSrc {
            ant.java(jar:"lib/frege3.21.586-g026e8d7.jar",fork:true) {
            arg(value: "-j") // do not run the java compiler
            arg(value: "-d")
            arg(value: "src/main/java") // the place where to put the generated source code (paired to the -d argument)
            arg(value: "src/main/frege/HelloFrege.fr")
            }
        }
        
        jar {
            manifest {
               attributes 'Main-Class': 'org.wathever.HelloFrege'
            }
        }
        
        task fatJar(type: Jar) {
            from files(sourceSets.main.output.classesDir)
            from files(sourceSets.main.output.resourcesDir)
            //from {configurations.compile.collect {zipTree(it)}} // this does not include the autogenerated source code
            baseName = project.name + '-fatJar'
            from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
            with jar
        }
        
        • 清单详细信息需要在jar 代码块中指定,如果我在task fatJar 中指定它们,那么在运行jar 时我会得到no main manifest attribute, in [...]
        • 如果我只使用代码块jar 和属性from("$projectDir") { include 'lib/**'} 来包含Frege jar,那么我会收到java.lang.ClassNotFoundException 之类的错误(我认为是因为Jar 是按原样包含而不是作为一个集合包含的.class 个文件)。
        • 在运行 Gradle 之前,文件夹 src/main/java/org/wathever 需要存在(附加信息:Maven 约定前缀 src/main/java 后缀为 HelloFrege.fr 源代码中指定的“Java 包”:module org.wathever.HelloFrege where

        我发现了一些有用的细节:

        【讨论】:

        • 请注意,一般情况下您不能使用 -j 标志。例如,当 A 依赖于 B 时,编译器在编译 A 时将需要 B 的类文件。
        猜你喜欢
        • 2016-11-17
        • 1970-01-01
        • 2019-01-19
        • 2014-05-09
        • 2012-08-01
        • 2014-05-16
        • 1970-01-01
        • 2012-06-24
        • 2017-03-09
        相关资源
        最近更新 更多