• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/gettext-0.17/gettext-tools/gnulib-lib/
1/* Compile a Java program.
2   Copyright (C) 2001-2003, 2006-2007 Free Software Foundation, Inc.
3   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19#include <alloca.h>
20
21/* Specification.  */
22#include "javacomp.h"
23
24#include <errno.h>
25#include <limits.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include "javaversion.h"
34#include "execute.h"
35#include "pipe.h"
36#include "wait-process.h"
37#include "classpath.h"
38#include "xsetenv.h"
39#include "sh-quote.h"
40#include "binary-io.h"
41#include "safe-read.h"
42#include "xalloc.h"
43#include "xmalloca.h"
44#include "filename.h"
45#include "fwriteerror.h"
46#include "clean-temp.h"
47#include "error.h"
48#include "xvasprintf.h"
49#include "c-strstr.h"
50#include "gettext.h"
51
52#define _(str) gettext (str)
53
54/* The results of open() in this file are not used with fchdir,
55   therefore save some unnecessary work in fchdir.c.  */
56#undef open
57#undef close
58
59
60/* Survey of Java compilers.
61
62   A = does it work without CLASSPATH being set
63   C = option to set CLASSPATH, other than setting it in the environment
64   O = option for optimizing
65   g = option for debugging
66   T = test for presence
67
68   Program  from        A  C               O  g  T
69
70   $JAVAC   unknown     N  n/a            -O -g  true
71   gcj -C   GCC 3.2     Y  --classpath=P  -O -g  gcj --version | sed -e 's,^[^0-9]*,,' -e 1q | sed -e '/^3\.[01]/d' | grep '^[3-9]' >/dev/null
72   javac    JDK 1.1.8   Y  -classpath P   -O -g  javac 2>/dev/null; test $? = 1
73   javac    JDK 1.3.0   Y  -classpath P   -O -g  javac 2>/dev/null; test $? -le 2
74   jikes    Jikes 1.14  N  -classpath P   -O -g  jikes 2>/dev/null; test $? = 1
75
76   All compilers support the option "-d DIRECTORY" for the base directory
77   of the classes to be written.
78
79   The CLASSPATH is a colon separated list of pathnames. (On Windows: a
80   semicolon separated list of pathnames.)
81
82   We try the Java compilers in the following order:
83     1. getenv ("JAVAC"), because the user must be able to override our
84	preferences,
85     2. "gcj -C", because it is a completely free compiler,
86     3. "javac", because it is a standard compiler,
87     4. "jikes", comes last because it has some deviating interpretation
88	of the Java Language Specification and because it requires a
89	CLASSPATH environment variable.
90
91   We unset the JAVA_HOME environment variable, because a wrong setting of
92   this variable can confuse the JDK's javac.
93 */
94
95/* Return the default target_version.  */
96static const char *
97default_target_version (void)
98{
99  /* Use a cache.  Assumes that the PATH environment variable doesn't change
100     during the lifetime of the program.  */
101  static const char *java_version_cache;
102  if (java_version_cache == NULL)
103    {
104      /* Determine the version from the found JVM.  */
105      java_version_cache = javaexec_version ();
106      if (java_version_cache == NULL
107	  || !(java_version_cache[0] == '1' && java_version_cache[1] == '.'
108	       && (java_version_cache[2] >= '1' && java_version_cache[2] <= '6')
109	       && java_version_cache[3] == '\0'))
110	java_version_cache = "1.1";
111    }
112  return java_version_cache;
113}
114
115/* ======================= Source version dependent ======================= */
116
117/* Convert a source version to an index.  */
118#define SOURCE_VERSION_BOUND 3 /* exclusive upper bound */
119static unsigned int
120source_version_index (const char *source_version)
121{
122  if (source_version[0] == '1' && source_version[1] == '.'
123      && (source_version[2] >= '3' && source_version[2] <= '5')
124      && source_version[3] == '\0')
125    return source_version[2] - '3';
126  error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class"));
127  return 0;
128}
129
130/* Return a snippet of code that should compile in the given source version.  */
131static const char *
132get_goodcode_snippet (const char *source_version)
133{
134  if (strcmp (source_version, "1.3") == 0)
135    return "class conftest {}\n";
136  if (strcmp (source_version, "1.4") == 0)
137    return "class conftest { static { assert(true); } }\n";
138  if (strcmp (source_version, "1.5") == 0)
139    return "class conftest<T> { T foo() { return null; } }\n";
140  error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class"));
141  return NULL;
142}
143
144/* Return a snippet of code that should fail to compile in the given source
145   version, or NULL (standing for a snippet that would fail to compile with
146   any compiler).  */
147static const char *
148get_failcode_snippet (const char *source_version)
149{
150  if (strcmp (source_version, "1.3") == 0)
151    return "class conftestfail { static { assert(true); } }\n";
152  if (strcmp (source_version, "1.4") == 0)
153    return "class conftestfail<T> { T foo() { return null; } }\n";
154  if (strcmp (source_version, "1.5") == 0)
155    return NULL;
156  error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class"));
157  return NULL;
158}
159
160/* ======================= Target version dependent ======================= */
161
162/* Convert a target version to an index.  */
163#define TARGET_VERSION_BOUND 6 /* exclusive upper bound */
164static unsigned int
165target_version_index (const char *target_version)
166{
167  if (target_version[0] == '1' && target_version[1] == '.'
168      && (target_version[2] >= '1' && target_version[2] <= '6')
169      && target_version[3] == '\0')
170    return target_version[2] - '1';
171  error (EXIT_FAILURE, 0, _("invalid target_version argument to compile_java_class"));
172  return 0;
173}
174
175/* Return the class file version number corresponding to a given target
176   version.  */
177static int
178corresponding_classfile_version (const char *target_version)
179{
180  if (strcmp (target_version, "1.1") == 0)
181    return 45;
182  if (strcmp (target_version, "1.2") == 0)
183    return 46;
184  if (strcmp (target_version, "1.3") == 0)
185    return 47;
186  if (strcmp (target_version, "1.4") == 0)
187    return 48;
188  if (strcmp (target_version, "1.5") == 0)
189    return 49;
190  if (strcmp (target_version, "1.6") == 0)
191    return 50;
192  error (EXIT_FAILURE, 0, _("invalid target_version argument to compile_java_class"));
193  return 0;
194}
195
196/* ======================== Compilation subroutines ======================== */
197
198/* Try to compile a set of Java sources with $JAVAC.
199   Return a failure indicator (true upon error).  */
200static bool
201compile_using_envjavac (const char *javac,
202			const char * const *java_sources,
203			unsigned int java_sources_count,
204			const char *directory,
205			bool optimize, bool debug,
206			bool verbose, bool null_stderr)
207{
208  /* Because $JAVAC may consist of a command and options, we use the
209     shell.  Because $JAVAC has been set by the user, we leave all
210     environment variables in place, including JAVA_HOME, and we don't
211     erase the user's CLASSPATH.  */
212  bool err;
213  unsigned int command_length;
214  char *command;
215  char *argv[4];
216  int exitstatus;
217  unsigned int i;
218  char *p;
219
220  command_length = strlen (javac);
221  if (optimize)
222    command_length += 3;
223  if (debug)
224    command_length += 3;
225  if (directory != NULL)
226    command_length += 4 + shell_quote_length (directory);
227  for (i = 0; i < java_sources_count; i++)
228    command_length += 1 + shell_quote_length (java_sources[i]);
229  command_length += 1;
230
231  command = (char *) xmalloca (command_length);
232  p = command;
233  /* Don't shell_quote $JAVAC, because it may consist of a command
234     and options.  */
235  memcpy (p, javac, strlen (javac));
236  p += strlen (javac);
237  if (optimize)
238    {
239      memcpy (p, " -O", 3);
240      p += 3;
241    }
242  if (debug)
243    {
244      memcpy (p, " -g", 3);
245      p += 3;
246    }
247  if (directory != NULL)
248    {
249      memcpy (p, " -d ", 4);
250      p += 4;
251      p = shell_quote_copy (p, directory);
252    }
253  for (i = 0; i < java_sources_count; i++)
254    {
255      *p++ = ' ';
256      p = shell_quote_copy (p, java_sources[i]);
257    }
258  *p++ = '\0';
259  /* Ensure command_length was correctly calculated.  */
260  if (p - command > command_length)
261    abort ();
262
263  if (verbose)
264    printf ("%s\n", command);
265
266  argv[0] = "/bin/sh";
267  argv[1] = "-c";
268  argv[2] = command;
269  argv[3] = NULL;
270  exitstatus = execute (javac, "/bin/sh", argv, false, false, false,
271			null_stderr, true, true);
272  err = (exitstatus != 0);
273
274  freea (command);
275
276  return err;
277}
278
279/* Try to compile a set of Java sources with gcj.
280   Return a failure indicator (true upon error).  */
281static bool
282compile_using_gcj (const char * const *java_sources,
283		   unsigned int java_sources_count,
284		   bool no_assert_option,
285		   bool fsource_option, const char *source_version,
286		   bool ftarget_option, const char *target_version,
287		   const char *directory,
288		   bool optimize, bool debug,
289		   bool verbose, bool null_stderr)
290{
291  bool err;
292  unsigned int argc;
293  char **argv;
294  char **argp;
295  char *fsource_arg;
296  char *ftarget_arg;
297  int exitstatus;
298  unsigned int i;
299
300  argc =
301    2 + (no_assert_option ? 1 : 0) + (fsource_option ? 1 : 0)
302    + (ftarget_option ? 1 : 0) + (optimize ? 1 : 0) + (debug ? 1 : 0)
303    + (directory != NULL ? 2 : 0) + java_sources_count;
304  argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
305
306  argp = argv;
307  *argp++ = "gcj";
308  *argp++ = "-C";
309  if (no_assert_option)
310    *argp++ = "-fno-assert";
311  if (fsource_option)
312    {
313      fsource_arg = (char *) xmalloca (9 + strlen (source_version) + 1);
314      memcpy (fsource_arg, "-fsource=", 9);
315      strcpy (fsource_arg + 9, source_version);
316      *argp++ = fsource_arg;
317    }
318  else
319    fsource_arg = NULL;
320  if (ftarget_option)
321    {
322      ftarget_arg = (char *) xmalloca (9 + strlen (target_version) + 1);
323      memcpy (ftarget_arg, "-ftarget=", 9);
324      strcpy (ftarget_arg + 9, target_version);
325      *argp++ = ftarget_arg;
326    }
327  else
328    ftarget_arg = NULL;
329  if (optimize)
330    *argp++ = "-O";
331  if (debug)
332    *argp++ = "-g";
333  if (directory != NULL)
334    {
335      *argp++ = "-d";
336      *argp++ = (char *) directory;
337    }
338  for (i = 0; i < java_sources_count; i++)
339    *argp++ = (char *) java_sources[i];
340  *argp = NULL;
341  /* Ensure argv length was correctly calculated.  */
342  if (argp - argv != argc)
343    abort ();
344
345  if (verbose)
346    {
347      char *command = shell_quote_argv (argv);
348      printf ("%s\n", command);
349      free (command);
350    }
351
352  exitstatus = execute ("gcj", "gcj", argv, false, false, false, null_stderr,
353			true, true);
354  err = (exitstatus != 0);
355
356  if (ftarget_arg != NULL)
357    freea (ftarget_arg);
358  if (fsource_arg != NULL)
359    freea (fsource_arg);
360  freea (argv);
361
362  return err;
363}
364
365/* Try to compile a set of Java sources with javac.
366   Return a failure indicator (true upon error).  */
367static bool
368compile_using_javac (const char * const *java_sources,
369		     unsigned int java_sources_count,
370		     bool source_option, const char *source_version,
371		     bool target_option, const char *target_version,
372		     const char *directory,
373		     bool optimize, bool debug,
374		     bool verbose, bool null_stderr)
375{
376  bool err;
377  unsigned int argc;
378  char **argv;
379  char **argp;
380  int exitstatus;
381  unsigned int i;
382
383  argc =
384    1 + (source_option ? 2 : 0) + (target_option ? 2 : 0) + (optimize ? 1 : 0)
385    + (debug ? 1 : 0) + (directory != NULL ? 2 : 0) + java_sources_count;
386  argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
387
388  argp = argv;
389  *argp++ = "javac";
390  if (source_option)
391    {
392      *argp++ = "-source";
393      *argp++ = (char *) source_version;
394    }
395  if (target_option)
396    {
397      *argp++ = "-target";
398      *argp++ = (char *) target_version;
399    }
400  if (optimize)
401    *argp++ = "-O";
402  if (debug)
403    *argp++ = "-g";
404  if (directory != NULL)
405    {
406      *argp++ = "-d";
407      *argp++ = (char *) directory;
408    }
409  for (i = 0; i < java_sources_count; i++)
410    *argp++ = (char *) java_sources[i];
411  *argp = NULL;
412  /* Ensure argv length was correctly calculated.  */
413  if (argp - argv != argc)
414    abort ();
415
416  if (verbose)
417    {
418      char *command = shell_quote_argv (argv);
419      printf ("%s\n", command);
420      free (command);
421    }
422
423  exitstatus = execute ("javac", "javac", argv, false, false, false,
424			null_stderr, true, true);
425  err = (exitstatus != 0);
426
427  freea (argv);
428
429  return err;
430}
431
432/* Try to compile a set of Java sources with jikes.
433   Return a failure indicator (true upon error).  */
434static bool
435compile_using_jikes (const char * const *java_sources,
436		     unsigned int java_sources_count,
437		     const char *directory,
438		     bool optimize, bool debug,
439		     bool verbose, bool null_stderr)
440{
441  bool err;
442  unsigned int argc;
443  char **argv;
444  char **argp;
445  int exitstatus;
446  unsigned int i;
447
448  argc =
449    1 + (optimize ? 1 : 0) + (debug ? 1 : 0) + (directory != NULL ? 2 : 0)
450    + java_sources_count;
451  argv = (char **) xmalloca ((argc + 1) * sizeof (char *));
452
453  argp = argv;
454  *argp++ = "jikes";
455  if (optimize)
456    *argp++ = "-O";
457  if (debug)
458    *argp++ = "-g";
459  if (directory != NULL)
460    {
461      *argp++ = "-d";
462      *argp++ = (char *) directory;
463    }
464  for (i = 0; i < java_sources_count; i++)
465    *argp++ = (char *) java_sources[i];
466  *argp = NULL;
467  /* Ensure argv length was correctly calculated.  */
468  if (argp - argv != argc)
469    abort ();
470
471  if (verbose)
472    {
473      char *command = shell_quote_argv (argv);
474      printf ("%s\n", command);
475      free (command);
476    }
477
478  exitstatus = execute ("jikes", "jikes", argv, false, false, false,
479			null_stderr, true, true);
480  err = (exitstatus != 0);
481
482  freea (argv);
483
484  return err;
485}
486
487/* ====================== Usability test subroutines ====================== */
488
489/* Write a given contents to a temporary file.
490   FILE_NAME is the name of a file inside TMPDIR that is known not to exist
491   yet.
492   Return a failure indicator (true upon error).  */
493static bool
494write_temp_file (struct temp_dir *tmpdir, const char *file_name,
495		 const char *contents)
496{
497  FILE *fp;
498
499  register_temp_file (tmpdir, file_name);
500  fp = fopen_temp (file_name, "w");
501  if (fp == NULL)
502    {
503      error (0, errno, _("failed to create \"%s\""), file_name);
504      unregister_temp_file (tmpdir, file_name);
505      return true;
506    }
507  fputs (contents, fp);
508  if (fwriteerror_temp (fp))
509    {
510      error (0, errno, _("error while writing \"%s\" file"), file_name);
511      return true;
512    }
513  return false;
514}
515
516/* Return the class file version number of a class file on disk.  */
517static int
518get_classfile_version (const char *compiled_file_name)
519{
520  unsigned char header[8];
521  int fd;
522
523  /* Open the class file.  */
524  fd = open (compiled_file_name, O_RDONLY | O_BINARY, 0);
525  if (fd >= 0)
526    {
527      /* Read its first 8 bytes.  */
528      if (safe_read (fd, header, 8) == 8)
529	{
530	  /* Verify the class file signature.  */
531	  if (header[0] == 0xCA && header[1] == 0xFE
532	      && header[2] == 0xBA && header[3] == 0xBE)
533	    return header[7];
534	}
535      close (fd);
536    }
537
538  /* Could not get the class file version.  Return a very large one.  */
539  return INT_MAX;
540}
541
542/* Return true if $JAVAC is a version of gcj.  */
543static bool
544is_envjavac_gcj (const char *javac)
545{
546  static bool envjavac_tested;
547  static bool envjavac_gcj;
548
549  if (!envjavac_tested)
550    {
551      /* Test whether $JAVAC is gcj:
552	 "$JAVAC --version 2>/dev/null | sed -e 1q | grep gcj > /dev/null"  */
553      unsigned int command_length;
554      char *command;
555      char *argv[4];
556      pid_t child;
557      int fd[1];
558      FILE *fp;
559      char *line;
560      size_t linesize;
561      size_t linelen;
562      int exitstatus;
563      char *p;
564
565      /* Setup the command "$JAVAC --version".  */
566      command_length = strlen (javac) + 1 + 9 + 1;
567      command = (char *) xmalloca (command_length);
568      p = command;
569      /* Don't shell_quote $JAVAC, because it may consist of a command
570	 and options.  */
571      memcpy (p, javac, strlen (javac));
572      p += strlen (javac);
573      memcpy (p, " --version", 1 + 9 + 1);
574      p += 1 + 9 + 1;
575      /* Ensure command_length was correctly calculated.  */
576      if (p - command > command_length)
577	abort ();
578
579      /* Call $JAVAC --version 2>/dev/null.  */
580      argv[0] = "/bin/sh";
581      argv[1] = "-c";
582      argv[2] = command;
583      argv[3] = NULL;
584      child = create_pipe_in (javac, "/bin/sh", argv, DEV_NULL, true, true,
585			      false, fd);
586      if (child == -1)
587	goto failed;
588
589      /* Retrieve its result.  */
590      fp = fdopen (fd[0], "r");
591      if (fp == NULL)
592	goto failed;
593
594      line = NULL; linesize = 0;
595      linelen = getline (&line, &linesize, fp);
596      if (linelen == (size_t)(-1))
597	{
598	  fclose (fp);
599	  goto failed;
600	}
601      /* It is safe to call c_strstr() instead of strstr() here; see the
602	 comments in c-strstr.h.  */
603      envjavac_gcj = (c_strstr (line, "gcj") != NULL);
604
605      fclose (fp);
606
607      /* Remove zombie process from process list, and retrieve exit status.  */
608      exitstatus = wait_subprocess (child, javac, true, true, true, false);
609      if (exitstatus != 0)
610	envjavac_gcj = false;
611
612     failed:
613      freea (command);
614
615      envjavac_tested = true;
616    }
617
618  return envjavac_gcj;
619}
620
621/* Return true if $JAVAC, known to be a version of gcj, is a version >= 4.3
622   of gcj.  */
623static bool
624is_envjavac_gcj43 (const char *javac)
625{
626  static bool envjavac_tested;
627  static bool envjavac_gcj43;
628
629  if (!envjavac_tested)
630    {
631      /* Test whether $JAVAC is gcj:
632	 "$JAVAC --version 2>/dev/null | sed -e 's,^[^0-9]*,,' -e 1q \
633	  | sed -e '/^4\.[012]/d' | grep '^[4-9]' >/dev/null"  */
634      unsigned int command_length;
635      char *command;
636      char *argv[4];
637      pid_t child;
638      int fd[1];
639      FILE *fp;
640      char *line;
641      size_t linesize;
642      size_t linelen;
643      int exitstatus;
644      char *p;
645
646      /* Setup the command "$JAVAC --version".  */
647      command_length = strlen (javac) + 1 + 9 + 1;
648      command = (char *) xmalloca (command_length);
649      p = command;
650      /* Don't shell_quote $JAVAC, because it may consist of a command
651	 and options.  */
652      memcpy (p, javac, strlen (javac));
653      p += strlen (javac);
654      memcpy (p, " --version", 1 + 9 + 1);
655      p += 1 + 9 + 1;
656      /* Ensure command_length was correctly calculated.  */
657      if (p - command > command_length)
658	abort ();
659
660      /* Call $JAVAC --version 2>/dev/null.  */
661      argv[0] = "/bin/sh";
662      argv[1] = "-c";
663      argv[2] = command;
664      argv[3] = NULL;
665      child = create_pipe_in (javac, "/bin/sh", argv, DEV_NULL, true, true,
666			      false, fd);
667      if (child == -1)
668	goto failed;
669
670      /* Retrieve its result.  */
671      fp = fdopen (fd[0], "r");
672      if (fp == NULL)
673	goto failed;
674
675      line = NULL; linesize = 0;
676      linelen = getline (&line, &linesize, fp);
677      if (linelen == (size_t)(-1))
678	{
679	  fclose (fp);
680	  goto failed;
681	}
682      p = line;
683      while (*p != '\0' && !(*p >= '0' && *p <= '9'))
684	p++;
685      envjavac_gcj43 =
686        !(*p == '4' && p[1] == '.' && p[2] >= '0' && p[2] <= '2')
687	&& (*p >= '4' && *p <= '9');
688
689      fclose (fp);
690
691      /* Remove zombie process from process list, and retrieve exit status.  */
692      exitstatus = wait_subprocess (child, javac, true, true, true, false);
693      if (exitstatus != 0)
694	envjavac_gcj43 = false;
695
696     failed:
697      freea (command);
698
699      envjavac_tested = true;
700    }
701
702  return envjavac_gcj43;
703}
704
705/* Test whether $JAVAC, known to be a version of gcj >= 4.3, can be used, and
706   whether it needs a -fsource and/or -ftarget option.
707   Return a failure indicator (true upon error).  */
708static bool
709is_envjavac_gcj43_usable (const char *javac,
710			  const char *source_version,
711			  const char *target_version,
712			  bool *usablep,
713			  bool *fsource_option_p, bool *ftarget_option_p)
714{
715  /* The cache depends on the source_version and target_version.  */
716  struct result_t
717  {
718    bool tested;
719    bool usable;
720    bool fsource_option;
721    bool ftarget_option;
722  };
723  static struct result_t result_cache[SOURCE_VERSION_BOUND][TARGET_VERSION_BOUND];
724  struct result_t *resultp;
725
726  resultp = &result_cache[source_version_index (source_version)]
727			 [target_version_index (target_version)];
728  if (!resultp->tested)
729    {
730      /* Try $JAVAC.  */
731      struct temp_dir *tmpdir;
732      char *conftest_file_name;
733      char *compiled_file_name;
734      const char *java_sources[1];
735      struct stat statbuf;
736
737      tmpdir = create_temp_dir ("java", NULL, false);
738      if (tmpdir == NULL)
739	return true;
740
741      conftest_file_name =
742	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
743      if (write_temp_file (tmpdir, conftest_file_name,
744			   get_goodcode_snippet (source_version)))
745	{
746	  free (conftest_file_name);
747	  cleanup_temp_dir (tmpdir);
748	  return true;
749	}
750
751      compiled_file_name =
752	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
753      register_temp_file (tmpdir, compiled_file_name);
754
755      java_sources[0] = conftest_file_name;
756      if (!compile_using_envjavac (javac,
757				   java_sources, 1, tmpdir->dir_name,
758				   false, false, false, true)
759	  && stat (compiled_file_name, &statbuf) >= 0
760	  && get_classfile_version (compiled_file_name)
761	     <= corresponding_classfile_version (target_version))
762	{
763	  /* $JAVAC compiled conftest.java successfully.  */
764	  /* Try adding -fsource option if it is useful.  */
765	  char *javac_source =
766	    xasprintf ("%s -fsource=%s", javac, source_version);
767
768	  unlink (compiled_file_name);
769
770	  java_sources[0] = conftest_file_name;
771	  if (!compile_using_envjavac (javac_source,
772				       java_sources, 1, tmpdir->dir_name,
773				       false, false, false, true)
774	      && stat (compiled_file_name, &statbuf) >= 0
775	      && get_classfile_version (compiled_file_name)
776		 <= corresponding_classfile_version (target_version))
777	    {
778	      const char *failcode = get_failcode_snippet (source_version);
779
780	      if (failcode != NULL)
781		{
782		  free (compiled_file_name);
783		  free (conftest_file_name);
784
785		  conftest_file_name =
786		    concatenated_filename (tmpdir->dir_name,
787					   "conftestfail.java",
788					   NULL);
789		  if (write_temp_file (tmpdir, conftest_file_name, failcode))
790		    {
791		      free (conftest_file_name);
792		      free (javac_source);
793		      cleanup_temp_dir (tmpdir);
794		      return true;
795		    }
796
797		  compiled_file_name =
798		    concatenated_filename (tmpdir->dir_name,
799					   "conftestfail.class",
800					   NULL);
801		  register_temp_file (tmpdir, compiled_file_name);
802
803		  java_sources[0] = conftest_file_name;
804		  if (!compile_using_envjavac (javac,
805					       java_sources, 1,
806					       tmpdir->dir_name,
807					       false, false, false, true)
808		      && stat (compiled_file_name, &statbuf) >= 0)
809		    {
810		      unlink (compiled_file_name);
811
812		      java_sources[0] = conftest_file_name;
813		      if (compile_using_envjavac (javac_source,
814						  java_sources, 1,
815						  tmpdir->dir_name,
816						  false, false, false, true))
817			/* $JAVAC compiled conftestfail.java successfully, and
818			   "$JAVAC -fsource=$source_version" rejects it.  So
819			   the -fsource option is useful.  */
820			resultp->fsource_option = true;
821		    }
822		}
823	    }
824
825	  free (javac_source);
826
827	  resultp->usable = true;
828	}
829      else
830	{
831	  /* Try with -fsource and -ftarget options.  */
832	  char *javac_target =
833	    xasprintf ("%s -fsource=%s -ftarget=%s",
834		       javac, source_version, target_version);
835
836	  unlink (compiled_file_name);
837
838	  java_sources[0] = conftest_file_name;
839	  if (!compile_using_envjavac (javac_target,
840				       java_sources, 1, tmpdir->dir_name,
841				       false, false, false, true)
842	      && stat (compiled_file_name, &statbuf) >= 0
843	      && get_classfile_version (compiled_file_name)
844		 <= corresponding_classfile_version (target_version))
845	    {
846	      /* "$JAVAC -fsource $source_version -ftarget $target_version"
847		 compiled conftest.java successfully.  */
848	      resultp->fsource_option = true;
849	      resultp->ftarget_option = true;
850	      resultp->usable = true;
851	    }
852
853	  free (javac_target);
854	}
855
856      free (compiled_file_name);
857      free (conftest_file_name);
858
859      resultp->tested = true;
860    }
861
862  *usablep = resultp->usable;
863  *fsource_option_p = resultp->fsource_option;
864  *ftarget_option_p = resultp->ftarget_option;
865  return false;
866}
867
868/* Test whether $JAVAC, known to be a version of gcj < 4.3, can be used for
869   compiling with target_version = 1.4 and source_version = 1.4.
870   Return a failure indicator (true upon error).  */
871static bool
872is_envjavac_oldgcj_14_14_usable (const char *javac, bool *usablep)
873{
874  static bool envjavac_tested;
875  static bool envjavac_usable;
876
877  if (!envjavac_tested)
878    {
879      /* Try $JAVAC.  */
880      struct temp_dir *tmpdir;
881      char *conftest_file_name;
882      char *compiled_file_name;
883      const char *java_sources[1];
884      struct stat statbuf;
885
886      tmpdir = create_temp_dir ("java", NULL, false);
887      if (tmpdir == NULL)
888	return true;
889
890      conftest_file_name =
891	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
892      if (write_temp_file (tmpdir, conftest_file_name,
893			   get_goodcode_snippet ("1.4")))
894	{
895	  free (conftest_file_name);
896	  cleanup_temp_dir (tmpdir);
897	  return true;
898	}
899
900      compiled_file_name =
901	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
902      register_temp_file (tmpdir, compiled_file_name);
903
904      java_sources[0] = conftest_file_name;
905      if (!compile_using_envjavac (javac, java_sources, 1, tmpdir->dir_name,
906				   false, false, false, true)
907	  && stat (compiled_file_name, &statbuf) >= 0)
908	/* Compilation succeeded.  */
909	envjavac_usable = true;
910
911      free (compiled_file_name);
912      free (conftest_file_name);
913
914      cleanup_temp_dir (tmpdir);
915
916      envjavac_tested = true;
917    }
918
919  *usablep = envjavac_usable;
920  return false;
921}
922
923/* Test whether $JAVAC, known to be a version of gcj < 4.3, can be used for
924   compiling with target_version = 1.4 and source_version = 1.3.
925   Return a failure indicator (true upon error).  */
926static bool
927is_envjavac_oldgcj_14_13_usable (const char *javac,
928				 bool *usablep, bool *need_no_assert_option_p)
929{
930  static bool envjavac_tested;
931  static bool envjavac_usable;
932  static bool envjavac_need_no_assert_option;
933
934  if (!envjavac_tested)
935    {
936      /* Try $JAVAC and "$JAVAC -fno-assert".  But add -fno-assert only if
937	 it makes a difference.  (It could already be part of $JAVAC.)  */
938      struct temp_dir *tmpdir;
939      char *conftest_file_name;
940      char *compiled_file_name;
941      const char *java_sources[1];
942      struct stat statbuf;
943      bool javac_works;
944      char *javac_noassert;
945      bool javac_noassert_works;
946
947      tmpdir = create_temp_dir ("java", NULL, false);
948      if (tmpdir == NULL)
949	return true;
950
951      conftest_file_name =
952	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
953      if (write_temp_file (tmpdir, conftest_file_name,
954			   get_goodcode_snippet ("1.3")))
955	{
956	  free (conftest_file_name);
957	  cleanup_temp_dir (tmpdir);
958	  return true;
959	}
960
961      compiled_file_name =
962	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
963      register_temp_file (tmpdir, compiled_file_name);
964
965      java_sources[0] = conftest_file_name;
966      if (!compile_using_envjavac (javac,
967				   java_sources, 1, tmpdir->dir_name,
968				   false, false, false, true)
969	  && stat (compiled_file_name, &statbuf) >= 0)
970	/* Compilation succeeded.  */
971	javac_works = true;
972      else
973	javac_works = false;
974
975      unlink (compiled_file_name);
976
977      javac_noassert = xasprintf ("%s -fno-assert", javac);
978
979      java_sources[0] = conftest_file_name;
980      if (!compile_using_envjavac (javac_noassert,
981				   java_sources, 1, tmpdir->dir_name,
982				   false, false, false, true)
983	  && stat (compiled_file_name, &statbuf) >= 0)
984	/* Compilation succeeded.  */
985	javac_noassert_works = true;
986      else
987	javac_noassert_works = false;
988
989      free (compiled_file_name);
990      free (conftest_file_name);
991
992      if (javac_works && javac_noassert_works)
993	{
994	  conftest_file_name =
995	    concatenated_filename (tmpdir->dir_name, "conftestfail.java",
996				   NULL);
997	  if (write_temp_file (tmpdir, conftest_file_name,
998			       get_failcode_snippet ("1.3")))
999	    {
1000	      free (conftest_file_name);
1001	      free (javac_noassert);
1002	      cleanup_temp_dir (tmpdir);
1003	      return true;
1004	    }
1005
1006	  compiled_file_name =
1007	    concatenated_filename (tmpdir->dir_name, "conftestfail.class",
1008				   NULL);
1009	  register_temp_file (tmpdir, compiled_file_name);
1010
1011	  java_sources[0] = conftest_file_name;
1012	  if (!compile_using_envjavac (javac,
1013				       java_sources, 1, tmpdir->dir_name,
1014				       false, false, false, true)
1015	      && stat (compiled_file_name, &statbuf) >= 0)
1016	    {
1017	      /* Compilation succeeded.  */
1018	      unlink (compiled_file_name);
1019
1020	      java_sources[0] = conftest_file_name;
1021	      if (!(!compile_using_envjavac (javac_noassert,
1022					     java_sources, 1, tmpdir->dir_name,
1023					     false, false, false, true)
1024		    && stat (compiled_file_name, &statbuf) >= 0))
1025		/* Compilation failed.  */
1026		/* "$JAVAC -fno-assert" works better than $JAVAC.  */
1027		javac_works = true;
1028	    }
1029
1030	  free (compiled_file_name);
1031	  free (conftest_file_name);
1032	}
1033
1034      cleanup_temp_dir (tmpdir);
1035
1036      if (javac_works)
1037	{
1038	  envjavac_usable = true;
1039	  envjavac_need_no_assert_option = false;
1040	}
1041      else if (javac_noassert_works)
1042	{
1043	  envjavac_usable = true;
1044	  envjavac_need_no_assert_option = true;
1045	}
1046
1047      envjavac_tested = true;
1048    }
1049
1050  *usablep = envjavac_usable;
1051  *need_no_assert_option_p = envjavac_need_no_assert_option;
1052  return false;
1053}
1054
1055/* Test whether $JAVAC, known to be not a version of gcj, can be used, and
1056   whether it needs a -source and/or -target option.
1057   Return a failure indicator (true upon error).  */
1058static bool
1059is_envjavac_nongcj_usable (const char *javac,
1060			   const char *source_version,
1061			   const char *target_version,
1062			   bool *usablep,
1063			   bool *source_option_p, bool *target_option_p)
1064{
1065  /* The cache depends on the source_version and target_version.  */
1066  struct result_t
1067  {
1068    bool tested;
1069    bool usable;
1070    bool source_option;
1071    bool target_option;
1072  };
1073  static struct result_t result_cache[SOURCE_VERSION_BOUND][TARGET_VERSION_BOUND];
1074  struct result_t *resultp;
1075
1076  resultp = &result_cache[source_version_index (source_version)]
1077			 [target_version_index (target_version)];
1078  if (!resultp->tested)
1079    {
1080      /* Try $JAVAC.  */
1081      struct temp_dir *tmpdir;
1082      char *conftest_file_name;
1083      char *compiled_file_name;
1084      const char *java_sources[1];
1085      struct stat statbuf;
1086
1087      tmpdir = create_temp_dir ("java", NULL, false);
1088      if (tmpdir == NULL)
1089	return true;
1090
1091      conftest_file_name =
1092	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
1093      if (write_temp_file (tmpdir, conftest_file_name,
1094			   get_goodcode_snippet (source_version)))
1095	{
1096	  free (conftest_file_name);
1097	  cleanup_temp_dir (tmpdir);
1098	  return true;
1099	}
1100
1101      compiled_file_name =
1102	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
1103      register_temp_file (tmpdir, compiled_file_name);
1104
1105      java_sources[0] = conftest_file_name;
1106      if (!compile_using_envjavac (javac,
1107				   java_sources, 1, tmpdir->dir_name,
1108				   false, false, false, true)
1109	  && stat (compiled_file_name, &statbuf) >= 0
1110	  && get_classfile_version (compiled_file_name)
1111	     <= corresponding_classfile_version (target_version))
1112	{
1113	  /* $JAVAC compiled conftest.java successfully.  */
1114	  /* Try adding -source option if it is useful.  */
1115	  char *javac_source =
1116	    xasprintf ("%s -source %s", javac, source_version);
1117
1118	  unlink (compiled_file_name);
1119
1120	  java_sources[0] = conftest_file_name;
1121	  if (!compile_using_envjavac (javac_source,
1122				       java_sources, 1, tmpdir->dir_name,
1123				       false, false, false, true)
1124	      && stat (compiled_file_name, &statbuf) >= 0
1125	      && get_classfile_version (compiled_file_name)
1126		 <= corresponding_classfile_version (target_version))
1127	    {
1128	      const char *failcode = get_failcode_snippet (source_version);
1129
1130	      if (failcode != NULL)
1131		{
1132		  free (compiled_file_name);
1133		  free (conftest_file_name);
1134
1135		  conftest_file_name =
1136		    concatenated_filename (tmpdir->dir_name,
1137					   "conftestfail.java",
1138					   NULL);
1139		  if (write_temp_file (tmpdir, conftest_file_name, failcode))
1140		    {
1141		      free (conftest_file_name);
1142		      free (javac_source);
1143		      cleanup_temp_dir (tmpdir);
1144		      return true;
1145		    }
1146
1147		  compiled_file_name =
1148		    concatenated_filename (tmpdir->dir_name,
1149					   "conftestfail.class",
1150					   NULL);
1151		  register_temp_file (tmpdir, compiled_file_name);
1152
1153		  java_sources[0] = conftest_file_name;
1154		  if (!compile_using_envjavac (javac,
1155					       java_sources, 1,
1156					       tmpdir->dir_name,
1157					       false, false, false, true)
1158		      && stat (compiled_file_name, &statbuf) >= 0)
1159		    {
1160		      unlink (compiled_file_name);
1161
1162		      java_sources[0] = conftest_file_name;
1163		      if (compile_using_envjavac (javac_source,
1164						  java_sources, 1,
1165						  tmpdir->dir_name,
1166						  false, false, false, true))
1167			/* $JAVAC compiled conftestfail.java successfully, and
1168			   "$JAVAC -source $source_version" rejects it.  So the
1169			   -source option is useful.  */
1170			resultp->source_option = true;
1171		    }
1172		}
1173	    }
1174
1175	  free (javac_source);
1176
1177	  resultp->usable = true;
1178	}
1179      else
1180	{
1181	  /* Try with -target option alone. (Sun javac 1.3.1 has the -target
1182	     option but no -source option.)  */
1183	  char *javac_target =
1184	    xasprintf ("%s -target %s", javac, target_version);
1185
1186	  unlink (compiled_file_name);
1187
1188	  java_sources[0] = conftest_file_name;
1189	  if (!compile_using_envjavac (javac_target,
1190				       java_sources, 1, tmpdir->dir_name,
1191				       false, false, false, true)
1192	      && stat (compiled_file_name, &statbuf) >= 0
1193	      && get_classfile_version (compiled_file_name)
1194		 <= corresponding_classfile_version (target_version))
1195	    {
1196	      /* "$JAVAC -target $target_version" compiled conftest.java
1197		 successfully.  */
1198	      /* Try adding -source option if it is useful.  */
1199	      char *javac_target_source =
1200		xasprintf ("%s -source %s", javac_target, source_version);
1201
1202	      unlink (compiled_file_name);
1203
1204	      java_sources[0] = conftest_file_name;
1205	      if (!compile_using_envjavac (javac_target_source,
1206					   java_sources, 1, tmpdir->dir_name,
1207					   false, false, false, true)
1208		  && stat (compiled_file_name, &statbuf) >= 0
1209		  && get_classfile_version (compiled_file_name)
1210		     <= corresponding_classfile_version (target_version))
1211		{
1212		  const char *failcode = get_failcode_snippet (source_version);
1213
1214		  if (failcode != NULL)
1215		    {
1216		      free (compiled_file_name);
1217		      free (conftest_file_name);
1218
1219		      conftest_file_name =
1220			concatenated_filename (tmpdir->dir_name,
1221					       "conftestfail.java",
1222					       NULL);
1223		      if (write_temp_file (tmpdir, conftest_file_name,
1224					   failcode))
1225			{
1226			  free (conftest_file_name);
1227			  free (javac_target_source);
1228			  free (javac_target);
1229			  cleanup_temp_dir (tmpdir);
1230			  return true;
1231			}
1232
1233		      compiled_file_name =
1234			concatenated_filename (tmpdir->dir_name,
1235					       "conftestfail.class",
1236					       NULL);
1237		      register_temp_file (tmpdir, compiled_file_name);
1238
1239		      java_sources[0] = conftest_file_name;
1240		      if (!compile_using_envjavac (javac_target,
1241						   java_sources, 1,
1242						   tmpdir->dir_name,
1243						   false, false, false, true)
1244			  && stat (compiled_file_name, &statbuf) >= 0)
1245			{
1246			  unlink (compiled_file_name);
1247
1248			  java_sources[0] = conftest_file_name;
1249			  if (compile_using_envjavac (javac_target_source,
1250						      java_sources, 1,
1251						      tmpdir->dir_name,
1252						      false, false, false,
1253						      true))
1254			    /* "$JAVAC -target $target_version" compiled
1255			       conftestfail.java successfully, and
1256			       "$JAVAC -target $target_version -source $source_version"
1257			       rejects it.  So the -source option is useful.  */
1258			    resultp->source_option = true;
1259			}
1260		    }
1261		}
1262
1263	      free (javac_target_source);
1264
1265	      resultp->target_option = true;
1266	      resultp->usable = true;
1267	    }
1268	  else
1269	    {
1270	      /* Maybe this -target option requires a -source option? Try with
1271		 -target and -source options. (Supported by Sun javac 1.4 and
1272		 higher.)  */
1273	      char *javac_target_source =
1274		xasprintf ("%s -source %s", javac_target, source_version);
1275
1276	      unlink (compiled_file_name);
1277
1278	      java_sources[0] = conftest_file_name;
1279	      if (!compile_using_envjavac (javac_target_source,
1280					   java_sources, 1, tmpdir->dir_name,
1281					   false, false, false, true)
1282		  && stat (compiled_file_name, &statbuf) >= 0
1283		  && get_classfile_version (compiled_file_name)
1284		     <= corresponding_classfile_version (target_version))
1285		{
1286		  /* "$JAVAC -target $target_version -source $source_version"
1287		     compiled conftest.java successfully.  */
1288		  resultp->source_option = true;
1289		  resultp->target_option = true;
1290		  resultp->usable = true;
1291		}
1292
1293	      free (javac_target_source);
1294	    }
1295
1296	  free (javac_target);
1297	}
1298
1299      free (compiled_file_name);
1300      free (conftest_file_name);
1301
1302      resultp->tested = true;
1303    }
1304
1305  *usablep = resultp->usable;
1306  *source_option_p = resultp->source_option;
1307  *target_option_p = resultp->target_option;
1308  return false;
1309}
1310
1311static bool
1312is_gcj_present (void)
1313{
1314  static bool gcj_tested;
1315  static bool gcj_present;
1316
1317  if (!gcj_tested)
1318    {
1319      /* Test for presence of gcj:
1320	 "gcj --version 2> /dev/null | \
1321	  sed -e 's,^[^0-9]*,,' -e 1q | \
1322	  sed -e '/^3\.[01]/d' | grep '^[3-9]' > /dev/null"  */
1323      char *argv[3];
1324      pid_t child;
1325      int fd[1];
1326      int exitstatus;
1327
1328      argv[0] = "gcj";
1329      argv[1] = "--version";
1330      argv[2] = NULL;
1331      child = create_pipe_in ("gcj", "gcj", argv, DEV_NULL, true, true,
1332			      false, fd);
1333      gcj_present = false;
1334      if (child != -1)
1335	{
1336	  /* Read the subprocess output, drop all lines except the first,
1337	     drop all characters before the first digit, and test whether
1338	     the remaining string starts with a digit >= 3, but not with
1339	     "3.0" or "3.1".  */
1340	  char c[3];
1341	  size_t count = 0;
1342
1343	  while (safe_read (fd[0], &c[count], 1) > 0)
1344	    {
1345	      if (c[count] == '\n')
1346		break;
1347	      if (count == 0)
1348		{
1349		  if (!(c[0] >= '0' && c[0] <= '9'))
1350		    continue;
1351		  gcj_present = (c[0] >= '3');
1352		}
1353	      count++;
1354	      if (count == 3)
1355		{
1356		  if (c[0] == '3' && c[1] == '.'
1357		      && (c[2] == '0' || c[2] == '1'))
1358		    gcj_present = false;
1359		  break;
1360		}
1361	    }
1362	  while (safe_read (fd[0], &c[0], 1) > 0)
1363	    ;
1364
1365	  close (fd[0]);
1366
1367	  /* Remove zombie process from process list, and retrieve exit
1368	     status.  */
1369	  exitstatus =
1370	    wait_subprocess (child, "gcj", false, true, true, false);
1371	  if (exitstatus != 0)
1372	    gcj_present = false;
1373	}
1374
1375      if (gcj_present)
1376	{
1377	  /* See if libgcj.jar is well installed.  */
1378	  struct temp_dir *tmpdir;
1379
1380	  tmpdir = create_temp_dir ("java", NULL, false);
1381	  if (tmpdir == NULL)
1382	    gcj_present = false;
1383	  else
1384	    {
1385	      char *conftest_file_name;
1386
1387	      conftest_file_name =
1388		concatenated_filename (tmpdir->dir_name, "conftestlib.java",
1389				       NULL);
1390	      if (write_temp_file (tmpdir, conftest_file_name,
1391"public class conftestlib {\n"
1392"  public static void main (String[] args) {\n"
1393"  }\n"
1394"}\n"))
1395		gcj_present = false;
1396	      else
1397		{
1398		  char *compiled_file_name;
1399		  const char *java_sources[1];
1400
1401		  compiled_file_name =
1402		    concatenated_filename (tmpdir->dir_name,
1403					   "conftestlib.class",
1404					   NULL);
1405		  register_temp_file (tmpdir, compiled_file_name);
1406
1407		  java_sources[0] = conftest_file_name;
1408		  if (compile_using_gcj (java_sources, 1, false,
1409					 false, NULL, false, NULL,
1410					 tmpdir->dir_name,
1411					 false, false, false, true))
1412		    gcj_present = false;
1413
1414		  free (compiled_file_name);
1415		}
1416	      free (conftest_file_name);
1417	    }
1418	  cleanup_temp_dir (tmpdir);
1419	}
1420
1421      gcj_tested = true;
1422    }
1423
1424  return gcj_present;
1425}
1426
1427static bool
1428is_gcj_43 (void)
1429{
1430  static bool gcj_tested;
1431  static bool gcj_43;
1432
1433  if (!gcj_tested)
1434    {
1435      /* Test for presence of gcj:
1436	 "gcj --version 2> /dev/null | \
1437	  sed -e 's,^[^0-9]*,,' -e 1q | \
1438	  sed -e '/^4\.[012]/d' | grep '^[4-9]'"  */
1439      char *argv[3];
1440      pid_t child;
1441      int fd[1];
1442      int exitstatus;
1443
1444      argv[0] = "gcj";
1445      argv[1] = "--version";
1446      argv[2] = NULL;
1447      child = create_pipe_in ("gcj", "gcj", argv, DEV_NULL, true, true,
1448			      false, fd);
1449      gcj_43 = false;
1450      if (child != -1)
1451	{
1452	  /* Read the subprocess output, drop all lines except the first,
1453	     drop all characters before the first digit, and test whether
1454	     the remaining string starts with a digit >= 4, but not with
1455	     "4.0" or "4.1" or "4.2".  */
1456	  char c[3];
1457	  size_t count = 0;
1458
1459	  while (safe_read (fd[0], &c[count], 1) > 0)
1460	    {
1461	      if (c[count] == '\n')
1462		break;
1463	      if (count == 0)
1464		{
1465		  if (!(c[0] >= '0' && c[0] <= '9'))
1466		    continue;
1467		  gcj_43 = (c[0] >= '4');
1468		}
1469	      count++;
1470	      if (count == 3)
1471		{
1472		  if (c[0] == '4' && c[1] == '.' && c[2] >= '0' && c[2] <= '2')
1473		    gcj_43 = false;
1474		  break;
1475		}
1476	    }
1477	  while (safe_read (fd[0], &c[0], 1) > 0)
1478	    ;
1479
1480	  close (fd[0]);
1481
1482	  /* Remove zombie process from process list, and retrieve exit
1483	     status.  */
1484	  exitstatus =
1485	    wait_subprocess (child, "gcj", false, true, true, false);
1486	  if (exitstatus != 0)
1487	    gcj_43 = false;
1488	}
1489
1490      gcj_tested = true;
1491    }
1492
1493  return gcj_43;
1494}
1495
1496/* Test whether gcj >= 4.3 can be used, and whether it needs a -fsource and/or
1497   -ftarget option.
1498   Return a failure indicator (true upon error).  */
1499static bool
1500is_gcj43_usable (const char *source_version,
1501		 const char *target_version,
1502		 bool *usablep,
1503		 bool *fsource_option_p, bool *ftarget_option_p)
1504{
1505  /* The cache depends on the source_version and target_version.  */
1506  struct result_t
1507  {
1508    bool tested;
1509    bool usable;
1510    bool fsource_option;
1511    bool ftarget_option;
1512  };
1513  static struct result_t result_cache[SOURCE_VERSION_BOUND][TARGET_VERSION_BOUND];
1514  struct result_t *resultp;
1515
1516  resultp = &result_cache[source_version_index (source_version)]
1517			 [target_version_index (target_version)];
1518  if (!resultp->tested)
1519    {
1520      /* Try gcj.  */
1521      struct temp_dir *tmpdir;
1522      char *conftest_file_name;
1523      char *compiled_file_name;
1524      const char *java_sources[1];
1525      struct stat statbuf;
1526
1527      tmpdir = create_temp_dir ("java", NULL, false);
1528      if (tmpdir == NULL)
1529	return true;
1530
1531      conftest_file_name =
1532	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
1533      if (write_temp_file (tmpdir, conftest_file_name,
1534			   get_goodcode_snippet (source_version)))
1535	{
1536	  free (conftest_file_name);
1537	  cleanup_temp_dir (tmpdir);
1538	  return true;
1539	}
1540
1541      compiled_file_name =
1542	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
1543      register_temp_file (tmpdir, compiled_file_name);
1544
1545      java_sources[0] = conftest_file_name;
1546      if (!compile_using_gcj (java_sources, 1, false, false, NULL, false, NULL,
1547			      tmpdir->dir_name, false, false, false, true)
1548	  && stat (compiled_file_name, &statbuf) >= 0
1549	  && get_classfile_version (compiled_file_name)
1550	     <= corresponding_classfile_version (target_version))
1551	{
1552	  /* gcj compiled conftest.java successfully.  */
1553	  /* Try adding -fsource option if it is useful.  */
1554	  unlink (compiled_file_name);
1555
1556	  java_sources[0] = conftest_file_name;
1557	  if (!compile_using_gcj (java_sources, 1,
1558				  false, true, source_version, false, NULL,
1559				  tmpdir->dir_name, false, false, false, true)
1560	      && stat (compiled_file_name, &statbuf) >= 0
1561	      && get_classfile_version (compiled_file_name)
1562		 <= corresponding_classfile_version (target_version))
1563	    {
1564	      const char *failcode = get_failcode_snippet (source_version);
1565
1566	      if (failcode != NULL)
1567		{
1568		  free (compiled_file_name);
1569		  free (conftest_file_name);
1570
1571		  conftest_file_name =
1572		    concatenated_filename (tmpdir->dir_name,
1573					   "conftestfail.java",
1574					   NULL);
1575		  if (write_temp_file (tmpdir, conftest_file_name, failcode))
1576		    {
1577		      free (conftest_file_name);
1578		      cleanup_temp_dir (tmpdir);
1579		      return true;
1580		    }
1581
1582		  compiled_file_name =
1583		    concatenated_filename (tmpdir->dir_name,
1584					   "conftestfail.class",
1585					   NULL);
1586		  register_temp_file (tmpdir, compiled_file_name);
1587
1588		  java_sources[0] = conftest_file_name;
1589		  if (!compile_using_gcj (java_sources, 1,
1590					  false, false, NULL, false, NULL,
1591					  tmpdir->dir_name,
1592					  false, false, false, true)
1593		      && stat (compiled_file_name, &statbuf) >= 0)
1594		    {
1595		      unlink (compiled_file_name);
1596
1597		      java_sources[0] = conftest_file_name;
1598		      if (compile_using_gcj (java_sources, 1,
1599					     false, true, source_version,
1600					     false, NULL,
1601					     tmpdir->dir_name,
1602					     false, false, false, true))
1603			/* gcj compiled conftestfail.java successfully, and
1604			   "gcj -fsource=$source_version" rejects it.  So
1605			   the -fsource option is useful.  */
1606			resultp->fsource_option = true;
1607		    }
1608		}
1609	    }
1610
1611	  resultp->usable = true;
1612	}
1613      else
1614	{
1615	  /* Try with -fsource and -ftarget options.  */
1616	  unlink (compiled_file_name);
1617
1618	  java_sources[0] = conftest_file_name;
1619	  if (!compile_using_gcj (java_sources, 1,
1620				  false, true, source_version,
1621				  true, target_version,
1622				  tmpdir->dir_name,
1623				  false, false, false, true)
1624	      && stat (compiled_file_name, &statbuf) >= 0
1625	      && get_classfile_version (compiled_file_name)
1626		 <= corresponding_classfile_version (target_version))
1627	    {
1628	      /* "gcj -fsource $source_version -ftarget $target_version"
1629		 compiled conftest.java successfully.  */
1630	      resultp->fsource_option = true;
1631	      resultp->ftarget_option = true;
1632	      resultp->usable = true;
1633	    }
1634	}
1635
1636      free (compiled_file_name);
1637      free (conftest_file_name);
1638
1639      resultp->tested = true;
1640    }
1641
1642  *usablep = resultp->usable;
1643  *fsource_option_p = resultp->fsource_option;
1644  *ftarget_option_p = resultp->ftarget_option;
1645  return false;
1646}
1647
1648/* Test whether gcj < 4.3 can be used for compiling with target_version = 1.4
1649   and source_version = 1.4.
1650   Return a failure indicator (true upon error).  */
1651static bool
1652is_oldgcj_14_14_usable (bool *usablep)
1653{
1654  static bool gcj_tested;
1655  static bool gcj_usable;
1656
1657  if (!gcj_tested)
1658    {
1659      /* Try gcj.  */
1660      struct temp_dir *tmpdir;
1661      char *conftest_file_name;
1662      char *compiled_file_name;
1663      const char *java_sources[1];
1664      struct stat statbuf;
1665
1666      tmpdir = create_temp_dir ("java", NULL, false);
1667      if (tmpdir == NULL)
1668	return true;
1669
1670      conftest_file_name =
1671	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
1672      if (write_temp_file (tmpdir, conftest_file_name,
1673			   get_goodcode_snippet ("1.4")))
1674	{
1675	  free (conftest_file_name);
1676	  cleanup_temp_dir (tmpdir);
1677	  return true;
1678	}
1679
1680      compiled_file_name =
1681	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
1682      register_temp_file (tmpdir, compiled_file_name);
1683
1684      java_sources[0] = conftest_file_name;
1685      if (!compile_using_gcj (java_sources, 1, false, false, NULL, false, NULL,
1686			      tmpdir->dir_name, false, false, false, true)
1687	  && stat (compiled_file_name, &statbuf) >= 0)
1688	/* Compilation succeeded.  */
1689	gcj_usable = true;
1690
1691      free (compiled_file_name);
1692      free (conftest_file_name);
1693
1694      cleanup_temp_dir (tmpdir);
1695
1696      gcj_tested = true;
1697    }
1698
1699  *usablep = gcj_usable;
1700  return false;
1701}
1702
1703/* Test whether gcj < 4.3 can be used for compiling with target_version = 1.4
1704   and source_version = 1.3.
1705   Return a failure indicator (true upon error).  */
1706static bool
1707is_oldgcj_14_13_usable (bool *usablep, bool *need_no_assert_option_p)
1708{
1709  static bool gcj_tested;
1710  static bool gcj_usable;
1711  static bool gcj_need_no_assert_option;
1712
1713  if (!gcj_tested)
1714    {
1715      /* Try gcj and "gcj -fno-assert".  But add -fno-assert only if
1716	 it works (not gcj < 3.3).  */
1717      struct temp_dir *tmpdir;
1718      char *conftest_file_name;
1719      char *compiled_file_name;
1720      const char *java_sources[1];
1721      struct stat statbuf;
1722
1723      tmpdir = create_temp_dir ("java", NULL, false);
1724      if (tmpdir == NULL)
1725	return true;
1726
1727      conftest_file_name =
1728	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
1729      if (write_temp_file (tmpdir, conftest_file_name,
1730			   get_goodcode_snippet ("1.3")))
1731	{
1732	  free (conftest_file_name);
1733	  cleanup_temp_dir (tmpdir);
1734	  return true;
1735	}
1736
1737      compiled_file_name =
1738	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
1739      register_temp_file (tmpdir, compiled_file_name);
1740
1741      java_sources[0] = conftest_file_name;
1742      if (!compile_using_gcj (java_sources, 1, true, false, NULL, false, NULL,
1743			      tmpdir->dir_name, false, false, false, true)
1744	  && stat (compiled_file_name, &statbuf) >= 0)
1745	/* Compilation succeeded.  */
1746	{
1747	  gcj_usable = true;
1748	  gcj_need_no_assert_option = true;
1749	}
1750      else
1751	{
1752	  unlink (compiled_file_name);
1753
1754	  java_sources[0] = conftest_file_name;
1755	  if (!compile_using_gcj (java_sources, 1, false,
1756				  false, NULL, false, NULL,
1757				  tmpdir->dir_name, false, false, false, true)
1758	      && stat (compiled_file_name, &statbuf) >= 0)
1759	    /* Compilation succeeded.  */
1760	    {
1761	      gcj_usable = true;
1762	      gcj_need_no_assert_option = false;
1763	    }
1764	}
1765
1766      free (compiled_file_name);
1767      free (conftest_file_name);
1768
1769      cleanup_temp_dir (tmpdir);
1770
1771      gcj_tested = true;
1772    }
1773
1774  *usablep = gcj_usable;
1775  *need_no_assert_option_p = gcj_need_no_assert_option;
1776  return false;
1777}
1778
1779static bool
1780is_javac_present (void)
1781{
1782  static bool javac_tested;
1783  static bool javac_present;
1784
1785  if (!javac_tested)
1786    {
1787      /* Test for presence of javac: "javac 2> /dev/null ; test $? -le 2"  */
1788      char *argv[2];
1789      int exitstatus;
1790
1791      argv[0] = "javac";
1792      argv[1] = NULL;
1793      exitstatus = execute ("javac", "javac", argv, false, false, true, true,
1794			    true, false);
1795      javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2);
1796      javac_tested = true;
1797    }
1798
1799  return javac_present;
1800}
1801
1802/* Test whether javac can be used and whether it needs a -source and/or
1803   -target option.
1804   Return a failure indicator (true upon error).  */
1805static bool
1806is_javac_usable (const char *source_version, const char *target_version,
1807		 bool *usablep, bool *source_option_p, bool *target_option_p)
1808{
1809  /* The cache depends on the source_version and target_version.  */
1810  struct result_t
1811  {
1812    bool tested;
1813    bool usable;
1814    bool source_option;
1815    bool target_option;
1816  };
1817  static struct result_t result_cache[SOURCE_VERSION_BOUND][TARGET_VERSION_BOUND];
1818  struct result_t *resultp;
1819
1820  resultp = &result_cache[source_version_index (source_version)]
1821			 [target_version_index (target_version)];
1822  if (!resultp->tested)
1823    {
1824      /* Try javac.  */
1825      struct temp_dir *tmpdir;
1826      char *conftest_file_name;
1827      char *compiled_file_name;
1828      const char *java_sources[1];
1829      struct stat statbuf;
1830
1831      tmpdir = create_temp_dir ("java", NULL, false);
1832      if (tmpdir == NULL)
1833	return true;
1834
1835      conftest_file_name =
1836	concatenated_filename (tmpdir->dir_name, "conftest.java", NULL);
1837      if (write_temp_file (tmpdir, conftest_file_name,
1838			   get_goodcode_snippet (source_version)))
1839	{
1840	  free (conftest_file_name);
1841	  cleanup_temp_dir (tmpdir);
1842	  return true;
1843	}
1844
1845      compiled_file_name =
1846	concatenated_filename (tmpdir->dir_name, "conftest.class", NULL);
1847      register_temp_file (tmpdir, compiled_file_name);
1848
1849      java_sources[0] = conftest_file_name;
1850      if (!compile_using_javac (java_sources, 1,
1851				false, source_version,
1852				false, target_version,
1853				tmpdir->dir_name, false, false, false, true)
1854	  && stat (compiled_file_name, &statbuf) >= 0
1855	  && get_classfile_version (compiled_file_name)
1856	     <= corresponding_classfile_version (target_version))
1857	{
1858	  /* javac compiled conftest.java successfully.  */
1859	  /* Try adding -source option if it is useful.  */
1860	  unlink (compiled_file_name);
1861
1862	  java_sources[0] = conftest_file_name;
1863	  if (!compile_using_javac (java_sources, 1,
1864				    true, source_version,
1865				    false, target_version,
1866				    tmpdir->dir_name, false, false, false, true)
1867	      && stat (compiled_file_name, &statbuf) >= 0
1868	      && get_classfile_version (compiled_file_name)
1869		 <= corresponding_classfile_version (target_version))
1870	    {
1871	      const char *failcode = get_failcode_snippet (source_version);
1872
1873	      if (failcode != NULL)
1874		{
1875		  free (compiled_file_name);
1876		  free (conftest_file_name);
1877
1878		  conftest_file_name =
1879		    concatenated_filename (tmpdir->dir_name,
1880					   "conftestfail.java",
1881					   NULL);
1882		  if (write_temp_file (tmpdir, conftest_file_name, failcode))
1883		    {
1884		      free (conftest_file_name);
1885		      cleanup_temp_dir (tmpdir);
1886		      return true;
1887		    }
1888
1889		  compiled_file_name =
1890		    concatenated_filename (tmpdir->dir_name,
1891					   "conftestfail.class",
1892					   NULL);
1893		  register_temp_file (tmpdir, compiled_file_name);
1894
1895		  java_sources[0] = conftest_file_name;
1896		  if (!compile_using_javac (java_sources, 1,
1897					    false, source_version,
1898					    false, target_version,
1899					    tmpdir->dir_name,
1900					    false, false, false, true)
1901		      && stat (compiled_file_name, &statbuf) >= 0)
1902		    {
1903		      unlink (compiled_file_name);
1904
1905		      java_sources[0] = conftest_file_name;
1906		      if (compile_using_javac (java_sources, 1,
1907					       true, source_version,
1908					       false, target_version,
1909					       tmpdir->dir_name,
1910					       false, false, false, true))
1911			/* javac compiled conftestfail.java successfully, and
1912			   "javac -source $source_version" rejects it.  So the
1913			   -source option is useful.  */
1914			resultp->source_option = true;
1915		    }
1916		}
1917	    }
1918
1919	  resultp->usable = true;
1920	}
1921      else
1922	{
1923	  /* Try with -target option alone. (Sun javac 1.3.1 has the -target
1924	     option but no -source option.)  */
1925	  unlink (compiled_file_name);
1926
1927	  java_sources[0] = conftest_file_name;
1928	  if (!compile_using_javac (java_sources, 1,
1929				    false, source_version,
1930				    true, target_version,
1931				    tmpdir->dir_name,
1932				    false, false, false, true)
1933	      && stat (compiled_file_name, &statbuf) >= 0
1934	      && get_classfile_version (compiled_file_name)
1935		 <= corresponding_classfile_version (target_version))
1936	    {
1937	      /* "javac -target $target_version" compiled conftest.java
1938		 successfully.  */
1939	      /* Try adding -source option if it is useful.  */
1940	      unlink (compiled_file_name);
1941
1942	      java_sources[0] = conftest_file_name;
1943	      if (!compile_using_javac (java_sources, 1,
1944					true, source_version,
1945					true, target_version,
1946					tmpdir->dir_name,
1947					false, false, false, true)
1948		  && stat (compiled_file_name, &statbuf) >= 0
1949		  && get_classfile_version (compiled_file_name)
1950		     <= corresponding_classfile_version (target_version))
1951		{
1952		  const char *failcode = get_failcode_snippet (source_version);
1953
1954		  if (failcode != NULL)
1955		    {
1956		      free (compiled_file_name);
1957		      free (conftest_file_name);
1958
1959		      conftest_file_name =
1960			concatenated_filename (tmpdir->dir_name,
1961					       "conftestfail.java",
1962					       NULL);
1963		      if (write_temp_file (tmpdir, conftest_file_name,
1964					   failcode))
1965			{
1966			  free (conftest_file_name);
1967			  cleanup_temp_dir (tmpdir);
1968			  return true;
1969			}
1970
1971		      compiled_file_name =
1972			concatenated_filename (tmpdir->dir_name,
1973					       "conftestfail.class",
1974					       NULL);
1975		      register_temp_file (tmpdir, compiled_file_name);
1976
1977		      java_sources[0] = conftest_file_name;
1978		      if (!compile_using_javac (java_sources, 1,
1979						false, source_version,
1980						true, target_version,
1981						tmpdir->dir_name,
1982						false, false, false, true)
1983			  && stat (compiled_file_name, &statbuf) >= 0)
1984			{
1985			  unlink (compiled_file_name);
1986
1987			  java_sources[0] = conftest_file_name;
1988			  if (compile_using_javac (java_sources, 1,
1989						   true, source_version,
1990						   true, target_version,
1991						   tmpdir->dir_name,
1992						   false, false, false, true))
1993			    /* "javac -target $target_version" compiled
1994			       conftestfail.java successfully, and
1995			       "javac -target $target_version -source $source_version"
1996			       rejects it.  So the -source option is useful.  */
1997			    resultp->source_option = true;
1998			}
1999		    }
2000		}
2001
2002	      resultp->target_option = true;
2003	      resultp->usable = true;
2004	    }
2005	  else
2006	    {
2007	      /* Maybe this -target option requires a -source option? Try with
2008		 -target and -source options. (Supported by Sun javac 1.4 and
2009		 higher.)  */
2010	      unlink (compiled_file_name);
2011
2012	      java_sources[0] = conftest_file_name;
2013	      if (!compile_using_javac (java_sources, 1,
2014					true, source_version,
2015					true, target_version,
2016					tmpdir->dir_name,
2017					false, false, false, true)
2018		  && stat (compiled_file_name, &statbuf) >= 0
2019		  && get_classfile_version (compiled_file_name)
2020		     <= corresponding_classfile_version (target_version))
2021		{
2022		  /* "javac -target $target_version -source $source_version"
2023		     compiled conftest.java successfully.  */
2024		  resultp->source_option = true;
2025		  resultp->target_option = true;
2026		  resultp->usable = true;
2027		}
2028	    }
2029	}
2030
2031      free (compiled_file_name);
2032      free (conftest_file_name);
2033
2034      resultp->tested = true;
2035    }
2036
2037  *usablep = resultp->usable;
2038  *source_option_p = resultp->source_option;
2039  *target_option_p = resultp->target_option;
2040  return false;
2041}
2042
2043static bool
2044is_jikes_present (void)
2045{
2046  static bool jikes_tested;
2047  static bool jikes_present;
2048
2049  if (!jikes_tested)
2050    {
2051      /* Test for presence of jikes: "jikes 2> /dev/null ; test $? = 1"  */
2052      char *argv[2];
2053      int exitstatus;
2054
2055      argv[0] = "jikes";
2056      argv[1] = NULL;
2057      exitstatus = execute ("jikes", "jikes", argv, false, false, true, true,
2058			    true, false);
2059      jikes_present = (exitstatus == 0 || exitstatus == 1);
2060      jikes_tested = true;
2061    }
2062
2063  return jikes_present;
2064}
2065
2066/* ============================= Main function ============================= */
2067
2068bool
2069compile_java_class (const char * const *java_sources,
2070		    unsigned int java_sources_count,
2071		    const char * const *classpaths,
2072		    unsigned int classpaths_count,
2073		    const char *source_version,
2074		    const char *target_version,
2075		    const char *directory,
2076		    bool optimize, bool debug,
2077		    bool use_minimal_classpath,
2078		    bool verbose)
2079{
2080  bool err = false;
2081  char *old_JAVA_HOME;
2082
2083  {
2084    const char *javac = getenv ("JAVAC");
2085    if (javac != NULL && javac[0] != '\0')
2086      {
2087	bool usable = false;
2088	bool no_assert_option = false;
2089	bool source_option = false;
2090	bool target_option = false;
2091	bool fsource_option = false;
2092	bool ftarget_option = false;
2093
2094	if (target_version == NULL)
2095	  target_version = default_target_version ();
2096
2097	if (is_envjavac_gcj (javac))
2098	  {
2099	    /* It's a version of gcj.  */
2100	    if (is_envjavac_gcj43 (javac))
2101	      {
2102		/* It's a version of gcj >= 4.3.  Assume the classfile versions
2103		   are correct.  */
2104		if (is_envjavac_gcj43_usable (javac,
2105					      source_version, target_version,
2106					      &usable,
2107					      &fsource_option, &ftarget_option))
2108		  {
2109		    err = true;
2110		    goto done1;
2111		  }
2112	      }
2113	    else
2114	      {
2115		/* It's a version of gcj < 4.3.  Ignore the version of the
2116		   class files that it creates.  */
2117		if (strcmp (target_version, "1.4") == 0
2118		    && strcmp (source_version, "1.4") == 0)
2119		  {
2120		    if (is_envjavac_oldgcj_14_14_usable (javac, &usable))
2121		      {
2122			err = true;
2123			goto done1;
2124		      }
2125		  }
2126		else if (strcmp (target_version, "1.4") == 0
2127			 && strcmp (source_version, "1.3") == 0)
2128		  {
2129		    if (is_envjavac_oldgcj_14_13_usable (javac,
2130							 &usable,
2131							 &no_assert_option))
2132		      {
2133			err = true;
2134			goto done1;
2135		      }
2136		  }
2137	      }
2138	  }
2139	else
2140	  {
2141	    /* It's not gcj.  Assume the classfile versions are correct.  */
2142	    if (is_envjavac_nongcj_usable (javac,
2143					   source_version, target_version,
2144					   &usable,
2145					   &source_option, &target_option))
2146	      {
2147		err = true;
2148		goto done1;
2149	      }
2150	  }
2151
2152	if (usable)
2153	  {
2154	    char *old_classpath;
2155	    char *javac_with_options;
2156
2157	    /* Set CLASSPATH.  */
2158	    old_classpath =
2159	      set_classpath (classpaths, classpaths_count, false, verbose);
2160
2161	    javac_with_options =
2162	      (no_assert_option
2163	       ? xasprintf ("%s -fno-assert", javac)
2164	       : xasprintf ("%s%s%s%s%s%s%s%s%s",
2165			    javac,
2166			    source_option ? " -source " : "",
2167			    source_option ? source_version : "",
2168			    target_option ? " -target " : "",
2169			    target_option ? target_version : "",
2170			    fsource_option ? " -fsource=" : "",
2171			    fsource_option ? source_version : "",
2172			    ftarget_option ? " -ftarget=" : "",
2173			    ftarget_option ? target_version : ""));
2174
2175	    err = compile_using_envjavac (javac_with_options,
2176					  java_sources, java_sources_count,
2177					  directory, optimize, debug, verbose,
2178					  false);
2179
2180	    free (javac_with_options);
2181
2182	    /* Reset CLASSPATH.  */
2183	    reset_classpath (old_classpath);
2184
2185	    goto done1;
2186	  }
2187      }
2188  }
2189
2190  /* Unset the JAVA_HOME environment variable.  */
2191  old_JAVA_HOME = getenv ("JAVA_HOME");
2192  if (old_JAVA_HOME != NULL)
2193    {
2194      old_JAVA_HOME = xstrdup (old_JAVA_HOME);
2195      unsetenv ("JAVA_HOME");
2196    }
2197
2198  if (is_gcj_present ())
2199    {
2200      /* It's a version of gcj.  */
2201      bool usable = false;
2202      bool no_assert_option = false;
2203      bool fsource_option = false;
2204      bool ftarget_option = false;
2205
2206      if (target_version == NULL)
2207	target_version = default_target_version ();
2208
2209      if (is_gcj_43 ())
2210	{
2211	  /* It's a version of gcj >= 4.3.  Assume the classfile versions
2212	     are correct.  */
2213	  if (is_gcj43_usable (source_version, target_version,
2214			       &usable, &fsource_option, &ftarget_option))
2215	    {
2216	      err = true;
2217	      goto done1;
2218	    }
2219	}
2220      else
2221	{
2222	  /* It's a version of gcj < 4.3.  Ignore the version of the class
2223	     files that it creates.
2224	     Test whether it supports the desired target-version and
2225	     source-version.  */
2226	  if (strcmp (target_version, "1.4") == 0
2227	      && strcmp (source_version, "1.4") == 0)
2228	    {
2229	      if (is_oldgcj_14_14_usable (&usable))
2230		{
2231		  err = true;
2232		  goto done1;
2233		}
2234	    }
2235	  else if (strcmp (target_version, "1.4") == 0
2236		   && strcmp (source_version, "1.3") == 0)
2237	    {
2238	      if (is_oldgcj_14_13_usable (&usable, &no_assert_option))
2239		{
2240		  err = true;
2241		  goto done1;
2242		}
2243	    }
2244	}
2245
2246      if (usable)
2247	{
2248	  char *old_classpath;
2249
2250	  /* Set CLASSPATH.  We could also use the --CLASSPATH=... option
2251	     of gcj.  Note that --classpath=... option is different: its
2252	     argument should also contain gcj's libgcj.jar, but we don't
2253	     know its location.  */
2254	  old_classpath =
2255	    set_classpath (classpaths, classpaths_count, use_minimal_classpath,
2256			   verbose);
2257
2258	  err = compile_using_gcj (java_sources, java_sources_count,
2259				   no_assert_option,
2260				   fsource_option, source_version,
2261				   ftarget_option, target_version,
2262				   directory, optimize, debug, verbose, false);
2263
2264	  /* Reset CLASSPATH.  */
2265	  reset_classpath (old_classpath);
2266
2267	  goto done2;
2268	}
2269    }
2270
2271  if (is_javac_present ())
2272    {
2273      bool usable = false;
2274      bool source_option = false;
2275      bool target_option = false;
2276
2277      if (target_version == NULL)
2278	target_version = default_target_version ();
2279
2280      if (is_javac_usable (source_version, target_version,
2281			   &usable, &source_option, &target_option))
2282	{
2283	  err = true;
2284	  goto done1;
2285	}
2286
2287      if (usable)
2288	{
2289	  char *old_classpath;
2290
2291	  /* Set CLASSPATH.  We don't use the "-classpath ..." option because
2292	     in JDK 1.1.x its argument should also contain the JDK's
2293	     classes.zip, but we don't know its location.  (In JDK 1.3.0 it
2294	     would work.)  */
2295	  old_classpath =
2296	    set_classpath (classpaths, classpaths_count, use_minimal_classpath,
2297			   verbose);
2298
2299	  err = compile_using_javac (java_sources, java_sources_count,
2300				     source_option, source_version,
2301				     target_option, target_version,
2302				     directory, optimize, debug, verbose,
2303				     false);
2304
2305	  /* Reset CLASSPATH.  */
2306	  reset_classpath (old_classpath);
2307
2308	  goto done2;
2309	}
2310    }
2311
2312  if (is_jikes_present ())
2313    {
2314      /* Test whether it supports the desired target-version and
2315	 source-version.  */
2316      bool usable = (strcmp (source_version, "1.3") == 0);
2317
2318      if (usable)
2319	{
2320	  char *old_classpath;
2321
2322	  /* Set CLASSPATH.  We could also use the "-classpath ..." option.
2323	     Since jikes doesn't come with its own standard library, it
2324	     needs a classes.zip or rt.jar or libgcj.jar in the CLASSPATH.
2325	     To increase the chance of success, we reuse the current CLASSPATH
2326	     if the user has set it.  */
2327	  old_classpath =
2328	    set_classpath (classpaths, classpaths_count, false, verbose);
2329
2330	  err = compile_using_jikes (java_sources, java_sources_count,
2331				     directory, optimize, debug, verbose,
2332				     false);
2333
2334	  /* Reset CLASSPATH.  */
2335	  reset_classpath (old_classpath);
2336
2337	  goto done2;
2338	}
2339    }
2340
2341  error (0, 0, _("Java compiler not found, try installing gcj or set $JAVAC"));
2342  err = true;
2343
2344 done2:
2345  if (old_JAVA_HOME != NULL)
2346    {
2347      xsetenv ("JAVA_HOME", old_JAVA_HOME, 1);
2348      free (old_JAVA_HOME);
2349    }
2350
2351 done1:
2352  return err;
2353}
2354