1

I would like to:

  1. use the Frege programming language to write a simple "Hello World" piece of code,
  2. then using the Frege compiler generating the equivalent Java source code,
  3. then building an executable Jar file to run from the command line,
  4. all the previous steps should be "controlled" by Gradle.

I am able to generate the source code (items 1. and 2. from the previous list), but I am not able to specify a "package" structure of the Java source code in output, i.e. I can not see the package Java statement as the first line of code in the generate Java source code. I can specify to the Frege compiler where to put the generated code though (via the -d argument).

I think this is the reason why when building an executable Jar, then launching it, I am seeing similar errors (according to different attempts on Gradle tasks) e.g.: no main manifest attribute.

The Frege source code is saved in a file named HelloFrege.fr, the generated Java source code is in a file named HelloFrege.java (I verified the file contains the expected main method).

Here there's a version of the Gradle "Jar task":

//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
}

Here there's another version of the Gradle "Jar" task:

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

How can I solve this problem? I would like to avoid to manually add the package reference to the automatically generated Java source code file.

TPPZ
  • 4,447
  • 10
  • 61
  • 106

3 Answers3

2

If your module name in Frege is unqualified such as HelloWorld, you will not see the package statement generated in Java. The module name will become the class name and the package will be empty or default package.

If your module name is qualified such as foo.bar.HelloWorld, then foo.bar will be the package name and HelloWorld will be the class name in the generated Java source.

The rule is that the last part of the module name becomes the class name and the qualifiers form the package name in the generated Java source.

Marimuthu Madasamy
  • 13,126
  • 4
  • 30
  • 52
1

I am not sure what gradle can do for you in this regard, but without gradle, the following should at least be possible:

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

This, of course, is just another way to create a manifest. If this works, then it would be time to investigate why gradle refuses to do it.

Postscriptum: After thinking another minute about what the problem might be, it occurs to me that you may think that the source file name/path has anything to do with the java package name. This is not so in Frege, though it is good practice to have the file path match the package name, and the file base name match the class name (just like in Java). In addition, to remove some confusion, use the module keyword in frege. As explained by Marimuthu, the Java package and class name is derived from the frege module name.

Example:

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

This generates the Baz class in package my.org, and creates the class file in bin/my/org/Baz.class

Ingo
  • 36,037
  • 5
  • 53
  • 100
0

I am posting here my findings so far. The combination of Gradle commands that works for me is the following one (calling it from the command line typing 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
}
  • The manifest details need to be specified in the jar block of code, if I specify them in the task fatJar then when running the jar I get no main manifest attribute, in [...].
  • If I use just the block of code jar with the property from("$projectDir") { include 'lib/**'} to include the Frege jar, then I get errors like java.lang.ClassNotFoundException (I think because the Jar is included as it is and not as a set of .class files).
  • The folder src/main/java/org/wathever needs to be there before running Gradle (additional info: the Maven convention prefix src/main/java with as a suffix the "Java package" as specified inside the HelloFrege.fr source code: module org.wathever.HelloFrege where)

Some useful details I found:

TPPZ
  • 4,447
  • 10
  • 61
  • 106
  • Note, though, that you can't use the -j flag in general. For example, when A depends on B then the compiler will need B's class file upon compiling A. – Ingo Nov 04 '14 at 08:08