root/maint/gnulib/lib/javacomp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. default_target_version
  2. source_version_index
  3. get_goodcode_snippet
  4. get_failcode_snippet
  5. target_version_index
  6. corresponding_classfile_version
  7. get_source_version_for_javac
  8. compile_using_envjavac
  9. compile_using_gcj
  10. compile_using_javac
  11. compile_using_jikes
  12. write_temp_file
  13. get_classfile_version
  14. is_envjavac_gcj
  15. is_envjavac_gcj43
  16. is_envjavac_gcj43_usable
  17. is_envjavac_oldgcj_14_14_usable
  18. is_envjavac_oldgcj_14_13_usable
  19. is_envjavac_nongcj_usable
  20. is_gcj_present
  21. is_gcj_43
  22. is_gcj43_usable
  23. is_oldgcj_14_14_usable
  24. is_oldgcj_14_13_usable
  25. is_javac_present
  26. is_javac_usable
  27. is_jikes_present
  28. compile_java_class

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

/* [previous][next][first][last][top][bottom][index][help] */