Subject: bug#9306: Java build errors due to trailing colon in CLASSPATH

From: Stefano Lattarini <[email-masked]>
Date: Tue, 16 Aug 2011 15:30:59 +0200

Hi Daniel, thanks for the report.

On Monday 15 August 2011, Daniel Richard wrote:
> I am using Automake 1.11.1, and have recently encountered a subtle issue
> that causes compilation of some Java programs to fail.
> 
> Here is a typical build failure, produced from a minimal test case I've
> assembled, using OpenJDK on Ubuntu's Natty release:
> 
> make[3]: Entering directory `/tmp/automake-java-bug/org/gnu/bug'
> CLASSPATH=../../..:./../../..:$CLASSPATH javac -d ../../..    Library.java Application.java
> ./Library.java:5: duplicate class: org.gnu.bug.Library
> public class Library
>        ^
> Application.java:9: cannot access Library
> bad class file: RegularFileObject[./Library.java]
> file does not contain class Library
> Please remove or make sure it appears in the correct subdirectory of the classpath.
> 		Library lib = new Library();
> 		^
> 2 errors
> make[3]: *** [classdist_noinst.stamp] Error 1
> 
> 
> If I copy-and-paste the javac invocation, edit it slightly, and run
> it...
> 
>     env CLASSPATH=../../..:./../../..: javac -d ../../.. Library.java Application.java
> 
> ...I get the same error. However, if I remove that trailing colon from
> CLASSPATH, and try it again...
> 
>     env CLASSPATH=../../..:./../../.. javac -d ../../.. Library.java Application.java
> 
> ...compilation succeeds. If I invoke the above build with
> 
>     env CLASSPATH=/does-not-exist make
> 
> then compilation likewise succeeds.
> 
> Note that I do not have CLASSPATH set in my environment. It would appear
> that a trailing colon in the CLASSPATH environment variable has a
> special meaning attached to it, which makes Automake's use of
> CLASSPATH=mumblemumble:$$CLASSPATH in makefiles problematic.
> 
> (The straightforward solution would be to replace that construct with
> CLASSPATH=mumblemumble$${CLASSPATH:+:$$CLASSPATH}, but whether all
> shells can handle that is an open question.)
>
Luckily, as far as I know, the above construct should be portable to all
non-museum shells.  So I've used it with only a minor modification (with
the only purpose of making the contruct slighlty clearer):

  CLASSPATH=mumblemumble$${CLASSPATH:+":$$CLASSPATH"}

> Attached is a tarball containing the minimal test case.
> 
I can reproduce the problem using your test case, and fix it using your
suggestion.  I've preparad the attached patch, which I will push in a
couple of days if there are no further comments.

BTW, are you the same "Daniel Richard G." listed in THANKS with the address
"[email-masked]"?  If yes, should I update your address there?

Thanks,
  Stefano
From 7f1cf56ba7d1b36fb4c9464f8ed7d10ad44e65a9 Mon Sep 17 00:00:00 2001
Message-Id: <7f1cf56ba[email-masked]>
From: Daniel Richard G <[email-masked]>
Date: Tue, 16 Aug 2011 15:19:14 +0200
Subject: [PATCH] java: avoid compilation errors when CLASSPATH is empty

* lib/am/java.am (CLASSPATH_ENV): When redefining `$CLASSPATH',
do not append an empty component in case the previous value of
CLASSPATH is empty or unset.
* tests/java-empty-classpath.test: New test.
* tests/Makefile.am (TESTS): Update.

Fixes automake bug#9306.
---
 ChangeLog                       |   11 +++++
 lib/am/java.am                  |    2 +-
 tests/java-empty-classpath.test |   90 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+), 1 deletions(-)
 create mode 100755 tests/java-empty-classpath.test

diff --git a/ChangeLog b/ChangeLog
index af2556f..c9ce830 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-08-16  Daniel Richard G. <[email-masked]>  (tiny change)
+	    Stefano Lattarini  <[email-masked]>
+
+	java: avoid compilation errors when CLASSPATH is empty
+	* lib/am/java.am (CLASSPATH_ENV): When redefining `$CLASSPATH',
+	do not append an empty component in case the previous value of
+	CLASSPATH is empty or unset.
+	* tests/java-empty-classpath.test: New test.
+	* tests/Makefile.am (TESTS): Update.
+	Fixes automake bug#9306.
+
 2011-08-08  Stefano Lattarini  <[email-masked]>
 
 	test defs: more environment cleanup
diff --git a/lib/am/java.am b/lib/am/java.am
index d6eb455..604df22 100644
--- a/lib/am/java.am
+++ b/lib/am/java.am
@@ -21,7 +21,7 @@
 ## ---------- ##
 
 JAVAC = javac
-CLASSPATH_ENV = CLASSPATH=$(JAVAROOT):$(srcdir)/$(JAVAROOT):$$CLASSPATH
+CLASSPATH_ENV = CLASSPATH=$(JAVAROOT):$(srcdir)/$(JAVAROOT)$${CLASSPATH:+":$$CLASSPATH"}
 JAVAROOT = $(top_builddir)
 
 class%DIR%.stamp: $(%DIR%_JAVA)
diff --git a/tests/java-empty-classpath.test b/tests/java-empty-classpath.test
new file mode 100755
index 0000000..230bb7c
--- /dev/null
+++ b/tests/java-empty-classpath.test
@@ -0,0 +1,90 @@
+#! /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/>.
+
+# Java compilation works also when CLASSPATH is unset or empty at
+# compilation time.  See automake bug#9306.
+
+required=javac
+. ./defs || Exit 1
+
+set -e
+
+cat >> configure.in <<'END'
+AC_CONFIG_SRCDIR([org/gnu/bug/Library.java])
+AC_CONFIG_FILES([
+    org/Makefile
+    org/gnu/Makefile
+    org/gnu/bug/Makefile
+])
+AC_OUTPUT
+END
+
+mkdir org org/gnu org/gnu/bug
+cat > Makefile.am <<END
+CLEANFILES = *.class
+SUBDIRS = org
+END
+echo SUBDIRS = gnu > org/Makefile.am 
+echo SUBDIRS = bug > org/gnu/Makefile.am 
+cat > org/gnu/bug/Makefile.am <<'END'
+JAVAROOT = ../../..
+dist_noinst_JAVA = Library.java Application.java
+END
+
+cat > org/gnu/bug/Library.java <<'END'
+package org.gnu.bug;
+public class Library
+{
+    public Library ()
+    {
+      // Nothing to do.
+    }
+    public static void doSomethingUseful (String arg)
+    {
+      System.out.println (arg);
+    }
+}
+END
+
+cat > org/gnu/bug/Application.java <<'END'
+import org.gnu.bug.*;
+public class Application
+{
+    public static void main (String args[])
+    {
+        Library lib = new Library ();
+        lib.doSomethingUseful ("PLUGH");
+    }
+}
+END
+
+$ACLOCAL
+$AUTOCONF
+$AUTOMAKE
+./configure
+
+unset CLASSPATH || :
+$MAKE
+$MAKE clean
+
+CLASSPATH=''; export CLASSPATH
+$MAKE
+$MAKE clean
+
+unset CLASSPATH || :
+$MAKE distcheck
+
+:
-- 
1.7.2.3