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