1 /* Compile a Java program.
2 Copyright (C) 2001-2003, 2006-2024 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"
53 #define _(str) gettext (str)
56 /* Survey of Java compilers.
58 A = does it work without CLASSPATH being set
59 C = option to set CLASSPATH, other than setting it in the environment
60 O = option for optimizing
61 g = option for debugging
64 Program from A C O g T
66 $JAVAC unknown N n/a -O -g true
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
70 All compilers support the option "-d DIRECTORY" for the base directory
71 of the classes to be written.
73 The CLASSPATH is a colon separated list of pathnames. (On Windows: a
74 semicolon separated list of pathnames.)
76 We try the Java compilers in the following order:
77 1. getenv ("JAVAC"), because the user must be able to override our
79 2. "javac", because it is a standard compiler.
81 We unset the JAVA_HOME environment variable, because a wrong setting of
82 this variable can confuse the JDK's javac.
85 /* Return the default target_version. */
87 default_target_version (void)
89 /* Use a cache. Assumes that the PATH environment variable doesn't change
90 during the lifetime of the program. */
91 static const char *java_version_cache
;
92 if (java_version_cache
== NULL
)
94 /* Determine the version from the found JVM. */
95 java_version_cache
= javaexec_version ();
96 if (java_version_cache
== NULL
)
97 java_version_cache
= "1.6";
98 else if (java_version_cache
[0] == '1'
99 && java_version_cache
[1] == '.'
100 && java_version_cache
[2] >= '1' && java_version_cache
[2] <= '5'
101 && java_version_cache
[3] == '\0')
103 error (0, 0, _("The java program is too old. Cannot compile Java code for this old version any more."));
104 java_version_cache
= "1.6";
106 else if ((java_version_cache
[0] == '1'
107 && java_version_cache
[1] == '.'
108 && java_version_cache
[2] >= '6' && java_version_cache
[2] <= '8'
109 && java_version_cache
[3] == '\0')
110 || (java_version_cache
[0] == '9'
111 && java_version_cache
[1] == '\0')
112 || ((java_version_cache
[0] >= '1'
113 && java_version_cache
[0] <= '9')
114 && (java_version_cache
[1] >= '0'
115 && java_version_cache
[1] <= '9')
116 && java_version_cache
[2] == '\0'))
117 /* Here we could choose any target_version between source_version and
118 the java_version_cache. (If it is too small, it will be incremented
119 below until it works.) Since we documented in javacomp.h that it is
120 determined from the JVM, we do that. */
123 java_version_cache
= "1.6";
125 return java_version_cache
;
128 /* ======================= Source version dependent ======================= */
130 /* Convert a source version to an index. */
131 #define SOURCE_VERSION_BOUND 94 /* 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] >= '6' && source_version
[2] <= '8')
138 && source_version
[3] == '\0')
139 return source_version
[2] - '6';
141 else if (source_version
[0] == '9' && source_version
[1] == '\0')
143 else if ((source_version
[0] >= '1' && source_version
[0] <= '9')
144 && (source_version
[1] >= '0' && source_version
[1] <= '9')
145 && source_version
[2] == '\0')
146 return (source_version
[0] - '1') * 10 + source_version
[1] - '0' + 4;
147 error (EXIT_FAILURE
, 0, _("invalid source_version argument to compile_java_class"));
151 /* ======================= Target version dependent ======================= */
153 /* Convert a target version to an index. */
154 #define TARGET_VERSION_BOUND 94 /* exclusive upper bound */
156 target_version_index (const char *target_version
)
158 if (target_version
[0] == '1' && target_version
[1] == '.'
159 && (target_version
[2] >= '6' && target_version
[2] <= '8')
160 && target_version
[3] == '\0')
161 return target_version
[2] - '6';
162 else if (target_version
[0] == '9' && target_version
[1] == '\0')
164 else if ((target_version
[0] >= '1' && target_version
[0] <= '9')
165 && (target_version
[1] >= '0' && target_version
[1] <= '9')
166 && target_version
[2] == '\0')
167 return (target_version
[0] - '1') * 10 + target_version
[1] - '0' + 4;
168 error (EXIT_FAILURE
, 0, _("invalid target_version argument to compile_java_class"));
172 /* ======================== Compilation subroutines ======================== */
174 /* Try to compile a set of Java sources with $JAVAC.
175 Return a failure indicator (true upon error). */
177 compile_using_envjavac (const char *javac
,
178 const char * const *java_sources
,
179 unsigned int java_sources_count
,
180 const char *directory
,
181 bool optimize
, bool debug
,
182 bool verbose
, bool null_stderr
)
184 /* Because $JAVAC may consist of a command and options, we use the
185 shell. Because $JAVAC has been set by the user, we leave all
186 environment variables in place, including JAVA_HOME, and we don't
187 erase the user's CLASSPATH. */
189 unsigned int command_length
;
196 command_length
= strlen (javac
);
201 if (directory
!= NULL
)
202 command_length
+= 4 + shell_quote_length (directory
);
203 for (i
= 0; i
< java_sources_count
; i
++)
204 command_length
+= 1 + shell_quote_length (java_sources
[i
]);
207 command
= (char *) xmalloca (command_length
);
209 /* Don't shell_quote $JAVAC, because it may consist of a command
211 memcpy (p
, javac
, strlen (javac
));
215 memcpy (p
, " -O", 3);
220 memcpy (p
, " -g", 3);
223 if (directory
!= NULL
)
225 memcpy (p
, " -d ", 4);
227 p
= shell_quote_copy (p
, directory
);
229 for (i
= 0; i
< java_sources_count
; i
++)
232 p
= shell_quote_copy (p
, java_sources
[i
]);
235 /* Ensure command_length was correctly calculated. */
236 if (p
- command
> command_length
)
240 printf ("%s\n", command
);
242 argv
[0] = BOURNE_SHELL
;
246 exitstatus
= execute (javac
, BOURNE_SHELL
, argv
, NULL
, NULL
,
247 false, false, false, null_stderr
,
249 err
= (exitstatus
!= 0);
256 /* Try to compile a set of Java sources with javac.
257 Return a failure indicator (true upon error). */
259 compile_using_javac (const char * const *java_sources
,
260 unsigned int java_sources_count
,
261 const char *nowarn_option
,
262 bool source_option
, const char *source_version
,
263 bool target_option
, const char *target_version
,
264 const char *directory
,
265 bool optimize
, bool debug
,
266 bool verbose
, bool null_stderr
)
276 1 + (nowarn_option
!= NULL
? 1 : 0) + (source_option
? 2 : 0)
277 + (target_option
? 2 : 0) + (optimize
? 1 : 0) + (debug
? 1 : 0)
278 + (directory
!= NULL
? 2 : 0) + java_sources_count
;
279 argv
= (const char **) xmalloca ((argc
+ 1) * sizeof (const char *));
283 if (nowarn_option
!= NULL
)
284 *argp
++ = nowarn_option
;
288 *argp
++ = source_version
;
293 *argp
++ = target_version
;
299 if (directory
!= NULL
)
304 for (i
= 0; i
< java_sources_count
; i
++)
305 *argp
++ = java_sources
[i
];
307 /* Ensure argv length was correctly calculated. */
308 if (argp
- argv
!= argc
)
313 char *command
= shell_quote_argv (argv
);
314 printf ("%s\n", command
);
318 exitstatus
= execute ("javac", "javac", argv
, NULL
, NULL
,
320 null_stderr
, true, true, NULL
);
321 err
= (exitstatus
!= 0);
328 /* ====================== Usability test subroutines ====================== */
330 /* Executes a program.
331 Returns the first line of its output, as a freshly allocated string, or
334 execute_and_read_line (const char *progname
,
335 const char *prog_path
, const char * const *prog_argv
)
345 /* Open a pipe to the program. */
346 child
= create_pipe_in (progname
, prog_path
, prog_argv
, NULL
, NULL
,
347 DEV_NULL
, false, true, false, fd
);
352 /* Retrieve its result. */
353 fp
= fdopen (fd
[0], "r");
355 error (EXIT_FAILURE
, errno
, _("fdopen() failed"));
357 line
= NULL
; linesize
= 0;
358 linelen
= getline (&line
, &linesize
, fp
);
359 if (linelen
== (size_t)(-1))
361 error (0, 0, _("%s subprocess I/O error"), progname
);
364 if (linelen
> 0 && line
[linelen
- 1] == '\n')
365 line
[linelen
- 1] = '\0';
367 /* Read until EOF (otherwise the child process may get a SIGPIPE signal). */
368 while (getc (fp
) != EOF
)
373 /* Remove zombie process from process list, and retrieve exit status. */
375 wait_subprocess (child
, progname
, true, false, true, false, NULL
);
385 /* Executes a program, assumed to be a Java compiler with '-version' option.
386 Returns the version number. */
388 get_compiler_version (const char *progname
,
389 const char *prog_path
, const char * const *prog_argv
)
391 char *line
= execute_and_read_line (progname
, prog_path
, prog_argv
);
395 /* Search the first digit in line. */
396 char *version_start
= line
;
397 for (version_start
= line
; ; version_start
++)
399 if (*version_start
== '\0')
401 /* No digits found. */
405 if (*version_start
>= '0' && *version_start
<= '9')
409 /* Search the end of the version string. */
410 char *version_end
= version_start
;
411 while ((*version_end
>= '0' && *version_end
<= '9') || *version_end
== '.')
415 /* Map 1.6.0_85 to 6, 1.8.0_151 to 8. Map 9.0.4 to 9, 10.0.2 to 10, etc. */
416 if (version_start
[0] == '1' && version_start
[1] == '.')
418 version_end
= strchr (version_start
, '.');
419 if (version_end
!= NULL
)
422 /* Convert number to 'unsigned int'. */
424 switch (strlen (version_start
))
427 result
= version_start
[0] - '0';
431 result
= (version_start
[0] - '0') * 10 + (version_start
[1] - '0');
442 /* Write a given contents to a temporary file.
443 FILE_NAME is the name of a file inside TMPDIR that is known not to exist
445 Return a failure indicator (true upon error). */
447 write_temp_file (struct temp_dir
*tmpdir
, const char *file_name
,
448 const char *contents
)
452 register_temp_file (tmpdir
, file_name
);
453 fp
= fopen_temp (file_name
, "we", false);
456 error (0, errno
, _("failed to create \"%s\""), file_name
);
457 unregister_temp_file (tmpdir
, file_name
);
460 fputs (contents
, fp
);
461 if (fwriteerror_temp (fp
))
463 error (0, errno
, _("error while writing \"%s\" file"), file_name
);
469 /* Return the class file version number of a class file on disk. */
471 get_classfile_version (const char *compiled_file_name
)
473 unsigned char header
[8];
476 /* Open the class file. */
477 fd
= open (compiled_file_name
, O_RDONLY
| O_BINARY
| O_CLOEXEC
, 0);
480 /* Read its first 8 bytes. */
481 if (safe_read (fd
, header
, 8) == 8)
483 /* Verify the class file signature. */
484 if (header
[0] == 0xCA && header
[1] == 0xFE
485 && header
[2] == 0xBA && header
[3] == 0xBE)
494 /* Could not get the class file version. Return a very large one. */
498 /* Test whether $JAVAC can be used, and whether it needs a -source and/or
499 -target option, as well as an option to inhibit warnings.
500 Return a failure indicator (true upon error). */
502 is_envjavac_usable (const char *javac
,
503 const char *source_version
, const char *target_version
,
505 char nowarn_option_out
[17],
506 char source_option_out
[30], char target_option_out
[30])
508 /* The cache depends on the source_version and target_version. */
511 /*bool*/ unsigned int tested
: 1;
512 /*bool*/ unsigned int usable
: 1;
513 /*bool*/ unsigned int nowarn_option
: 1;
514 unsigned int source_option
: 7;
515 unsigned int target_option
: 7;
517 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
518 struct result_t
*resultp
;
520 resultp
= &result_cache
[source_version_index (source_version
)]
521 [target_version_index (target_version
)];
522 if (!resultp
->tested
)
524 /* Canonicalize source_version and target_version, for easier
526 int try_source_version
= 6 + source_version_index (source_version
);
527 int try_target_version
= 6 + target_version_index (target_version
);
529 if (try_source_version
<= try_target_version
)
532 struct temp_dir
*tmpdir
;
533 char *conftest_file_name
;
534 char *compiled_file_name
;
535 const char *java_sources
[1];
536 const char *nowarn_option
;
539 tmpdir
= create_temp_dir ("java", NULL
, false);
544 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
545 if (write_temp_file (tmpdir
, conftest_file_name
, "class conftest {}"))
547 free (conftest_file_name
);
548 cleanup_temp_dir (tmpdir
);
553 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
554 register_temp_file (tmpdir
, compiled_file_name
);
556 /* See the discussion in javacomp.m4. */
557 nowarn_option
= " -Xlint:-options";
558 char *javac_nowarn
= xasprintf ("%s%s", javac
, nowarn_option
);
559 assume (javac_nowarn
!= NULL
);
561 java_sources
[0] = conftest_file_name
;
562 if ((!compile_using_envjavac (javac_nowarn
,
563 java_sources
, 1, tmpdir
->dir_name
,
564 false, false, false, true)
565 && stat (compiled_file_name
, &statbuf
) >= 0)
566 || (nowarn_option
= "",
567 unlink (compiled_file_name
),
568 (!compile_using_envjavac (javac
,
569 java_sources
, 1, tmpdir
->dir_name
,
570 false, false, false, true)
571 && stat (compiled_file_name
, &statbuf
) >= 0)))
573 /* $JAVAC compiled conftest.java successfully. */
574 int compiler_cfversion
=
575 get_classfile_version (compiled_file_name
);
576 int compiler_target_version
= compiler_cfversion
- 44;
578 /* It is hard to determine the compiler_source_version. This
579 would require a list of code snippets that can be compiled only
580 with a specific '-source' option and up, and this list would
581 need to grow every 6 months.
582 Also, $JAVAC may already include a '-source' option.
583 Therefore, pass a '-source' option always. */
584 char source_option
[30];
585 sprintf (source_option
, " -source %s%d",
586 try_source_version
<= 8 ? "1." : "",
589 /* And pass a '-target' option as well, if needed.
590 (All supported javac versions support both, see the table in
592 char target_option
[30];
593 if (try_target_version
== compiler_target_version
)
594 target_option
[0] = '\0';
596 sprintf (target_option
, " -target %s%d",
597 try_target_version
<= 8 ? "1." : "",
600 char *javac_source_target
=
601 xasprintf ("%s%s%s%s", javac
, nowarn_option
,
602 source_option
, target_option
);
603 assume (javac_source_target
!= NULL
);
605 unlink (compiled_file_name
);
607 java_sources
[0] = conftest_file_name
;
608 if (!compile_using_envjavac (javac_source_target
,
609 java_sources
, 1, tmpdir
->dir_name
,
610 false, false, false, true)
611 && stat (compiled_file_name
, &statbuf
) >= 0)
613 /* The compiler directly supports the desired source_version
614 and target_version. Perfect. */
615 free (javac_source_target
);
617 resultp
->nowarn_option
= (nowarn_option
[0] != '\0');
618 resultp
->source_option
= try_source_version
;
619 resultp
->target_option
=
620 (try_target_version
== compiler_target_version
? 0 :
622 resultp
->usable
= true;
626 /* If the desired source_version or target_version were too
627 large for the compiler, there's nothing else we can do. */
628 unsigned int compiler_version
;
630 free (javac_source_target
);
633 size_t command_length
;
637 command_length
= strlen (javac
) + 9 + 1;
639 command
= (char *) xmalloca (command_length
);
642 p
= stpcpy (p
, javac
);
643 p
= stpcpy (p
, " -version");
645 /* Ensure command_length was correctly calculated. */
646 if (p
- command
> command_length
)
650 argv
[0] = BOURNE_SHELL
;
655 get_compiler_version (javac
, BOURNE_SHELL
, argv
);
660 if (try_source_version
<= compiler_version
661 && try_target_version
<= compiler_version
)
663 /* Increase try_source_version and compiler_version until
664 the compiler accepts these values. This is necessary
665 to make e.g. try_source_version = 6 work with Java 12
666 or newer, or try_source_version = 7 work with Java 20
671 try_source_version <= try_target_version. */
672 if (try_source_version
== try_target_version
)
673 try_target_version
++;
674 try_source_version
++;
675 if (try_source_version
> compiler_version
)
678 sprintf (source_option
, " -source %s%d",
679 try_source_version
<= 8 ? "1." : "",
682 if (try_target_version
== compiler_target_version
)
683 target_option
[0] = '\0';
685 sprintf (target_option
, " -target %s%d",
686 try_target_version
<= 8 ? "1." : "",
689 javac_source_target
=
690 xasprintf ("%s%s%s%s", javac
, nowarn_option
,
691 source_option
, target_option
);
692 assume (javac_source_target
!= NULL
);
694 unlink (compiled_file_name
);
696 java_sources
[0] = conftest_file_name
;
697 if (!compile_using_envjavac (javac_source_target
,
702 && stat (compiled_file_name
, &statbuf
) >= 0)
704 /* The compiler supports the try_source_version
705 and try_target_version. It's better than
707 free (javac_source_target
);
709 resultp
->nowarn_option
= (nowarn_option
[0] != '\0');
710 resultp
->source_option
= try_source_version
;
711 resultp
->target_option
=
712 (try_target_version
== compiler_target_version
? 0 :
714 resultp
->usable
= true;
718 free (javac_source_target
);
724 cleanup_temp_dir (tmpdir
);
727 free (compiled_file_name
);
728 free (conftest_file_name
);
731 resultp
->tested
= true;
734 *usablep
= resultp
->usable
;
735 if (resultp
->nowarn_option
)
736 strcpy (nowarn_option_out
, " -Xlint:-options");
738 nowarn_option_out
[0] = '\0';
739 sprintf (source_option_out
, " -source %s%d",
740 resultp
->source_option
<= 8 ? "1." : "",
741 resultp
->source_option
);
742 if (resultp
->target_option
== 0)
743 target_option_out
[0] = '\0';
745 sprintf (target_option_out
, " -target %s%d",
746 resultp
->target_option
<= 8 ? "1." : "",
747 resultp
->target_option
);
752 is_javac_present (void)
754 static bool javac_tested
;
755 static bool javac_present
;
759 /* Test for presence of javac: "javac 2> /dev/null ; test $? -le 2" */
765 exitstatus
= execute ("javac", "javac", argv
, NULL
, NULL
,
766 false, false, true, true,
768 javac_present
= (exitstatus
== 0 || exitstatus
== 1 || exitstatus
== 2);
772 return javac_present
;
775 /* Test whether javac can be used and whether it needs a -source and/or
776 -target option, as well as an option to inhibit warnings.
777 Return a failure indicator (true upon error). */
779 is_javac_usable (const char *source_version
, const char *target_version
,
781 char nowarn_option_out
[17],
782 char source_option_out
[20], char target_option_out
[20])
784 /* The cache depends on the source_version and target_version. */
787 /*bool*/ unsigned int tested
: 1;
788 /*bool*/ unsigned int usable
: 1;
789 /*bool*/ unsigned int nowarn_option
: 1;
790 unsigned int source_option
: 7;
791 unsigned int target_option
: 7;
793 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
794 struct result_t
*resultp
;
796 resultp
= &result_cache
[source_version_index (source_version
)]
797 [target_version_index (target_version
)];
798 if (!resultp
->tested
)
800 /* Canonicalize source_version and target_version, for easier
802 int try_source_version
= 6 + source_version_index (source_version
);
803 int try_target_version
= 6 + target_version_index (target_version
);
805 if (try_source_version
<= try_target_version
)
808 struct temp_dir
*tmpdir
;
809 char *conftest_file_name
;
810 char *compiled_file_name
;
811 const char *java_sources
[1];
812 const char *nowarn_option
;
815 tmpdir
= create_temp_dir ("java", NULL
, false);
820 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
821 if (write_temp_file (tmpdir
, conftest_file_name
, "class conftest {}"))
823 free (conftest_file_name
);
824 cleanup_temp_dir (tmpdir
);
829 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
830 register_temp_file (tmpdir
, compiled_file_name
);
832 /* See the discussion in javacomp.m4. */
833 nowarn_option
= "-Xlint:-options";
835 java_sources
[0] = conftest_file_name
;
836 if ((!compile_using_javac (java_sources
, 1,
838 false, source_version
,
839 false, target_version
,
841 false, false, false, true)
842 && stat (compiled_file_name
, &statbuf
) >= 0)
843 || (nowarn_option
= NULL
,
844 unlink (compiled_file_name
),
845 (!compile_using_javac (java_sources
, 1,
847 false, source_version
,
848 false, target_version
,
850 false, false, false, true)
851 && stat (compiled_file_name
, &statbuf
) >= 0)))
853 /* javac compiled conftest.java successfully. */
854 int compiler_cfversion
=
855 get_classfile_version (compiled_file_name
);
856 int compiler_target_version
= compiler_cfversion
- 44;
858 /* It is hard to determine the compiler_source_version. This
859 would require a list of code snippets that can be compiled only
860 with a specific '-source' option and up, and this list would
861 need to grow every 6 months.
862 Also, javac may point to a shell script that already includes a
864 Therefore, pass a '-source' option always. */
865 char source_option
[20];
866 sprintf (source_option
, "%s%d",
867 try_source_version
<= 8 ? "1." : "",
870 /* And pass a '-target' option as well, if needed.
871 (All supported javac versions support both, see the table in
873 char target_option
[20];
874 sprintf (target_option
, "%s%d",
875 try_target_version
<= 8 ? "1." : "",
878 unlink (compiled_file_name
);
880 java_sources
[0] = conftest_file_name
;
881 if (!compile_using_javac (java_sources
, 1,
885 try_target_version
!= compiler_target_version
,
888 false, false, false, true)
889 && stat (compiled_file_name
, &statbuf
) >= 0)
891 /* The compiler directly supports the desired source_version
892 and target_version. Perfect. */
893 resultp
->nowarn_option
= (nowarn_option
!= NULL
);
894 resultp
->source_option
= try_source_version
;
895 resultp
->target_option
=
896 (try_target_version
== compiler_target_version
? 0 :
898 resultp
->usable
= true;
902 /* If the desired source_version or target_version were too
903 large for the compiler, there's nothing else we can do. */
904 unsigned int compiler_version
;
910 argv
[1] = "-version";
913 get_compiler_version ("javac", argv
[0], argv
);
916 if (try_source_version
<= compiler_version
917 && try_target_version
<= compiler_version
)
919 /* Increase try_source_version and compiler_version until
920 the compiler accepts these values. This is necessary
921 to make e.g. try_source_version = 6 work with Java 12
922 or newer, or try_source_version = 7 work with Java 20
927 try_source_version <= try_target_version. */
928 if (try_source_version
== try_target_version
)
929 try_target_version
++;
930 try_source_version
++;
931 if (try_source_version
> compiler_version
)
934 sprintf (source_option
, "%s%d",
935 try_source_version
<= 8 ? "1." : "",
938 sprintf (target_option
, "%s%d",
939 try_target_version
<= 8 ? "1." : "",
942 unlink (compiled_file_name
);
944 java_sources
[0] = conftest_file_name
;
945 if (!compile_using_javac (java_sources
, 1,
949 try_target_version
!= compiler_target_version
,
952 false, false, false, true)
953 && stat (compiled_file_name
, &statbuf
) >= 0)
955 /* The compiler supports the try_source_version
956 and try_target_version. It's better than
958 resultp
->nowarn_option
= (nowarn_option
!= NULL
);
959 resultp
->source_option
= try_source_version
;
960 resultp
->target_option
=
961 (try_target_version
== compiler_target_version
? 0 :
963 resultp
->usable
= true;
971 cleanup_temp_dir (tmpdir
);
973 free (compiled_file_name
);
974 free (conftest_file_name
);
977 resultp
->tested
= true;
980 *usablep
= resultp
->usable
;
981 if (resultp
->nowarn_option
)
982 strcpy (nowarn_option_out
, "-Xlint:-options");
984 nowarn_option_out
[0] = '\0';
985 sprintf (source_option_out
, "%s%d",
986 resultp
->source_option
<= 8 ? "1." : "",
987 resultp
->source_option
);
988 if (resultp
->target_option
== 0)
989 target_option_out
[0] = '\0';
991 sprintf (target_option_out
, "%s%d",
992 resultp
->target_option
<= 8 ? "1." : "",
993 resultp
->target_option
);
997 /* ============================= Main function ============================= */
1000 compile_java_class (const char * const *java_sources
,
1001 unsigned int java_sources_count
,
1002 const char * const *classpaths
,
1003 unsigned int classpaths_count
,
1004 const char *source_version
,
1005 const char *target_version
,
1006 const char *directory
,
1007 bool optimize
, bool debug
,
1008 bool use_minimal_classpath
,
1012 char *old_JAVA_HOME
;
1014 /* Map source_version 1.1 ... 1.5 to 1.6. */
1015 if (source_version
[0] == '1' && source_version
[1] == '.'
1016 && (source_version
[2] >= '1' && source_version
[2] <= '5')
1017 && source_version
[3] == '\0')
1018 source_version
= "1.6";
1020 /* Map target_version 1.1 ... 1.5 to 1.6. */
1021 if (target_version
!= NULL
1022 && target_version
[0] == '1' && target_version
[1] == '.'
1023 && (target_version
[2] >= '1' && target_version
[2] <= '5')
1024 && target_version
[3] == '\0')
1025 target_version
= "1.6";
1028 const char *javac
= getenv ("JAVAC");
1029 if (javac
!= NULL
&& javac
[0] != '\0')
1031 bool usable
= false;
1032 char nowarn_option
[17];
1033 char source_option
[30];
1034 char target_option
[30];
1036 if (target_version
== NULL
)
1037 target_version
= default_target_version ();
1039 if (is_envjavac_usable (javac
,
1040 source_version
, target_version
,
1043 source_option
, target_option
))
1051 char *old_classpath
;
1052 char *javac_with_options
;
1054 /* Set CLASSPATH. */
1056 set_classpath (classpaths
, classpaths_count
, false, verbose
);
1058 javac_with_options
=
1059 xasprintf ("%s%s%s%s", javac
,
1060 nowarn_option
, source_option
, target_option
);
1061 assume (javac_with_options
!= NULL
);
1063 err
= compile_using_envjavac (javac_with_options
,
1064 java_sources
, java_sources_count
,
1065 directory
, optimize
, debug
, verbose
,
1068 free (javac_with_options
);
1070 /* Reset CLASSPATH. */
1071 reset_classpath (old_classpath
);
1078 /* Unset the JAVA_HOME environment variable. */
1079 old_JAVA_HOME
= getenv ("JAVA_HOME");
1080 if (old_JAVA_HOME
!= NULL
)
1082 old_JAVA_HOME
= xstrdup (old_JAVA_HOME
);
1083 unsetenv ("JAVA_HOME");
1086 if (is_javac_present ())
1088 bool usable
= false;
1089 char nowarn_option
[17];
1090 char source_option
[20];
1091 char target_option
[20];
1093 if (target_version
== NULL
)
1094 target_version
= default_target_version ();
1096 if (is_javac_usable (source_version
, target_version
,
1099 source_option
, target_option
))
1107 char *old_classpath
;
1109 /* Set CLASSPATH. We don't use the "-classpath ..." option because
1110 in JDK 1.1.x its argument should also contain the JDK's
1111 classes.zip, but we don't know its location. (In JDK 1.3.0 it
1114 set_classpath (classpaths
, classpaths_count
, use_minimal_classpath
,
1117 err
= compile_using_javac (java_sources
, java_sources_count
,
1118 nowarn_option
[0] != '\0' ? nowarn_option
: NULL
,
1119 true, source_option
,
1120 target_option
[0] != '\0', target_option
,
1121 directory
, optimize
, debug
, verbose
,
1124 /* Reset CLASSPATH. */
1125 reset_classpath (old_classpath
);
1131 error (0, 0, _("Java compiler not found, try setting $JAVAC"));
1135 if (old_JAVA_HOME
!= NULL
)
1137 xsetenv ("JAVA_HOME", old_JAVA_HOME
, 1);
1138 free (old_JAVA_HOME
);