Subject: bug#8434: [PATCH] java: allow both dist_JAVA and nodist_JAVA in the same Makefile.am (was: Re: bug#8434: java: cannot use JAVA with both dist_ and nodist_ prefixes)

From: Stefano Lattarini <[email-masked]>
Date: Mon, 18 Apr 2011 21:35:52 +0200

On Saturday 09 April 2011, Ralf Wildenhues wrote:
> Hi Stefano,
> 
> * Stefano Lattarini wrote on Wed, Apr 06, 2011 at 09:00:32PM CEST:
> > Currently, limitations in the Automake support for java enforce the
> > restriction that only one `_JAVA' primary can be used in a given
> > Makefile.am.
> 
> > This bug is particularly annoying because *.java files listed with
> > the `JAVA' primary are not included by default in the distribution.
> > 
> > Ganted, one can always use EXTRA_DIST to work around this issue,
> > but it would be nice if things Just Worked.
> 
> Agreed on all accounts.  Do you see a way to fix this, for arbitrary
> dependency structure between the java classes?
> 
> Thanks for the bug report,
> Ralf
> 
Attached is a patch that fixes the problem.  OK for a new 'java-work'
branch based off of the right maint-based commits (as to make new
tests like 'java-extra.test' and `java-noinst.test' available)?  We
can decide at a later date whether this branch has to be merged into
maint or into master only.

I'll push in 72 hours if there is no objection.

Regards,
   Stefano
From d76b503883525aaab6048102cbfe96bbdd9a0a85 Mon Sep 17 00:00:00 2001
From: Stefano Lattarini <[email-masked]>
Date: Mon, 18 Apr 2011 15:18:08 +0200
Subject: [PATCH] java: allow both dist_JAVA and nodist_JAVA in the same Makefile.am

Fixes automake bug#8434.

* automake.in (handle_java): Strip `dist_' and `nodist_' from
the given prefix.  Define a new internal Makefile variable
`am__java_sources'.  Related adjustments.
* lib/am/java.am (JAVAC, JAVAROOT, CLASSPATH_ENV): Define only the
first time this am file is processed.
(class%DIR%.stamp): Stamp file renamed ...
(class%NDIR%.stamp): ... to this, so that the `dist_' and `nodist_'
prefixes are stripped from the name of the stampfile.  Adjust
declaration of dependencies by using the new automake-generated
internal variable `$(am__java_sources)'.  In the rule, use `$@'
as the name of the target, rather than hard-coding it.
* tests/java.test: Update and extend.
* tests/java-no-duplicate.test: New test.
* tests/java-mix-dist-nodist.test: Likewise.
* tests/java-compile-and-install.test: Likewise.
* tests/java-clean.test: Likewise.
* tests/java-sources.test: Likewise.
* tests/Makefile.am (TESTS): Update.
---
 ChangeLog                       |   23 ++++++++++
 automake.in                     |   20 +++++++--
 lib/am/java.am                  |   14 ++++---
 tests/Makefile.am               |    5 ++
 tests/Makefile.in               |    5 ++
 tests/java-clean.test           |   57 ++++++++++++++++++++++++++
 tests/java-compile-install.test |   86 +++++++++++++++++++++++++++++++++++++++
 tests/java-mix-dist-nodist.test |   56 +++++++++++++++++++++++++
 tests/java-no-duplicate.test    |   44 ++++++++++++++++++++
 tests/java-sources.test         |   61 +++++++++++++++++++++++++++
 tests/java.test                 |    9 +++-
 11 files changed, 367 insertions(+), 13 deletions(-)
 create mode 100755 tests/java-clean.test
 create mode 100755 tests/java-compile-install.test
 create mode 100755 tests/java-mix-dist-nodist.test
 create mode 100755 tests/java-no-duplicate.test
 create mode 100755 tests/java-sources.test

diff --git a/ChangeLog b/ChangeLog
index 3ece73c..791d8e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2011-04-18  Stefano Lattarini  <[email-masked]>
+
+	java: allow both dist_JAVA and nodist_JAVA in the same Makefile.am
+	Fixes automake bug#8434.
+	* automake.in (handle_java): Strip `dist_' and `nodist_' from
+	the given prefix.  Define a new internal Makefile variable
+	`am__java_sources'.  Related adjustments.
+	* lib/am/java.am (JAVAC, JAVAROOT, CLASSPATH_ENV): Define only the
+	first time this am file is processed.
+	(class%DIR%.stamp): Stamp file renamed ...
+	(class%NDIR%.stamp): ... to this, so that the `dist_' and `nodist_'
+	prefixes are stripped from the name of the stampfile.  Adjust
+	declaration of dependencies by using the new automake-generated
+	internal variable `$(am__java_sources)'.  In the rule, use `$@'
+	as the name of the target, rather than hard-coding it.
+	* tests/java.test: Update and extend.
+	* tests/java-no-duplicate.test: New test.
+	* tests/java-mix-dist-nodist.test: Likewise.
+	* tests/java-compile-and-install.test: Likewise.
+	* tests/java-clean.test: Likewise.
+	* tests/java-sources.test: Likewise.
+	* tests/Makefile.am (TESTS): Update.
+
 2011-04-06  Stefano Lattarini  <[email-masked]>
 
 	coverage: more on java support EXTRA_ and noinst_ prefixes
diff --git a/automake.in b/automake.in
index a8ec749..01b41a1 100755
--- a/automake.in
+++ b/automake.in
@@ -5107,20 +5107,32 @@ sub handle_java
 				      'java', 'noinst', 'check');
     return if ! @sourcelist;
 
-    my @prefix = am_primary_prefixes ('JAVA', 1,
+    my @prefixes = am_primary_prefixes ('JAVA', 1,
 				      'java', 'noinst', 'check');
 
     my $dir;
-    foreach my $curs (@prefix)
+    my @java_sources = ();
+    foreach my $prefix (@prefixes)
       {
+        (my $curs = $prefix) =~ s/^(?:no)?dist_//;
+
 	next
 	  if $curs eq 'EXTRA';
 
-	err_var "${curs}_JAVA", "multiple _JAVA primaries in use"
-	  if defined $dir;
+        push @java_sources, '$(' . $prefix . '_JAVA' . ')';
+
+	if (defined $dir)
+	  {
+	    err_var "${curs}_JAVA", "multiple _JAVA primaries in use"
+	     unless $curs eq $dir;
+	  }
+
 	$dir = $curs;
       }
 
+    define_pretty_variable ('am__java_sources', TRUE, INTERNAL,
+                            "@java_sources");
+
     if ($dir eq 'check')
       {
         push (@check, "class$dir.stamp");
diff --git a/lib/am/java.am b/lib/am/java.am
index d6eb455..e0f5bba 100644
--- a/lib/am/java.am
+++ b/lib/am/java.am
@@ -20,11 +20,13 @@
 ## Building.  ##
 ## ---------- ##
 
+if %?FIRST%
 JAVAC = javac
 CLASSPATH_ENV = CLASSPATH=$(JAVAROOT):$(srcdir)/$(JAVAROOT):$$CLASSPATH
 JAVAROOT = $(top_builddir)
+endif %?FIRST%
 
-class%DIR%.stamp: $(%DIR%_JAVA)
+class%NDIR%.stamp: $(am__java_sources)
 	@list1='$?'; list2=; if test -n "$$list1"; then \
 	  for p in $$list1; do \
 	    if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
@@ -33,7 +35,7 @@ class%DIR%.stamp: $(%DIR%_JAVA)
 	  echo '$(CLASSPATH_ENV) $(JAVAC) -d $(JAVAROOT) $(AM_JAVACFLAGS) $(JAVACFLAGS) '"$$list2"; \
 	  $(CLASSPATH_ENV) $(JAVAC) -d $(JAVAROOT) $(AM_JAVACFLAGS) $(JAVACFLAGS) $$list2; \
 	else :; fi
-	echo timestamp > class%DIR%.stamp
+	echo timestamp > $@

 ## ------------ ##
@@ -44,7 +46,7 @@ if %?INSTALL%
 am__installdirs += "$(DESTDIR)$(%NDIR%dir)"
 ?EXEC?.PHONY install-exec-am: install-%DIR%JAVA
 ?!EXEC?.PHONY install-data-am: install-%DIR%JAVA
-install-%DIR%JAVA: class%DIR%.stamp
+install-%DIR%JAVA: class%NDIR%.stamp
 	@$(NORMAL_INSTALL)
 	test -z "$(%NDIR%dir)" || $(MKDIR_P) "$(DESTDIR)$(%NDIR%dir)"
 ## A single .java file can be compiled into multiple .class files.  So
@@ -76,9 +78,9 @@ endif %?INSTALL%
 ## Cleaning.  ##
 ## ---------- ##
 
-.PHONY clean-am: clean-%DIR%JAVA
-clean-%DIR%JAVA:
-	-rm -f *.class class%DIR%.stamp
+.PHONY clean-am: clean-%NDIR%JAVA
+clean-%NDIR%JAVA:
+	-rm -f *.class class%NDIR%.stamp

 ## -------------- ##
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 96b7e89..5ed38a1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -422,10 +422,15 @@ java.test \
 java2.test \
 java3.test \
 java-check.test \
+java-clean.test \
 javaprim.test \
 javasubst.test \
 java-extra.test \
 java-noinst.test \
+java-compile-install.test \
+java-sources.test \
+java-no-duplicate.test \
+java-mix-dist-nodist.test \
 ldadd.test \
 ldflags.test \
 lex.test \
diff --git a/tests/Makefile.in b/tests/Makefile.in
index dce3a00..b467e35 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -692,10 +692,15 @@ java.test \
 java2.test \
 java3.test \
 java-check.test \
+java-clean.test \
 javaprim.test \
 javasubst.test \
 java-extra.test \
 java-noinst.test \
+java-compile-install.test \
+java-sources.test \
+java-no-duplicate.test \
+java-mix-dist-nodist.test \
 ldadd.test \
 ldflags.test \
 lex.test \
diff --git a/tests/java-clean.test b/tests/java-clean.test
new file mode 100755
index 0000000..4dcc966
--- /dev/null
+++ b/tests/java-clean.test
@@ -0,0 +1,57 @@
+#! /bin/sh
+# Copyright (C) 1998, 2001, 2002, 2004, 2007  Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test cleaning of Java class files and timestamps.
+
+required=javac
+. ./defs || Exit 1
+
+set -e
+
+cat >> configure.in <<'END'
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+javadir = $(datadir)/java
+java_JAVA = Class.java
+dist_java_JAVA = ClassDist.java
+nodist_java_JAVA = ClassNoDist.java
+END
+
+echo 'class Class {}' > Class.java
+echo 'class ClassDist {}' > ClassDist.java
+echo 'class ClassNoDist {}' > ClassNoDist.java
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE
+
+./configure
+$MAKE
+ls -l
+test -f classjava.stamp
+test -f Class.class
+test -f ClassDist.class
+test -f ClassNoDist.class
+$MAKE clean
+find . -name '*.class' -o -name '*.stamp' | grep . && Exit 1
+# We should not remove unrelated stamp files.
+echo timestamp > classjava2.stamp
+$MAKE clean
+test -f classjava2.stamp
+
+:
diff --git a/tests/java-compile-install.test b/tests/java-compile-install.test
new file mode 100755
index 0000000..b2145fb
--- /dev/null
+++ b/tests/java-compile-install.test
@@ -0,0 +1,86 @@
+#! /bin/sh
+# Copyright (C) 1998, 2001, 2002, 2004, 2007  Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test on compilation and installation of Java class files.
+
+required=javac
+. ./defs || Exit 1
+
+set -e
+
+cat >>configure.in <<'EOF'
+AC_OUTPUT
+EOF
+
+cat > Makefile.am << 'END'
+javadir = $(datadir)/java
+java_JAVA = Foo.java
+dist_java_JAVA = Bar.java
+nodist_java_JAVA = Baz.java
+
+# Java files are not distributed by default.
+EXTRA_DIST = Foo.java
+
+Baz.java:
+	rm -f $@ $@-t
+	echo 'class Baz {}' > $@-t
+	echo 'class Baz2 {}' >> $@-t
+	chmod a-w $@-t && mv -f $@-t $@
+
+test:
+	ls -l $(srcdir) . ;: For debugging.
+	test   -f $(srcdir)/Foo.java
+	test   -f $(srcdir)/Bar.java
+	test   -f Baz.java
+	test   -f aClass.class
+	test   -f Zardoz.class
+	test   -f Baz.class
+	test   -f Baz2.class
+	test ! -r Foo.class
+	test ! -r Bar.class
+
+test-install:
+	find $(prefix) ;: For debugging.
+	test   -f '$(javadir)/aClass.class'
+	test   -f '$(javadir)/Zardoz.class'
+	test   -f '$(javadir)/Baz.class'
+	test   -f '$(javadir)/Baz2.class'
+	test ! -r '$(javadir)/Foo.class'
+	test ! -r '$(javadir)/Bar.class'
+
+check-local: test
+installcheck-local: test-install
+
+.PHONY: test test-install
+
+DISTCLEANFILES = Baz.java
+END
+
+echo 'class aClass {}' > Foo.java
+echo 'class Zardoz {}' > Bar.java
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE
+
+./configure --prefix="`pwd`"/_inst
+$MAKE
+$MAKE test
+$MAKE install
+$MAKE test-install
+$MAKE distcheck
+
+:
diff --git a/tests/java-mix-dist-nodist.test b/tests/java-mix-dist-nodist.test
new file mode 100755
index 0000000..786f400
--- /dev/null
+++ b/tests/java-mix-dist-nodist.test
@@ -0,0 +1,56 @@
+#! /bin/sh
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Check that the JAVA primary can be used with both `dist_' and `nodist_'
+# modifiers in the same directory.
+
+. ./defs || Exit 1
+
+cat >> configure.in << 'END'
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+# This test does not require compilation of *.java files.
+JAVAC = false
+javadir = $(prefix)
+java_JAVA = Class1.java
+dist_java_JAVA = Class2.java
+nodist_java_JAVA = Class3.java
+Class3.java:
+	@echo '$@ should not be generated!' >&2; exit 1
+END
+
+: > Class1.java
+: > Class2.java
+
+$ACLOCAL
+$AUTOCONF
+# Automake used to display non-fatal warnings with this test,
+# but those must be seen as a failure by us.
+$AUTOMAKE 2>stderr || { cat stderr >&2; Exit 1; }
+cat stderr >&2
+test ! -s stderr
+
+./configure
+
+$MAKE distdir
+ls -l $distdir # For debugging.
+test -f $distdir/Class1.java
+test -f $distdir/Class2.java
+test ! -f $distdir/Class3.java
+
+:
diff --git a/tests/java-no-duplicate.test b/tests/java-no-duplicate.test
new file mode 100755
index 0000000..d5fec4b
--- /dev/null
+++ b/tests/java-no-duplicate.test
@@ -0,0 +1,44 @@
+#! /bin/sh
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test that some Java-related variables and rules are not repeatedly
+# defined.
+
+. ./defs || Exit 1
+
+set -e
+
+cat > Makefile.am << 'END'
+javadir = $(datadir)/java
+java_JAVA = a.java
+dist_java_JAVA = b.java
+nodist_java_JAVA = c.java
+END
+
+$ACLOCAL
+$AUTOMAKE
+
+$EGREP -i '\.stamp|\.class|java|classpath' Makefile.in # For debugging.
+
+for var in JAVAC JAVAROOT CLASSPATH_ENV am__java_sources; do
+  grep "^$var =" Makefile.in
+  test `grep -c "^[$sp$tab]*$var[$sp$tab]*=" Makefile.in` = 1
+done
+
+grep '^classjava\.stamp:' Makefile.in
+test `grep -c "class.*java.*\.stamp.*:" Makefile.in` = 1
+
+:
diff --git a/tests/java-sources.test b/tests/java-sources.test
new file mode 100755
index 0000000..4a489e4
--- /dev/null
+++ b/tests/java-sources.test
@@ -0,0 +1,61 @@
+#! /bin/sh
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test definition of automake-generated private Makefile variable
+# `$(am__java_sources)'.
+
+. ./defs || Exit 1
+
+set -e
+
+cat >> configure.in << 'END'
+AC_OUTPUT
+END
+
+cat > Makefile.am << 'END'
+foodir = $(prefix)
+
+foo_JAVA = a.java
+dist_foo_JAVA = b.java
+nodist_foo_JAVA = c.java
+
+.PHONY: debug
+debug:
+	@echo 'am__java_sources: "$(am__java_sources)"'
+got:
+	@lst='$(am__java_sources)'; \
+         for f in $$lst; do echo $$f; done | sort > $@
+END
+
+$ACLOCAL
+$AUTOMAKE
+$AUTOCONF
+
+cat > exp << 'END'
+a.java
+b.java
+c.java
+END
+
+./configure
+$MAKE debug
+$MAKE got
+
+cat got
+cat exp
+diff exp got
+
+:
diff --git a/tests/java.test b/tests/java.test
index cae56dc..4aa91d0 100755
--- a/tests/java.test
+++ b/tests/java.test
@@ -1,5 +1,6 @@
 #! /bin/sh
-# Copyright (C) 1998, 2001, 2002, 2004, 2007  Free Software Foundation, Inc.
+# Copyright (C) 1998, 2001, 2002, 2004, 2007, 2011 Free Software
+# Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -25,7 +26,6 @@ cat >>configure.in <<'EOF'
 AC_OUTPUT
 EOF
 
-
 cat > Makefile.am << 'END'
 javadir = $(datadir)/java
 dist_java_JAVA = a.java b.java
@@ -34,7 +34,10 @@ END
 $ACLOCAL
 $AUTOCONF
 $AUTOMAKE
-grep '^all[-a-z]*:.*classdist_java\.stamp' Makefile.in
+
+$EGREP '\.stamp|class' Makefile.in # For debugging.
+grep '^all[-a-z]*:.*classjava\.stamp' Makefile.in
+test `grep -c '^all[-a-z]*:.*classjava\.stamp' Makefile.in` -eq 1
 
 cat >a.java <<EOF
 class a
-- 
1.7.2.3