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