fix typos in mathl
[gnulib.git] / lib / javacomp.c
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.  */
96 static const char *
97 default_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 */
119 static unsigned int
120 source_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.  */
131 static const char *
132 get_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).  */
147 static const char *
148 get_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 */
164 static unsigned int
165 target_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.  */
177 static int
178 corresponding_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).  */
200 static bool
201 compile_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).  */
281 static bool
282 compile_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).  */
367 static bool
368 compile_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).  */
434 static bool
435 compile_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).  */
493 static bool
494 write_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.  */
517 static int
518 get_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.  */
543 static bool
544 is_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.  */
623 static bool
624 is_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).  */
708 static bool
709 is_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).  */
871 static bool
872 is_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).  */
926 static bool
927 is_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).  */
1058 static bool
1059 is_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
1311 static bool
1312 is_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
1427 static bool
1428 is_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).  */
1499 static bool
1500 is_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).  */
1651 static bool
1652 is_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).  */
1706 static bool
1707 is_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
1779 static bool
1780 is_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).  */
1805 static bool
1806 is_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
2043 static bool
2044 is_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
2068 bool
2069 compile_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 }