Subject: Java support

From: Stefano Lattarini <[email-masked]>
Date: Fri, 15 Jul 2011 10:58:01 +0200

[Adding bug-automake in CC:, so that we won't forget about the issue]

On Thursday 14 July 2011, tsuna  wrote:
> Hi all,
> whether I like it or not, it so happens that I have a Java project I'm
> trying to package properly, and I'm trying to use autoconf/automake
> for maximum portability and ease of integration with various distros
> (since most of them have tools to automagically build packages on
> properly autotoolized projects), not to mention all the usual benefits
> that the autotools provide out of the box.
> 
> I'm aware of http://sources.redhat.com/automake/automake.html#Java-Support
> (support via GCJ) but that's not what I want.  Most of the Java people
> don't use GCJ, they use Sun's JDK.  Somewhat confusingly perhaps, that
> section of the documentation doesn't refer to
> http://sources.redhat.com/automake/automake.html#Java which seems to
> be closer to what I want.
>
You're right; the documentation on Java support should be definitely
be improved (especially making better distinction between usual bytecode
compilation with javac and "native/binary compilation" with gcj).

> It's not clear from that part of the
> documentation how to get a .jar and have it installed etc.  I read the
> code in lib/am/java.am and it seems all it does is to compile all the
> .java files into .class files and install the .class files.
>
Sadly true.  And IMHO adding support for generating and installing .jar
files would be definitely worthwhile.  BTW, I had already given some
thoughts to this possibility, but I wasn't sure if there would be enough
user interest to warrant a change in this direction; your mail seems to
show that indeed there is some interest at least (thank you for that!).

> The good
> thing about this is that it's compiling all the .java files at once
> (and not one-by-one like we do with C/C++ files), the bad thing is
> that it has no facility to produce and install a .jar file that
> contains all the .class files,

> and it only supports one _JAVA target per Makefile.am.
>
Yes (but my proposal below about a new JARS primary should allow us
to easily remove this limitation).

> I noticed there's a branch called "java-work", however it's not clear
> to me what improvements it has, and its lib/am/java.am seems pretty
> much identical.
>
Yes, so far that branch has only dealt with small bug fixes and
improved testsuite coverage.

> One of the problems noted in the manual and in Automake's code is that
> a single .java files doesn't predictably translate into a .class file.
> And there's no equivalent to gcc -M in the Java world.  "Foo.java" is
> pretty much guaranteed to produce "Foo.class", but frequently there
> will be other class files of the form "Foo$Something.class" produced
> (this is because the nested class "Something" in the class "Foo" is
> compiled into its own file).  Right now in my project I build pretty
> much everything with custom rules (even though I just switched from
> plain Make to Automake) and the approach I've used to work around this
> problem is to assume that "Foo.java" will produce "Foo*.class".  I
> don't know if Automake could use this approach too, since there are
> cases where this will glob unrelated files, but it's working like a
> charm in my project.  Ideally we should look for "Foo.class" and,
> maybe, "Foo$*.class", however the `maybe' part is annoying because if
> the globbing pattern doesn't match anything, it'll stay as is or,
> worse, produce an error with some shells (e.g. zsh with certain
> options).
> 
I'd rather deprecate the JAVA primary, and then introduce a new `JARS'
primary, to be used e.g. as follows:

  jar_JARS = foo.jar
  zardoz_JARS = bar.jar
  foo_jar_SOURCES = all.java foo.java
  bar_jar_SOURCES = all.java bar.java
  bar_jar_JAVACFLAGS = -nowarn
  bar_jar_JARFLAGS = -J-Xmx48M

This should cause the following behaviour:

 1. javac will be called (with the `-d' option), to generate .class files
    from all.java and foo.java, and put them into a "private" directory
    `.classes/foo_jar/';

 2. similarly, javac will be called (this time also with the `-nowarn'
    option) to generate .class files from all.java and bar.java, placing
    them into the directory `.classes/bar_jar/';

 3. jar will be called to build `foo.jar' from all the .class files found
    in .classes/foo_jar/;
  
 4. similarly, jar will be called (this time with the `-J-Xmx48M' option)
    to build `bar.jar' from all the .class files in .classes/foo_jar/;

 5. "make mostlyclean" will remove the `.classes' directory;

 6. "make clean" will also remove foo.jar and bar.jar;

 7. "make install" will install foo.jar in $(jardir) (which we could make
    default to `$(datadir)/jar') and bar.jar in $(zardozdir) (which we
    expect to be user-defined).

As my java foo is pretty weak, I'm not sure how to handle jar manifests,
jar entry points, or other jar/javac subtleties and advanced features.
Suggestions welcome.

> My question now boils down to this:
> Has anyone already got some thoughts on how to make Automake play well
> with Java projects or what kind of workarounds can I use to leverage
> as much of Automake as possible while still building my Java stuff the
> way I want it?
>
> Alternate question: if Java was a brand new language Automake had
> never heard of, how would I build my project with Automake without
> doing what I'm doing now where I have custom rules for everything and
> I need to hook myself into install- and dist-hooks to Do The Right
> Thing?
>
Basically (and as far as my knowledge/understanding goes), you wouldn't;
Automake is unfortunately quite unflexible in this regard.  Providing
your own "all-local", "install-hook" and "uninstall-local" rules is
probably the best route to follow.

> Like isn't it possible to have a bin_PROGRAMS = foo.jar and
> foo_jar_SOURCES = main.java and then tell automake how to transform a
> .java into a .class and then how to turn all the .class into a .jar?
> It seems that when I try this, Automake dies with "Java source seen
> but `GCJ' is undefined".
> 
Yes, because Automake thinks you want to build foo.jar as a binary
executable, and so it wants to use gcj to compile it.  This happens
because you've listed foo.jar in a PROGRAMS primary, which is only
meant for binary executables, not scripts or bytecode files (ok, I'm
simplifying things a bit here, but the main point stands).

> Thanks and sorry for the longish email.
> 

Well, thanks to you for rekindling interest in the Automake Java
support :-)

Regards,
  Stefano