1 /* Compile a Java program.
2 Copyright (C) 2001-2003, 2006-2018 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
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.
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.
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/>. */
30 #include <sys/types.h>
33 #include "javaversion.h"
35 #include "spawn-pipe.h"
36 #include "wait-process.h"
37 #include "classpath.h"
40 #include "binary-io.h"
41 #include "safe-read.h"
44 #include "concat-filename.h"
45 #include "fwriteerror.h"
46 #include "clean-temp.h"
48 #include "xvasprintf.h"
52 #define _(str) gettext (str)
55 /* Survey of Java compilers.
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
63 Program from A C O g T
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
71 All compilers support the option "-d DIRECTORY" for the base directory
72 of the classes to be written.
74 The CLASSPATH is a colon separated list of pathnames. (On Windows: a
75 semicolon separated list of pathnames.)
77 We try the Java compilers in the following order:
78 1. getenv ("JAVAC"), because the user must be able to override our
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.
86 We unset the JAVA_HOME environment variable, because a wrong setting of
87 this variable can confuse the JDK's javac.
90 /* Return the default target_version. */
92 default_target_version (void)
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
)
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. */
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";
123 java_version_cache
= "1.1";
125 return java_version_cache
;
128 /* ======================= Source version dependent ======================= */
130 /* Convert a source version to an index. */
131 #define SOURCE_VERSION_BOUND 8 /* exclusive upper bound */
133 source_version_index (const char *source_version
)
135 if (source_version
[0] == '1' && source_version
[1] == '.')
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';
144 else if (source_version
[0] == '9' && source_version
[1] == '\0')
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"));
154 /* Return a snippet of code that should compile in the given source version. */
156 get_goodcode_snippet (const char *source_version
)
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"));
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
182 get_failcode_snippet (const char *source_version
)
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)
200 error (EXIT_FAILURE
, 0, _("invalid source_version argument to compile_java_class"));
204 /* ======================= Target version dependent ======================= */
206 /* Convert a target version to an index. */
207 #define TARGET_VERSION_BOUND 11 /* exclusive upper bound */
209 target_version_index (const char *target_version
)
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')
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"));
225 /* Return the class file version number corresponding to a given target
228 corresponding_classfile_version (const char *target_version
)
230 if (strcmp (target_version
, "1.1") == 0)
232 if (strcmp (target_version
, "1.2") == 0)
234 if (strcmp (target_version
, "1.3") == 0)
236 if (strcmp (target_version
, "1.4") == 0)
238 if (strcmp (target_version
, "1.5") == 0)
240 if (strcmp (target_version
, "1.6") == 0)
242 if (strcmp (target_version
, "1.7") == 0)
244 if (strcmp (target_version
, "1.8") == 0)
246 if (strcmp (target_version
, "9") == 0)
248 if (strcmp (target_version
, "10") == 0)
250 if (strcmp (target_version
, "11") == 0)
252 error (EXIT_FAILURE
, 0, _("invalid target_version argument to compile_java_class"));
256 /* Return the source version to pass to javac. */
258 get_source_version_for_javac (const char *source_version
,
259 const char *target_version
)
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'))
269 return source_version
;
272 /* ======================== Compilation subroutines ======================== */
274 /* Try to compile a set of Java sources with $JAVAC.
275 Return a failure indicator (true upon error). */
277 compile_using_envjavac (const char *javac
,
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
)
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. */
289 unsigned int command_length
;
296 command_length
= strlen (javac
);
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
]);
307 command
= (char *) xmalloca (command_length
);
309 /* Don't shell_quote $JAVAC, because it may consist of a command
311 memcpy (p
, javac
, strlen (javac
));
315 memcpy (p
, " -O", 3);
320 memcpy (p
, " -g", 3);
323 if (directory
!= NULL
)
325 memcpy (p
, " -d ", 4);
327 p
= shell_quote_copy (p
, directory
);
329 for (i
= 0; i
< java_sources_count
; i
++)
332 p
= shell_quote_copy (p
, java_sources
[i
]);
335 /* Ensure command_length was correctly calculated. */
336 if (p
- command
> command_length
)
340 printf ("%s\n", command
);
342 argv
[0] = BOURNE_SHELL
;
346 exitstatus
= execute (javac
, BOURNE_SHELL
, argv
, false, false, false,
347 null_stderr
, true, true, NULL
);
348 err
= (exitstatus
!= 0);
355 /* Try to compile a set of Java sources with gcj.
356 Return a failure indicator (true upon error). */
358 compile_using_gcj (const char * const *java_sources
,
359 unsigned int java_sources_count
,
360 bool no_assert_option
,
361 bool fsource_option
, const char *source_version
,
362 bool ftarget_option
, const char *target_version
,
363 const char *directory
,
364 bool optimize
, bool debug
,
365 bool verbose
, bool null_stderr
)
377 2 + (no_assert_option
? 1 : 0) + (fsource_option
? 1 : 0)
378 + (ftarget_option
? 1 : 0) + (optimize
? 1 : 0) + (debug
? 1 : 0)
379 + (directory
!= NULL
? 2 : 0) + java_sources_count
;
380 argv
= (char **) xmalloca ((argc
+ 1) * sizeof (char *));
385 if (no_assert_option
)
386 *argp
++ = "-fno-assert";
389 fsource_arg
= (char *) xmalloca (9 + strlen (source_version
) + 1);
390 memcpy (fsource_arg
, "-fsource=", 9);
391 strcpy (fsource_arg
+ 9, source_version
);
392 *argp
++ = fsource_arg
;
398 ftarget_arg
= (char *) xmalloca (9 + strlen (target_version
) + 1);
399 memcpy (ftarget_arg
, "-ftarget=", 9);
400 strcpy (ftarget_arg
+ 9, target_version
);
401 *argp
++ = ftarget_arg
;
409 if (directory
!= NULL
)
412 *argp
++ = (char *) directory
;
414 for (i
= 0; i
< java_sources_count
; i
++)
415 *argp
++ = (char *) java_sources
[i
];
417 /* Ensure argv length was correctly calculated. */
418 if (argp
- argv
!= argc
)
423 char *command
= shell_quote_argv (argv
);
424 printf ("%s\n", command
);
428 exitstatus
= execute ("gcj", "gcj", argv
, false, false, false, null_stderr
,
430 err
= (exitstatus
!= 0);
432 if (ftarget_arg
!= NULL
)
434 if (fsource_arg
!= NULL
)
441 /* Try to compile a set of Java sources with javac.
442 Return a failure indicator (true upon error). */
444 compile_using_javac (const char * const *java_sources
,
445 unsigned int java_sources_count
,
446 bool source_option
, const char *source_version
,
447 bool target_option
, const char *target_version
,
448 const char *directory
,
449 bool optimize
, bool debug
,
450 bool verbose
, bool null_stderr
)
460 1 + (source_option
? 2 : 0) + (target_option
? 2 : 0) + (optimize
? 1 : 0)
461 + (debug
? 1 : 0) + (directory
!= NULL
? 2 : 0) + java_sources_count
;
462 argv
= (char **) xmalloca ((argc
+ 1) * sizeof (char *));
469 *argp
++ = (char *) source_version
;
474 *argp
++ = (char *) target_version
;
480 if (directory
!= NULL
)
483 *argp
++ = (char *) directory
;
485 for (i
= 0; i
< java_sources_count
; i
++)
486 *argp
++ = (char *) java_sources
[i
];
488 /* Ensure argv length was correctly calculated. */
489 if (argp
- argv
!= argc
)
494 char *command
= shell_quote_argv (argv
);
495 printf ("%s\n", command
);
499 exitstatus
= execute ("javac", "javac", argv
, false, false, false,
500 null_stderr
, true, true, NULL
);
501 err
= (exitstatus
!= 0);
508 /* Try to compile a set of Java sources with jikes.
509 Return a failure indicator (true upon error). */
511 compile_using_jikes (const char * const *java_sources
,
512 unsigned int java_sources_count
,
513 const char *directory
,
514 bool optimize
, bool debug
,
515 bool verbose
, bool null_stderr
)
525 1 + (optimize
? 1 : 0) + (debug
? 1 : 0) + (directory
!= NULL
? 2 : 0)
526 + java_sources_count
;
527 argv
= (char **) xmalloca ((argc
+ 1) * sizeof (char *));
535 if (directory
!= NULL
)
538 *argp
++ = (char *) directory
;
540 for (i
= 0; i
< java_sources_count
; i
++)
541 *argp
++ = (char *) java_sources
[i
];
543 /* Ensure argv length was correctly calculated. */
544 if (argp
- argv
!= argc
)
549 char *command
= shell_quote_argv (argv
);
550 printf ("%s\n", command
);
554 exitstatus
= execute ("jikes", "jikes", argv
, false, false, false,
555 null_stderr
, true, true, NULL
);
556 err
= (exitstatus
!= 0);
563 /* ====================== Usability test subroutines ====================== */
565 /* Write a given contents to a temporary file.
566 FILE_NAME is the name of a file inside TMPDIR that is known not to exist
568 Return a failure indicator (true upon error). */
570 write_temp_file (struct temp_dir
*tmpdir
, const char *file_name
,
571 const char *contents
)
575 register_temp_file (tmpdir
, file_name
);
576 fp
= fopen_temp (file_name
, "w");
579 error (0, errno
, _("failed to create \"%s\""), file_name
);
580 unregister_temp_file (tmpdir
, file_name
);
583 fputs (contents
, fp
);
584 if (fwriteerror_temp (fp
))
586 error (0, errno
, _("error while writing \"%s\" file"), file_name
);
592 /* Return the class file version number of a class file on disk. */
594 get_classfile_version (const char *compiled_file_name
)
596 unsigned char header
[8];
599 /* Open the class file. */
600 fd
= open (compiled_file_name
, O_RDONLY
| O_BINARY
, 0);
603 /* Read its first 8 bytes. */
604 if (safe_read (fd
, header
, 8) == 8)
606 /* Verify the class file signature. */
607 if (header
[0] == 0xCA && header
[1] == 0xFE
608 && header
[2] == 0xBA && header
[3] == 0xBE)
617 /* Could not get the class file version. Return a very large one. */
621 /* Return true if $JAVAC is a version of gcj. */
623 is_envjavac_gcj (const char *javac
)
625 static bool envjavac_tested
;
626 static bool envjavac_gcj
;
628 if (!envjavac_tested
)
630 /* Test whether $JAVAC is gcj:
631 "$JAVAC --version 2>/dev/null | sed -e 1q | grep gcj > /dev/null" */
632 unsigned int command_length
;
644 /* Setup the command "$JAVAC --version". */
645 command_length
= strlen (javac
) + 1 + 9 + 1;
646 command
= (char *) xmalloca (command_length
);
648 /* Don't shell_quote $JAVAC, because it may consist of a command
650 memcpy (p
, javac
, strlen (javac
));
652 memcpy (p
, " --version", 1 + 9 + 1);
654 /* Ensure command_length was correctly calculated. */
655 if (p
- command
> command_length
)
658 /* Call $JAVAC --version 2>/dev/null. */
659 argv
[0] = BOURNE_SHELL
;
663 child
= create_pipe_in (javac
, BOURNE_SHELL
, argv
, DEV_NULL
, true, true,
668 /* Retrieve its result. */
669 fp
= fdopen (fd
[0], "r");
673 line
= NULL
; linesize
= 0;
674 linelen
= getline (&line
, &linesize
, fp
);
675 if (linelen
== (size_t)(-1))
680 /* It is safe to call c_strstr() instead of strstr() here; see the
681 comments in c-strstr.h. */
682 envjavac_gcj
= (c_strstr (line
, "gcj") != NULL
);
686 /* Remove zombie process from process list, and retrieve exit status. */
688 wait_subprocess (child
, javac
, true, true, true, false, NULL
);
690 envjavac_gcj
= false;
695 envjavac_tested
= true;
701 /* Return true if $JAVAC, known to be a version of gcj, is a version >= 4.3
704 is_envjavac_gcj43 (const char *javac
)
706 static bool envjavac_tested
;
707 static bool envjavac_gcj43
;
709 if (!envjavac_tested
)
711 /* Test whether $JAVAC is gcj:
712 "$JAVAC --version 2>/dev/null | sed -e 's,^[^0-9]*,,' -e 1q \
713 | sed -e '/^4\.[012]/d' | grep '^[4-9]' >/dev/null" */
714 unsigned int command_length
;
726 /* Setup the command "$JAVAC --version". */
727 command_length
= strlen (javac
) + 1 + 9 + 1;
728 command
= (char *) xmalloca (command_length
);
730 /* Don't shell_quote $JAVAC, because it may consist of a command
732 memcpy (p
, javac
, strlen (javac
));
734 memcpy (p
, " --version", 1 + 9 + 1);
736 /* Ensure command_length was correctly calculated. */
737 if (p
- command
> command_length
)
740 /* Call $JAVAC --version 2>/dev/null. */
741 argv
[0] = BOURNE_SHELL
;
745 child
= create_pipe_in (javac
, BOURNE_SHELL
, argv
, DEV_NULL
, true, true,
750 /* Retrieve its result. */
751 fp
= fdopen (fd
[0], "r");
755 line
= NULL
; linesize
= 0;
756 linelen
= getline (&line
, &linesize
, fp
);
757 if (linelen
== (size_t)(-1))
763 while (*p
!= '\0' && !(*p
>= '0' && *p
<= '9'))
766 !(*p
== '4' && p
[1] == '.' && p
[2] >= '0' && p
[2] <= '2')
767 && (*p
>= '4' && *p
<= '9');
771 /* Remove zombie process from process list, and retrieve exit status. */
773 wait_subprocess (child
, javac
, true, true, true, false, NULL
);
775 envjavac_gcj43
= false;
780 envjavac_tested
= true;
783 return envjavac_gcj43
;
786 /* Test whether $JAVAC, known to be a version of gcj >= 4.3, can be used, and
787 whether it needs a -fsource and/or -ftarget option.
788 Return a failure indicator (true upon error). */
790 is_envjavac_gcj43_usable (const char *javac
,
791 const char *source_version
,
792 const char *target_version
,
794 bool *fsource_option_p
, bool *ftarget_option_p
)
796 /* The cache depends on the source_version and target_version. */
804 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
805 struct result_t
*resultp
;
807 resultp
= &result_cache
[source_version_index (source_version
)]
808 [target_version_index (target_version
)];
809 if (!resultp
->tested
)
812 struct temp_dir
*tmpdir
;
813 char *conftest_file_name
;
814 char *compiled_file_name
;
815 const char *java_sources
[1];
818 tmpdir
= create_temp_dir ("java", NULL
, false);
823 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
824 if (write_temp_file (tmpdir
, conftest_file_name
,
825 get_goodcode_snippet (source_version
)))
827 free (conftest_file_name
);
828 cleanup_temp_dir (tmpdir
);
833 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
834 register_temp_file (tmpdir
, compiled_file_name
);
836 java_sources
[0] = conftest_file_name
;
837 if (!compile_using_envjavac (javac
,
838 java_sources
, 1, tmpdir
->dir_name
,
839 false, false, false, true)
840 && stat (compiled_file_name
, &statbuf
) >= 0
841 && get_classfile_version (compiled_file_name
)
842 <= corresponding_classfile_version (target_version
))
844 /* $JAVAC compiled conftest.java successfully. */
845 /* Try adding -fsource option if it is useful. */
847 xasprintf ("%s -fsource=%s", javac
, source_version
);
849 unlink (compiled_file_name
);
851 java_sources
[0] = conftest_file_name
;
852 if (!compile_using_envjavac (javac_source
,
853 java_sources
, 1, tmpdir
->dir_name
,
854 false, false, false, true)
855 && stat (compiled_file_name
, &statbuf
) >= 0
856 && get_classfile_version (compiled_file_name
)
857 <= corresponding_classfile_version (target_version
))
859 const char *failcode
= get_failcode_snippet (source_version
);
861 if (failcode
!= NULL
)
863 free (compiled_file_name
);
864 free (conftest_file_name
);
867 xconcatenated_filename (tmpdir
->dir_name
,
870 if (write_temp_file (tmpdir
, conftest_file_name
, failcode
))
872 free (conftest_file_name
);
874 cleanup_temp_dir (tmpdir
);
879 xconcatenated_filename (tmpdir
->dir_name
,
880 "conftestfail.class",
882 register_temp_file (tmpdir
, compiled_file_name
);
884 java_sources
[0] = conftest_file_name
;
885 if (!compile_using_envjavac (javac
,
888 false, false, false, true)
889 && stat (compiled_file_name
, &statbuf
) >= 0)
891 unlink (compiled_file_name
);
893 java_sources
[0] = conftest_file_name
;
894 if (compile_using_envjavac (javac_source
,
897 false, false, false, true))
898 /* $JAVAC compiled conftestfail.java successfully, and
899 "$JAVAC -fsource=$source_version" rejects it. So
900 the -fsource option is useful. */
901 resultp
->fsource_option
= true;
908 resultp
->usable
= true;
912 /* Try with -fsource and -ftarget options. */
914 xasprintf ("%s -fsource=%s -ftarget=%s",
915 javac
, source_version
, target_version
);
917 unlink (compiled_file_name
);
919 java_sources
[0] = conftest_file_name
;
920 if (!compile_using_envjavac (javac_target
,
921 java_sources
, 1, tmpdir
->dir_name
,
922 false, false, false, true)
923 && stat (compiled_file_name
, &statbuf
) >= 0
924 && get_classfile_version (compiled_file_name
)
925 <= corresponding_classfile_version (target_version
))
927 /* "$JAVAC -fsource $source_version -ftarget $target_version"
928 compiled conftest.java successfully. */
929 resultp
->fsource_option
= true;
930 resultp
->ftarget_option
= true;
931 resultp
->usable
= true;
937 free (compiled_file_name
);
938 free (conftest_file_name
);
940 resultp
->tested
= true;
943 *usablep
= resultp
->usable
;
944 *fsource_option_p
= resultp
->fsource_option
;
945 *ftarget_option_p
= resultp
->ftarget_option
;
949 /* Test whether $JAVAC, known to be a version of gcj < 4.3, can be used for
950 compiling with target_version = 1.4 and source_version = 1.4.
951 Return a failure indicator (true upon error). */
953 is_envjavac_oldgcj_14_14_usable (const char *javac
, bool *usablep
)
955 static bool envjavac_tested
;
956 static bool envjavac_usable
;
958 if (!envjavac_tested
)
961 struct temp_dir
*tmpdir
;
962 char *conftest_file_name
;
963 char *compiled_file_name
;
964 const char *java_sources
[1];
967 tmpdir
= create_temp_dir ("java", NULL
, false);
972 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
973 if (write_temp_file (tmpdir
, conftest_file_name
,
974 get_goodcode_snippet ("1.4")))
976 free (conftest_file_name
);
977 cleanup_temp_dir (tmpdir
);
982 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
983 register_temp_file (tmpdir
, compiled_file_name
);
985 java_sources
[0] = conftest_file_name
;
986 if (!compile_using_envjavac (javac
, java_sources
, 1, tmpdir
->dir_name
,
987 false, false, false, true)
988 && stat (compiled_file_name
, &statbuf
) >= 0)
989 /* Compilation succeeded. */
990 envjavac_usable
= true;
992 free (compiled_file_name
);
993 free (conftest_file_name
);
995 cleanup_temp_dir (tmpdir
);
997 envjavac_tested
= true;
1000 *usablep
= envjavac_usable
;
1004 /* Test whether $JAVAC, known to be a version of gcj < 4.3, can be used for
1005 compiling with target_version = 1.4 and source_version = 1.3.
1006 Return a failure indicator (true upon error). */
1008 is_envjavac_oldgcj_14_13_usable (const char *javac
,
1009 bool *usablep
, bool *need_no_assert_option_p
)
1011 static bool envjavac_tested
;
1012 static bool envjavac_usable
;
1013 static bool envjavac_need_no_assert_option
;
1015 if (!envjavac_tested
)
1017 /* Try $JAVAC and "$JAVAC -fno-assert". But add -fno-assert only if
1018 it makes a difference. (It could already be part of $JAVAC.) */
1019 struct temp_dir
*tmpdir
;
1020 char *conftest_file_name
;
1021 char *compiled_file_name
;
1022 const char *java_sources
[1];
1023 struct stat statbuf
;
1025 char *javac_noassert
;
1026 bool javac_noassert_works
;
1028 tmpdir
= create_temp_dir ("java", NULL
, false);
1032 conftest_file_name
=
1033 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1034 if (write_temp_file (tmpdir
, conftest_file_name
,
1035 get_goodcode_snippet ("1.3")))
1037 free (conftest_file_name
);
1038 cleanup_temp_dir (tmpdir
);
1042 compiled_file_name
=
1043 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1044 register_temp_file (tmpdir
, compiled_file_name
);
1046 java_sources
[0] = conftest_file_name
;
1047 if (!compile_using_envjavac (javac
,
1048 java_sources
, 1, tmpdir
->dir_name
,
1049 false, false, false, true)
1050 && stat (compiled_file_name
, &statbuf
) >= 0)
1051 /* Compilation succeeded. */
1054 javac_works
= false;
1056 unlink (compiled_file_name
);
1058 javac_noassert
= xasprintf ("%s -fno-assert", javac
);
1060 java_sources
[0] = conftest_file_name
;
1061 if (!compile_using_envjavac (javac_noassert
,
1062 java_sources
, 1, tmpdir
->dir_name
,
1063 false, false, false, true)
1064 && stat (compiled_file_name
, &statbuf
) >= 0)
1065 /* Compilation succeeded. */
1066 javac_noassert_works
= true;
1068 javac_noassert_works
= false;
1070 free (compiled_file_name
);
1071 free (conftest_file_name
);
1073 if (javac_works
&& javac_noassert_works
)
1075 conftest_file_name
=
1076 xconcatenated_filename (tmpdir
->dir_name
, "conftestfail.java",
1078 if (write_temp_file (tmpdir
, conftest_file_name
,
1079 get_failcode_snippet ("1.3")))
1081 free (conftest_file_name
);
1082 free (javac_noassert
);
1083 cleanup_temp_dir (tmpdir
);
1087 compiled_file_name
=
1088 xconcatenated_filename (tmpdir
->dir_name
, "conftestfail.class",
1090 register_temp_file (tmpdir
, compiled_file_name
);
1092 java_sources
[0] = conftest_file_name
;
1093 if (!compile_using_envjavac (javac
,
1094 java_sources
, 1, tmpdir
->dir_name
,
1095 false, false, false, true)
1096 && stat (compiled_file_name
, &statbuf
) >= 0)
1098 /* Compilation succeeded. */
1099 unlink (compiled_file_name
);
1101 java_sources
[0] = conftest_file_name
;
1102 if (!(!compile_using_envjavac (javac_noassert
,
1103 java_sources
, 1, tmpdir
->dir_name
,
1104 false, false, false, true)
1105 && stat (compiled_file_name
, &statbuf
) >= 0))
1106 /* Compilation failed. */
1107 /* "$JAVAC -fno-assert" works better than $JAVAC. */
1111 free (compiled_file_name
);
1112 free (conftest_file_name
);
1115 cleanup_temp_dir (tmpdir
);
1119 envjavac_usable
= true;
1120 envjavac_need_no_assert_option
= false;
1122 else if (javac_noassert_works
)
1124 envjavac_usable
= true;
1125 envjavac_need_no_assert_option
= true;
1128 envjavac_tested
= true;
1131 *usablep
= envjavac_usable
;
1132 *need_no_assert_option_p
= envjavac_need_no_assert_option
;
1136 /* Test whether $JAVAC, known to be not a version of gcj, can be used, and
1137 whether it needs a -source and/or -target option.
1138 Return a failure indicator (true upon error). */
1140 is_envjavac_nongcj_usable (const char *javac
,
1141 const char *source_version
,
1142 const char *source_version_for_javac
,
1143 const char *target_version
,
1145 bool *source_option_p
, bool *target_option_p
)
1147 /* The cache depends on the source_version and target_version. */
1155 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
1156 struct result_t
*resultp
;
1158 resultp
= &result_cache
[source_version_index (source_version
)]
1159 [target_version_index (target_version
)];
1160 if (!resultp
->tested
)
1163 struct temp_dir
*tmpdir
;
1164 char *conftest_file_name
;
1165 char *compiled_file_name
;
1166 const char *java_sources
[1];
1167 struct stat statbuf
;
1169 tmpdir
= create_temp_dir ("java", NULL
, false);
1173 conftest_file_name
=
1174 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1175 if (write_temp_file (tmpdir
, conftest_file_name
,
1176 get_goodcode_snippet (source_version
)))
1178 free (conftest_file_name
);
1179 cleanup_temp_dir (tmpdir
);
1183 compiled_file_name
=
1184 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1185 register_temp_file (tmpdir
, compiled_file_name
);
1187 java_sources
[0] = conftest_file_name
;
1188 if (!compile_using_envjavac (javac
,
1189 java_sources
, 1, tmpdir
->dir_name
,
1190 false, false, false, true)
1191 && stat (compiled_file_name
, &statbuf
) >= 0
1192 && get_classfile_version (compiled_file_name
)
1193 <= corresponding_classfile_version (target_version
))
1195 /* $JAVAC compiled conftest.java successfully. */
1196 /* Try adding -source option if it is useful. */
1197 char *javac_source
=
1198 xasprintf ("%s -source %s", javac
, source_version_for_javac
);
1200 unlink (compiled_file_name
);
1202 java_sources
[0] = conftest_file_name
;
1203 if (!compile_using_envjavac (javac_source
,
1204 java_sources
, 1, tmpdir
->dir_name
,
1205 false, false, false, true)
1206 && stat (compiled_file_name
, &statbuf
) >= 0
1207 && get_classfile_version (compiled_file_name
)
1208 <= corresponding_classfile_version (target_version
))
1210 const char *failcode
= get_failcode_snippet (source_version
);
1212 if (failcode
!= NULL
)
1214 free (compiled_file_name
);
1215 free (conftest_file_name
);
1217 conftest_file_name
=
1218 xconcatenated_filename (tmpdir
->dir_name
,
1219 "conftestfail.java",
1221 if (write_temp_file (tmpdir
, conftest_file_name
, failcode
))
1223 free (conftest_file_name
);
1224 free (javac_source
);
1225 cleanup_temp_dir (tmpdir
);
1229 compiled_file_name
=
1230 xconcatenated_filename (tmpdir
->dir_name
,
1231 "conftestfail.class",
1233 register_temp_file (tmpdir
, compiled_file_name
);
1235 java_sources
[0] = conftest_file_name
;
1236 if (!compile_using_envjavac (javac
,
1239 false, false, false, true)
1240 && stat (compiled_file_name
, &statbuf
) >= 0)
1242 unlink (compiled_file_name
);
1244 java_sources
[0] = conftest_file_name
;
1245 if (compile_using_envjavac (javac_source
,
1248 false, false, false, true))
1249 /* $JAVAC compiled conftestfail.java successfully, and
1250 "$JAVAC -source $source_version_for_javac" rejects it.
1251 So the -source option is useful. */
1252 resultp
->source_option
= true;
1257 free (javac_source
);
1259 resultp
->usable
= true;
1263 /* Try with -target option alone. (Sun javac 1.3.1 has the -target
1264 option but no -source option.) */
1265 char *javac_target
=
1266 xasprintf ("%s -target %s", javac
, target_version
);
1268 unlink (compiled_file_name
);
1270 java_sources
[0] = conftest_file_name
;
1271 if (!compile_using_envjavac (javac_target
,
1272 java_sources
, 1, tmpdir
->dir_name
,
1273 false, false, false, true)
1274 && stat (compiled_file_name
, &statbuf
) >= 0
1275 && get_classfile_version (compiled_file_name
)
1276 <= corresponding_classfile_version (target_version
))
1278 /* "$JAVAC -target $target_version" compiled conftest.java
1280 /* Try adding -source option if it is useful. */
1281 char *javac_target_source
=
1282 xasprintf ("%s -source %s", javac_target
, source_version_for_javac
);
1284 unlink (compiled_file_name
);
1286 java_sources
[0] = conftest_file_name
;
1287 if (!compile_using_envjavac (javac_target_source
,
1288 java_sources
, 1, tmpdir
->dir_name
,
1289 false, false, false, true)
1290 && stat (compiled_file_name
, &statbuf
) >= 0
1291 && get_classfile_version (compiled_file_name
)
1292 <= corresponding_classfile_version (target_version
))
1294 const char *failcode
= get_failcode_snippet (source_version
);
1296 if (failcode
!= NULL
)
1298 free (compiled_file_name
);
1299 free (conftest_file_name
);
1301 conftest_file_name
=
1302 xconcatenated_filename (tmpdir
->dir_name
,
1303 "conftestfail.java",
1305 if (write_temp_file (tmpdir
, conftest_file_name
,
1308 free (conftest_file_name
);
1309 free (javac_target_source
);
1310 free (javac_target
);
1311 cleanup_temp_dir (tmpdir
);
1315 compiled_file_name
=
1316 xconcatenated_filename (tmpdir
->dir_name
,
1317 "conftestfail.class",
1319 register_temp_file (tmpdir
, compiled_file_name
);
1321 java_sources
[0] = conftest_file_name
;
1322 if (!compile_using_envjavac (javac_target
,
1325 false, false, false, true)
1326 && stat (compiled_file_name
, &statbuf
) >= 0)
1328 unlink (compiled_file_name
);
1330 java_sources
[0] = conftest_file_name
;
1331 if (compile_using_envjavac (javac_target_source
,
1334 false, false, false,
1336 /* "$JAVAC -target $target_version" compiled
1337 conftestfail.java successfully, and
1338 "$JAVAC -target $target_version -source $source_version_for_javac"
1339 rejects it. So the -source option is useful. */
1340 resultp
->source_option
= true;
1345 free (javac_target_source
);
1347 resultp
->target_option
= true;
1348 resultp
->usable
= true;
1352 /* Maybe this -target option requires a -source option? Try with
1353 -target and -source options. (Supported by Sun javac 1.4 and
1355 char *javac_target_source
=
1356 xasprintf ("%s -source %s", javac_target
, source_version_for_javac
);
1358 unlink (compiled_file_name
);
1360 java_sources
[0] = conftest_file_name
;
1361 if (!compile_using_envjavac (javac_target_source
,
1362 java_sources
, 1, tmpdir
->dir_name
,
1363 false, false, false, true)
1364 && stat (compiled_file_name
, &statbuf
) >= 0
1365 && get_classfile_version (compiled_file_name
)
1366 <= corresponding_classfile_version (target_version
))
1368 /* "$JAVAC -target $target_version -source $source_version_for_javac"
1369 compiled conftest.java successfully. */
1370 resultp
->source_option
= true;
1371 resultp
->target_option
= true;
1372 resultp
->usable
= true;
1375 free (javac_target_source
);
1378 free (javac_target
);
1381 free (compiled_file_name
);
1382 free (conftest_file_name
);
1384 resultp
->tested
= true;
1387 *usablep
= resultp
->usable
;
1388 *source_option_p
= resultp
->source_option
;
1389 *target_option_p
= resultp
->target_option
;
1394 is_gcj_present (void)
1396 static bool gcj_tested
;
1397 static bool gcj_present
;
1401 /* Test for presence of gcj:
1402 "gcj --version 2> /dev/null | \
1403 sed -e 's,^[^0-9]*,,' -e 1q | \
1404 sed -e '/^3\.[01]/d' | grep '^[3-9]' > /dev/null" */
1411 argv
[1] = "--version";
1413 child
= create_pipe_in ("gcj", "gcj", argv
, DEV_NULL
, true, true,
1415 gcj_present
= false;
1418 /* Read the subprocess output, drop all lines except the first,
1419 drop all characters before the first digit, and test whether
1420 the remaining string starts with a digit >= 3, but not with
1425 while (safe_read (fd
[0], &c
[count
], 1) > 0)
1427 if (c
[count
] == '\n')
1431 if (!(c
[0] >= '0' && c
[0] <= '9'))
1433 gcj_present
= (c
[0] >= '3');
1438 if (c
[0] == '3' && c
[1] == '.'
1439 && (c
[2] == '0' || c
[2] == '1'))
1440 gcj_present
= false;
1444 while (safe_read (fd
[0], &c
[0], 1) > 0)
1449 /* Remove zombie process from process list, and retrieve exit
1452 wait_subprocess (child
, "gcj", false, true, true, false, NULL
);
1453 if (exitstatus
!= 0)
1454 gcj_present
= false;
1459 /* See if libgcj.jar is well installed. */
1460 struct temp_dir
*tmpdir
;
1462 tmpdir
= create_temp_dir ("java", NULL
, false);
1464 gcj_present
= false;
1467 char *conftest_file_name
;
1469 conftest_file_name
=
1470 xconcatenated_filename (tmpdir
->dir_name
, "conftestlib.java",
1472 if (write_temp_file (tmpdir
, conftest_file_name
,
1473 "public class conftestlib {\n"
1474 " public static void main (String[] args) {\n"
1477 gcj_present
= false;
1480 char *compiled_file_name
;
1481 const char *java_sources
[1];
1483 compiled_file_name
=
1484 xconcatenated_filename (tmpdir
->dir_name
,
1485 "conftestlib.class",
1487 register_temp_file (tmpdir
, compiled_file_name
);
1489 java_sources
[0] = conftest_file_name
;
1490 if (compile_using_gcj (java_sources
, 1, false,
1491 false, NULL
, false, NULL
,
1493 false, false, false, true))
1494 gcj_present
= false;
1496 free (compiled_file_name
);
1498 free (conftest_file_name
);
1500 cleanup_temp_dir (tmpdir
);
1512 static bool gcj_tested
;
1517 /* Test for presence of gcj:
1518 "gcj --version 2> /dev/null | \
1519 sed -e 's,^[^0-9]*,,' -e 1q | \
1520 sed -e '/^4\.[012]/d' | grep '^[4-9]'" */
1527 argv
[1] = "--version";
1529 child
= create_pipe_in ("gcj", "gcj", argv
, DEV_NULL
, true, true,
1534 /* Read the subprocess output, drop all lines except the first,
1535 drop all characters before the first digit, and test whether
1536 the remaining string starts with a digit >= 4, but not with
1537 "4.0" or "4.1" or "4.2". */
1541 while (safe_read (fd
[0], &c
[count
], 1) > 0)
1543 if (c
[count
] == '\n')
1547 if (!(c
[0] >= '0' && c
[0] <= '9'))
1549 gcj_43
= (c
[0] >= '4');
1554 if (c
[0] == '4' && c
[1] == '.' && c
[2] >= '0' && c
[2] <= '2')
1559 while (safe_read (fd
[0], &c
[0], 1) > 0)
1564 /* Remove zombie process from process list, and retrieve exit
1567 wait_subprocess (child
, "gcj", false, true, true, false, NULL
);
1568 if (exitstatus
!= 0)
1578 /* Test whether gcj >= 4.3 can be used, and whether it needs a -fsource and/or
1580 Return a failure indicator (true upon error). */
1582 is_gcj43_usable (const char *source_version
,
1583 const char *target_version
,
1585 bool *fsource_option_p
, bool *ftarget_option_p
)
1587 /* The cache depends on the source_version and target_version. */
1592 bool fsource_option
;
1593 bool ftarget_option
;
1595 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
1596 struct result_t
*resultp
;
1598 resultp
= &result_cache
[source_version_index (source_version
)]
1599 [target_version_index (target_version
)];
1600 if (!resultp
->tested
)
1603 struct temp_dir
*tmpdir
;
1604 char *conftest_file_name
;
1605 char *compiled_file_name
;
1606 const char *java_sources
[1];
1607 struct stat statbuf
;
1609 tmpdir
= create_temp_dir ("java", NULL
, false);
1613 conftest_file_name
=
1614 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1615 if (write_temp_file (tmpdir
, conftest_file_name
,
1616 get_goodcode_snippet (source_version
)))
1618 free (conftest_file_name
);
1619 cleanup_temp_dir (tmpdir
);
1623 compiled_file_name
=
1624 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1625 register_temp_file (tmpdir
, compiled_file_name
);
1627 java_sources
[0] = conftest_file_name
;
1628 if (!compile_using_gcj (java_sources
, 1, false, false, NULL
, false, NULL
,
1629 tmpdir
->dir_name
, false, false, false, true)
1630 && stat (compiled_file_name
, &statbuf
) >= 0
1631 && get_classfile_version (compiled_file_name
)
1632 <= corresponding_classfile_version (target_version
))
1634 /* gcj compiled conftest.java successfully. */
1635 /* Try adding -fsource option if it is useful. */
1636 unlink (compiled_file_name
);
1638 java_sources
[0] = conftest_file_name
;
1639 if (!compile_using_gcj (java_sources
, 1,
1640 false, true, source_version
, false, NULL
,
1641 tmpdir
->dir_name
, false, false, false, true)
1642 && stat (compiled_file_name
, &statbuf
) >= 0
1643 && get_classfile_version (compiled_file_name
)
1644 <= corresponding_classfile_version (target_version
))
1646 const char *failcode
= get_failcode_snippet (source_version
);
1648 if (failcode
!= NULL
)
1650 free (compiled_file_name
);
1651 free (conftest_file_name
);
1653 conftest_file_name
=
1654 xconcatenated_filename (tmpdir
->dir_name
,
1655 "conftestfail.java",
1657 if (write_temp_file (tmpdir
, conftest_file_name
, failcode
))
1659 free (conftest_file_name
);
1660 cleanup_temp_dir (tmpdir
);
1664 compiled_file_name
=
1665 xconcatenated_filename (tmpdir
->dir_name
,
1666 "conftestfail.class",
1668 register_temp_file (tmpdir
, compiled_file_name
);
1670 java_sources
[0] = conftest_file_name
;
1671 if (!compile_using_gcj (java_sources
, 1,
1672 false, false, NULL
, false, NULL
,
1674 false, false, false, true)
1675 && stat (compiled_file_name
, &statbuf
) >= 0)
1677 unlink (compiled_file_name
);
1679 java_sources
[0] = conftest_file_name
;
1680 if (compile_using_gcj (java_sources
, 1,
1681 false, true, source_version
,
1684 false, false, false, true))
1685 /* gcj compiled conftestfail.java successfully, and
1686 "gcj -fsource=$source_version" rejects it. So
1687 the -fsource option is useful. */
1688 resultp
->fsource_option
= true;
1693 resultp
->usable
= true;
1697 /* Try with -fsource and -ftarget options. */
1698 unlink (compiled_file_name
);
1700 java_sources
[0] = conftest_file_name
;
1701 if (!compile_using_gcj (java_sources
, 1,
1702 false, true, source_version
,
1703 true, target_version
,
1705 false, false, false, true)
1706 && stat (compiled_file_name
, &statbuf
) >= 0
1707 && get_classfile_version (compiled_file_name
)
1708 <= corresponding_classfile_version (target_version
))
1710 /* "gcj -fsource $source_version -ftarget $target_version"
1711 compiled conftest.java successfully. */
1712 resultp
->fsource_option
= true;
1713 resultp
->ftarget_option
= true;
1714 resultp
->usable
= true;
1718 free (compiled_file_name
);
1719 free (conftest_file_name
);
1721 resultp
->tested
= true;
1724 *usablep
= resultp
->usable
;
1725 *fsource_option_p
= resultp
->fsource_option
;
1726 *ftarget_option_p
= resultp
->ftarget_option
;
1730 /* Test whether gcj < 4.3 can be used for compiling with target_version = 1.4
1731 and source_version = 1.4.
1732 Return a failure indicator (true upon error). */
1734 is_oldgcj_14_14_usable (bool *usablep
)
1736 static bool gcj_tested
;
1737 static bool gcj_usable
;
1742 struct temp_dir
*tmpdir
;
1743 char *conftest_file_name
;
1744 char *compiled_file_name
;
1745 const char *java_sources
[1];
1746 struct stat statbuf
;
1748 tmpdir
= create_temp_dir ("java", NULL
, false);
1752 conftest_file_name
=
1753 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1754 if (write_temp_file (tmpdir
, conftest_file_name
,
1755 get_goodcode_snippet ("1.4")))
1757 free (conftest_file_name
);
1758 cleanup_temp_dir (tmpdir
);
1762 compiled_file_name
=
1763 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1764 register_temp_file (tmpdir
, compiled_file_name
);
1766 java_sources
[0] = conftest_file_name
;
1767 if (!compile_using_gcj (java_sources
, 1, false, false, NULL
, false, NULL
,
1768 tmpdir
->dir_name
, false, false, false, true)
1769 && stat (compiled_file_name
, &statbuf
) >= 0)
1770 /* Compilation succeeded. */
1773 free (compiled_file_name
);
1774 free (conftest_file_name
);
1776 cleanup_temp_dir (tmpdir
);
1781 *usablep
= gcj_usable
;
1785 /* Test whether gcj < 4.3 can be used for compiling with target_version = 1.4
1786 and source_version = 1.3.
1787 Return a failure indicator (true upon error). */
1789 is_oldgcj_14_13_usable (bool *usablep
, bool *need_no_assert_option_p
)
1791 static bool gcj_tested
;
1792 static bool gcj_usable
;
1793 static bool gcj_need_no_assert_option
;
1797 /* Try gcj and "gcj -fno-assert". But add -fno-assert only if
1798 it works (not gcj < 3.3). */
1799 struct temp_dir
*tmpdir
;
1800 char *conftest_file_name
;
1801 char *compiled_file_name
;
1802 const char *java_sources
[1];
1803 struct stat statbuf
;
1805 tmpdir
= create_temp_dir ("java", NULL
, false);
1809 conftest_file_name
=
1810 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1811 if (write_temp_file (tmpdir
, conftest_file_name
,
1812 get_goodcode_snippet ("1.3")))
1814 free (conftest_file_name
);
1815 cleanup_temp_dir (tmpdir
);
1819 compiled_file_name
=
1820 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1821 register_temp_file (tmpdir
, compiled_file_name
);
1823 java_sources
[0] = conftest_file_name
;
1824 if (!compile_using_gcj (java_sources
, 1, true, false, NULL
, false, NULL
,
1825 tmpdir
->dir_name
, false, false, false, true)
1826 && stat (compiled_file_name
, &statbuf
) >= 0)
1827 /* Compilation succeeded. */
1830 gcj_need_no_assert_option
= true;
1834 unlink (compiled_file_name
);
1836 java_sources
[0] = conftest_file_name
;
1837 if (!compile_using_gcj (java_sources
, 1, false,
1838 false, NULL
, false, NULL
,
1839 tmpdir
->dir_name
, false, false, false, true)
1840 && stat (compiled_file_name
, &statbuf
) >= 0)
1841 /* Compilation succeeded. */
1844 gcj_need_no_assert_option
= false;
1848 free (compiled_file_name
);
1849 free (conftest_file_name
);
1851 cleanup_temp_dir (tmpdir
);
1856 *usablep
= gcj_usable
;
1857 *need_no_assert_option_p
= gcj_need_no_assert_option
;
1862 is_javac_present (void)
1864 static bool javac_tested
;
1865 static bool javac_present
;
1869 /* Test for presence of javac: "javac 2> /dev/null ; test $? -le 2" */
1875 exitstatus
= execute ("javac", "javac", argv
, false, false, true, true,
1877 javac_present
= (exitstatus
== 0 || exitstatus
== 1 || exitstatus
== 2);
1878 javac_tested
= true;
1881 return javac_present
;
1884 /* Test whether javac can be used and whether it needs a -source and/or
1886 Return a failure indicator (true upon error). */
1888 is_javac_usable (const char *source_version
,
1889 const char *source_version_for_javac
,
1890 const char *target_version
,
1891 bool *usablep
, bool *source_option_p
, bool *target_option_p
)
1893 /* The cache depends on the source_version and target_version. */
1901 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
1902 struct result_t
*resultp
;
1904 resultp
= &result_cache
[source_version_index (source_version
)]
1905 [target_version_index (target_version
)];
1906 if (!resultp
->tested
)
1909 struct temp_dir
*tmpdir
;
1910 char *conftest_file_name
;
1911 char *compiled_file_name
;
1912 const char *java_sources
[1];
1913 struct stat statbuf
;
1915 tmpdir
= create_temp_dir ("java", NULL
, false);
1919 conftest_file_name
=
1920 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
1921 if (write_temp_file (tmpdir
, conftest_file_name
,
1922 get_goodcode_snippet (source_version
)))
1924 free (conftest_file_name
);
1925 cleanup_temp_dir (tmpdir
);
1929 compiled_file_name
=
1930 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
1931 register_temp_file (tmpdir
, compiled_file_name
);
1933 java_sources
[0] = conftest_file_name
;
1934 if (!compile_using_javac (java_sources
, 1,
1935 false, source_version_for_javac
,
1936 false, target_version
,
1937 tmpdir
->dir_name
, false, false, false, true)
1938 && stat (compiled_file_name
, &statbuf
) >= 0
1939 && get_classfile_version (compiled_file_name
)
1940 <= corresponding_classfile_version (target_version
))
1942 /* javac compiled conftest.java successfully. */
1943 /* Try adding -source option if it is useful. */
1944 unlink (compiled_file_name
);
1946 java_sources
[0] = conftest_file_name
;
1947 if (!compile_using_javac (java_sources
, 1,
1948 true, source_version_for_javac
,
1949 false, target_version
,
1950 tmpdir
->dir_name
, false, false, false, true)
1951 && stat (compiled_file_name
, &statbuf
) >= 0
1952 && get_classfile_version (compiled_file_name
)
1953 <= corresponding_classfile_version (target_version
))
1955 const char *failcode
= get_failcode_snippet (source_version
);
1957 if (failcode
!= NULL
)
1959 free (compiled_file_name
);
1960 free (conftest_file_name
);
1962 conftest_file_name
=
1963 xconcatenated_filename (tmpdir
->dir_name
,
1964 "conftestfail.java",
1966 if (write_temp_file (tmpdir
, conftest_file_name
, failcode
))
1968 free (conftest_file_name
);
1969 cleanup_temp_dir (tmpdir
);
1973 compiled_file_name
=
1974 xconcatenated_filename (tmpdir
->dir_name
,
1975 "conftestfail.class",
1977 register_temp_file (tmpdir
, compiled_file_name
);
1979 java_sources
[0] = conftest_file_name
;
1980 if (!compile_using_javac (java_sources
, 1,
1981 false, source_version_for_javac
,
1982 false, target_version
,
1984 false, false, false, true)
1985 && stat (compiled_file_name
, &statbuf
) >= 0)
1987 unlink (compiled_file_name
);
1989 java_sources
[0] = conftest_file_name
;
1990 if (compile_using_javac (java_sources
, 1,
1991 true, source_version_for_javac
,
1992 false, target_version
,
1994 false, false, false, true))
1995 /* javac compiled conftestfail.java successfully, and
1996 "javac -source $source_version_for_javac" rejects it.
1997 So the -source option is useful. */
1998 resultp
->source_option
= true;
2003 resultp
->usable
= true;
2007 /* Try with -target option alone. (Sun javac 1.3.1 has the -target
2008 option but no -source option.) */
2009 unlink (compiled_file_name
);
2011 java_sources
[0] = conftest_file_name
;
2012 if (!compile_using_javac (java_sources
, 1,
2013 false, source_version_for_javac
,
2014 true, target_version
,
2016 false, false, false, true)
2017 && stat (compiled_file_name
, &statbuf
) >= 0
2018 && get_classfile_version (compiled_file_name
)
2019 <= corresponding_classfile_version (target_version
))
2021 /* "javac -target $target_version" compiled conftest.java
2023 /* Try adding -source option if it is useful. */
2024 unlink (compiled_file_name
);
2026 java_sources
[0] = conftest_file_name
;
2027 if (!compile_using_javac (java_sources
, 1,
2028 true, source_version_for_javac
,
2029 true, target_version
,
2031 false, false, false, true)
2032 && stat (compiled_file_name
, &statbuf
) >= 0
2033 && get_classfile_version (compiled_file_name
)
2034 <= corresponding_classfile_version (target_version
))
2036 const char *failcode
= get_failcode_snippet (source_version
);
2038 if (failcode
!= NULL
)
2040 free (compiled_file_name
);
2041 free (conftest_file_name
);
2043 conftest_file_name
=
2044 xconcatenated_filename (tmpdir
->dir_name
,
2045 "conftestfail.java",
2047 if (write_temp_file (tmpdir
, conftest_file_name
,
2050 free (conftest_file_name
);
2051 cleanup_temp_dir (tmpdir
);
2055 compiled_file_name
=
2056 xconcatenated_filename (tmpdir
->dir_name
,
2057 "conftestfail.class",
2059 register_temp_file (tmpdir
, compiled_file_name
);
2061 java_sources
[0] = conftest_file_name
;
2062 if (!compile_using_javac (java_sources
, 1,
2063 false, source_version_for_javac
,
2064 true, target_version
,
2066 false, false, false, true)
2067 && stat (compiled_file_name
, &statbuf
) >= 0)
2069 unlink (compiled_file_name
);
2071 java_sources
[0] = conftest_file_name
;
2072 if (compile_using_javac (java_sources
, 1,
2073 true, source_version_for_javac
,
2074 true, target_version
,
2076 false, false, false, true))
2077 /* "javac -target $target_version" compiled
2078 conftestfail.java successfully, and
2079 "javac -target $target_version -source $source_version_for_javac"
2080 rejects it. So the -source option is useful. */
2081 resultp
->source_option
= true;
2086 resultp
->target_option
= true;
2087 resultp
->usable
= true;
2091 /* Maybe this -target option requires a -source option? Try with
2092 -target and -source options. (Supported by Sun javac 1.4 and
2094 unlink (compiled_file_name
);
2096 java_sources
[0] = conftest_file_name
;
2097 if (!compile_using_javac (java_sources
, 1,
2098 true, source_version_for_javac
,
2099 true, target_version
,
2101 false, false, false, true)
2102 && stat (compiled_file_name
, &statbuf
) >= 0
2103 && get_classfile_version (compiled_file_name
)
2104 <= corresponding_classfile_version (target_version
))
2106 /* "javac -target $target_version -source $source_version_for_javac"
2107 compiled conftest.java successfully. */
2108 resultp
->source_option
= true;
2109 resultp
->target_option
= true;
2110 resultp
->usable
= true;
2115 free (compiled_file_name
);
2116 free (conftest_file_name
);
2118 resultp
->tested
= true;
2121 *usablep
= resultp
->usable
;
2122 *source_option_p
= resultp
->source_option
;
2123 *target_option_p
= resultp
->target_option
;
2128 is_jikes_present (void)
2130 static bool jikes_tested
;
2131 static bool jikes_present
;
2135 /* Test for presence of jikes: "jikes 2> /dev/null ; test $? = 1" */
2141 exitstatus
= execute ("jikes", "jikes", argv
, false, false, true, true,
2143 jikes_present
= (exitstatus
== 0 || exitstatus
== 1);
2144 jikes_tested
= true;
2147 return jikes_present
;
2150 /* ============================= Main function ============================= */
2153 compile_java_class (const char * const *java_sources
,
2154 unsigned int java_sources_count
,
2155 const char * const *classpaths
,
2156 unsigned int classpaths_count
,
2157 const char *source_version
,
2158 const char *target_version
,
2159 const char *directory
,
2160 bool optimize
, bool debug
,
2161 bool use_minimal_classpath
,
2165 char *old_JAVA_HOME
;
2168 const char *javac
= getenv ("JAVAC");
2169 if (javac
!= NULL
&& javac
[0] != '\0')
2171 bool usable
= false;
2172 bool no_assert_option
= false;
2173 bool source_option
= false;
2174 bool target_option
= false;
2175 bool fsource_option
= false;
2176 bool ftarget_option
= false;
2177 const char *source_version_for_javac
;
2179 if (target_version
== NULL
)
2180 target_version
= default_target_version ();
2182 source_version_for_javac
=
2183 get_source_version_for_javac (source_version
, target_version
);
2185 if (is_envjavac_gcj (javac
))
2187 /* It's a version of gcj. */
2188 if (is_envjavac_gcj43 (javac
))
2190 /* It's a version of gcj >= 4.3. Assume the classfile versions
2192 if (is_envjavac_gcj43_usable (javac
,
2193 source_version
, target_version
,
2195 &fsource_option
, &ftarget_option
))
2203 /* It's a version of gcj < 4.3. Ignore the version of the
2204 class files that it creates. */
2205 if (strcmp (target_version
, "1.4") == 0
2206 && strcmp (source_version
, "1.4") == 0)
2208 if (is_envjavac_oldgcj_14_14_usable (javac
, &usable
))
2214 else if (strcmp (target_version
, "1.4") == 0
2215 && strcmp (source_version
, "1.3") == 0)
2217 if (is_envjavac_oldgcj_14_13_usable (javac
,
2229 /* It's not gcj. Assume the classfile versions are correct. */
2230 if (is_envjavac_nongcj_usable (javac
,
2232 source_version_for_javac
,
2235 &source_option
, &target_option
))
2244 char *old_classpath
;
2245 char *javac_with_options
;
2247 /* Set CLASSPATH. */
2249 set_classpath (classpaths
, classpaths_count
, false, verbose
);
2251 javac_with_options
=
2253 ? xasprintf ("%s -fno-assert", javac
)
2254 : xasprintf ("%s%s%s%s%s%s%s%s%s",
2256 source_option
? " -source " : "",
2257 source_option
? source_version_for_javac
: "",
2258 target_option
? " -target " : "",
2259 target_option
? target_version
: "",
2260 fsource_option
? " -fsource=" : "",
2261 fsource_option
? source_version
: "",
2262 ftarget_option
? " -ftarget=" : "",
2263 ftarget_option
? target_version
: ""));
2265 err
= compile_using_envjavac (javac_with_options
,
2266 java_sources
, java_sources_count
,
2267 directory
, optimize
, debug
, verbose
,
2270 free (javac_with_options
);
2272 /* Reset CLASSPATH. */
2273 reset_classpath (old_classpath
);
2280 /* Unset the JAVA_HOME environment variable. */
2281 old_JAVA_HOME
= getenv ("JAVA_HOME");
2282 if (old_JAVA_HOME
!= NULL
)
2284 old_JAVA_HOME
= xstrdup (old_JAVA_HOME
);
2285 unsetenv ("JAVA_HOME");
2288 if (is_gcj_present ())
2290 /* It's a version of gcj. */
2291 bool usable
= false;
2292 bool no_assert_option
= false;
2293 bool fsource_option
= false;
2294 bool ftarget_option
= false;
2296 if (target_version
== NULL
)
2297 target_version
= default_target_version ();
2301 /* It's a version of gcj >= 4.3. Assume the classfile versions
2303 if (is_gcj43_usable (source_version
, target_version
,
2304 &usable
, &fsource_option
, &ftarget_option
))
2312 /* It's a version of gcj < 4.3. Ignore the version of the class
2313 files that it creates.
2314 Test whether it supports the desired target-version and
2316 if (strcmp (target_version
, "1.4") == 0
2317 && strcmp (source_version
, "1.4") == 0)
2319 if (is_oldgcj_14_14_usable (&usable
))
2325 else if (strcmp (target_version
, "1.4") == 0
2326 && strcmp (source_version
, "1.3") == 0)
2328 if (is_oldgcj_14_13_usable (&usable
, &no_assert_option
))
2338 char *old_classpath
;
2340 /* Set CLASSPATH. We could also use the --CLASSPATH=... option
2341 of gcj. Note that --classpath=... option is different: its
2342 argument should also contain gcj's libgcj.jar, but we don't
2343 know its location. */
2345 set_classpath (classpaths
, classpaths_count
, use_minimal_classpath
,
2348 err
= compile_using_gcj (java_sources
, java_sources_count
,
2350 fsource_option
, source_version
,
2351 ftarget_option
, target_version
,
2352 directory
, optimize
, debug
, verbose
, false);
2354 /* Reset CLASSPATH. */
2355 reset_classpath (old_classpath
);
2361 if (is_javac_present ())
2363 bool usable
= false;
2364 bool source_option
= false;
2365 bool target_option
= false;
2366 const char *source_version_for_javac
;
2368 if (target_version
== NULL
)
2369 target_version
= default_target_version ();
2371 source_version_for_javac
=
2372 get_source_version_for_javac (source_version
, target_version
);
2374 if (is_javac_usable (source_version
, source_version_for_javac
,
2376 &usable
, &source_option
, &target_option
))
2384 char *old_classpath
;
2386 /* Set CLASSPATH. We don't use the "-classpath ..." option because
2387 in JDK 1.1.x its argument should also contain the JDK's
2388 classes.zip, but we don't know its location. (In JDK 1.3.0 it
2391 set_classpath (classpaths
, classpaths_count
, use_minimal_classpath
,
2394 err
= compile_using_javac (java_sources
, java_sources_count
,
2395 source_option
, source_version_for_javac
,
2396 target_option
, target_version
,
2397 directory
, optimize
, debug
, verbose
,
2400 /* Reset CLASSPATH. */
2401 reset_classpath (old_classpath
);
2407 if (is_jikes_present ())
2409 /* Test whether it supports the desired target-version and
2411 bool usable
= (strcmp (source_version
, "1.3") == 0);
2415 char *old_classpath
;
2417 /* Set CLASSPATH. We could also use the "-classpath ..." option.
2418 Since jikes doesn't come with its own standard library, it
2419 needs a classes.zip or rt.jar or libgcj.jar in the CLASSPATH.
2420 To increase the chance of success, we reuse the current CLASSPATH
2421 if the user has set it. */
2423 set_classpath (classpaths
, classpaths_count
, false, verbose
);
2425 err
= compile_using_jikes (java_sources
, java_sources_count
,
2426 directory
, optimize
, debug
, verbose
,
2429 /* Reset CLASSPATH. */
2430 reset_classpath (old_classpath
);
2436 error (0, 0, _("Java compiler not found, try installing gcj or set $JAVAC"));
2440 if (old_JAVA_HOME
!= NULL
)
2442 xsetenv ("JAVA_HOME", old_JAVA_HOME
, 1);
2443 free (old_JAVA_HOME
);