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
,
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
,
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
,
347 DEV_NULL
, false, true, false, fd
);
352 /* Retrieve its result. */
353 fp
= fdopen (fd
[0], "r");
356 error (0, errno
, _("fdopen() failed"));
360 line
= NULL
; linesize
= 0;
361 linelen
= getline (&line
, &linesize
, fp
);
362 if (linelen
== (size_t)(-1))
364 error (0, 0, _("%s subprocess I/O error"), progname
);
367 if (linelen
> 0 && line
[linelen
- 1] == '\n')
368 line
[linelen
- 1] = '\0';
370 /* Read until EOF (otherwise the child process may get a SIGPIPE signal). */
371 while (getc (fp
) != EOF
)
376 /* Remove zombie process from process list, and retrieve exit status. */
378 wait_subprocess (child
, progname
, true, false, true, false, NULL
);
388 /* Executes a program, assumed to be a Java compiler with '-version' option.
389 Returns the version number. */
391 get_compiler_version (const char *progname
,
392 const char *prog_path
, const char * const *prog_argv
)
394 char *line
= execute_and_read_line (progname
, prog_path
, prog_argv
);
398 /* Search the first digit in line. */
399 char *version_start
= line
;
400 for (version_start
= line
; ; version_start
++)
402 if (*version_start
== '\0')
404 /* No digits found. */
408 if (*version_start
>= '0' && *version_start
<= '9')
412 /* Search the end of the version string. */
413 char *version_end
= version_start
;
414 while ((*version_end
>= '0' && *version_end
<= '9') || *version_end
== '.')
418 /* 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. */
419 if (version_start
[0] == '1' && version_start
[1] == '.')
421 version_end
= strchr (version_start
, '.');
422 if (version_end
!= NULL
)
425 /* Convert number to 'unsigned int'. */
427 switch (strlen (version_start
))
430 result
= version_start
[0] - '0';
434 result
= (version_start
[0] - '0') * 10 + (version_start
[1] - '0');
445 /* Write a given contents to a temporary file.
446 FILE_NAME is the name of a file inside TMPDIR that is known not to exist
448 Return a failure indicator (true upon error). */
450 write_temp_file (struct temp_dir
*tmpdir
, const char *file_name
,
451 const char *contents
)
455 register_temp_file (tmpdir
, file_name
);
456 fp
= fopen_temp (file_name
, "we", false);
459 error (0, errno
, _("failed to create \"%s\""), file_name
);
460 unregister_temp_file (tmpdir
, file_name
);
463 fputs (contents
, fp
);
464 if (fwriteerror_temp (fp
))
466 error (0, errno
, _("error while writing \"%s\" file"), file_name
);
472 /* Return the class file version number of a class file on disk. */
474 get_classfile_version (const char *compiled_file_name
)
476 unsigned char header
[8];
479 /* Open the class file. */
480 fd
= open (compiled_file_name
, O_RDONLY
| O_BINARY
| O_CLOEXEC
, 0);
483 /* Read its first 8 bytes. */
484 if (safe_read (fd
, header
, 8) == 8)
486 /* Verify the class file signature. */
487 if (header
[0] == 0xCA && header
[1] == 0xFE
488 && header
[2] == 0xBA && header
[3] == 0xBE)
497 /* Could not get the class file version. Return a very large one. */
501 /* Test whether $JAVAC can be used, and whether it needs a -source and/or
502 -target option, as well as an option to inhibit warnings.
503 Return a failure indicator (true upon error). */
505 is_envjavac_usable (const char *javac
,
506 const char *source_version
, const char *target_version
,
508 char nowarn_option_out
[17],
509 char source_option_out
[30], char target_option_out
[30])
511 /* The cache depends on the source_version and target_version. */
514 /*bool*/ unsigned int tested
: 1;
515 /*bool*/ unsigned int usable
: 1;
516 /*bool*/ unsigned int nowarn_option
: 1;
517 unsigned int source_option
: 7;
518 unsigned int target_option
: 7;
520 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
521 struct result_t
*resultp
;
523 resultp
= &result_cache
[source_version_index (source_version
)]
524 [target_version_index (target_version
)];
525 if (!resultp
->tested
)
527 /* Canonicalize source_version and target_version, for easier
529 int try_source_version
= 6 + source_version_index (source_version
);
530 int try_target_version
= 6 + target_version_index (target_version
);
532 if (try_source_version
<= try_target_version
)
535 struct temp_dir
*tmpdir
;
536 char *conftest_file_name
;
537 char *compiled_file_name
;
538 const char *java_sources
[1];
539 const char *nowarn_option
;
542 tmpdir
= create_temp_dir ("java", NULL
, false);
547 xconcatenated_filename (tmpdir
->dir_name
, "conftest.java", NULL
);
548 if (write_temp_file (tmpdir
, conftest_file_name
, "class conftest {}"))
550 free (conftest_file_name
);
551 cleanup_temp_dir (tmpdir
);
556 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
557 register_temp_file (tmpdir
, compiled_file_name
);
559 /* See the discussion in javacomp.m4. */
560 nowarn_option
= " -Xlint:-options";
561 char *javac_nowarn
= xasprintf ("%s%s", javac
, nowarn_option
);
562 assume (javac_nowarn
!= NULL
);
564 java_sources
[0] = conftest_file_name
;
565 if ((!compile_using_envjavac (javac_nowarn
,
566 java_sources
, 1, tmpdir
->dir_name
,
567 false, false, false, true)
568 && stat (compiled_file_name
, &statbuf
) >= 0)
569 || (nowarn_option
= "",
570 unlink (compiled_file_name
),
571 (!compile_using_envjavac (javac
,
572 java_sources
, 1, tmpdir
->dir_name
,
573 false, false, false, true)
574 && stat (compiled_file_name
, &statbuf
) >= 0)))
576 /* $JAVAC compiled conftest.java successfully. */
577 int compiler_cfversion
=
578 get_classfile_version (compiled_file_name
);
579 int compiler_target_version
= compiler_cfversion
- 44;
581 /* It is hard to determine the compiler_source_version. This
582 would require a list of code snippets that can be compiled only
583 with a specific '-source' option and up, and this list would
584 need to grow every 6 months.
585 Also, $JAVAC may already include a '-source' option.
586 Therefore, pass a '-source' option always. */
587 char source_option
[30];
588 sprintf (source_option
, " -source %s%d",
589 try_source_version
<= 8 ? "1." : "",
592 /* And pass a '-target' option as well, if needed.
593 (All supported javac versions support both, see the table in
595 char target_option
[30];
596 if (try_target_version
== compiler_target_version
)
597 target_option
[0] = '\0';
599 sprintf (target_option
, " -target %s%d",
600 try_target_version
<= 8 ? "1." : "",
603 char *javac_source_target
=
604 xasprintf ("%s%s%s%s", javac
, nowarn_option
,
605 source_option
, target_option
);
606 assume (javac_source_target
!= NULL
);
608 unlink (compiled_file_name
);
610 java_sources
[0] = conftest_file_name
;
611 if (!compile_using_envjavac (javac_source_target
,
612 java_sources
, 1, tmpdir
->dir_name
,
613 false, false, false, true)
614 && stat (compiled_file_name
, &statbuf
) >= 0)
616 /* The compiler directly supports the desired source_version
617 and target_version. Perfect. */
618 free (javac_source_target
);
620 resultp
->nowarn_option
= (nowarn_option
[0] != '\0');
621 resultp
->source_option
= try_source_version
;
622 resultp
->target_option
=
623 (try_target_version
== compiler_target_version
? 0 :
625 resultp
->usable
= true;
629 /* If the desired source_version or target_version were too
630 large for the compiler, there's nothing else we can do. */
631 unsigned int compiler_version
;
633 free (javac_source_target
);
636 size_t command_length
;
640 command_length
= strlen (javac
) + 9 + 1;
642 command
= (char *) xmalloca (command_length
);
645 p
= stpcpy (p
, javac
);
646 p
= stpcpy (p
, " -version");
648 /* Ensure command_length was correctly calculated. */
649 if (p
- command
> command_length
)
653 argv
[0] = BOURNE_SHELL
;
658 get_compiler_version (javac
, BOURNE_SHELL
, argv
);
663 if (try_source_version
<= compiler_version
664 && try_target_version
<= compiler_version
)
666 /* Increase try_source_version and compiler_version until
667 the compiler accepts these values. This is necessary
668 to make e.g. try_source_version = 6 work with Java 12
669 or newer, or try_source_version = 7 work with Java 20
674 try_source_version <= try_target_version. */
675 if (try_source_version
== try_target_version
)
676 try_target_version
++;
677 try_source_version
++;
678 if (try_source_version
> compiler_version
)
681 sprintf (source_option
, " -source %s%d",
682 try_source_version
<= 8 ? "1." : "",
685 if (try_target_version
== compiler_target_version
)
686 target_option
[0] = '\0';
688 sprintf (target_option
, " -target %s%d",
689 try_target_version
<= 8 ? "1." : "",
692 javac_source_target
=
693 xasprintf ("%s%s%s%s", javac
, nowarn_option
,
694 source_option
, target_option
);
695 assume (javac_source_target
!= NULL
);
697 unlink (compiled_file_name
);
699 java_sources
[0] = conftest_file_name
;
700 if (!compile_using_envjavac (javac_source_target
,
705 && stat (compiled_file_name
, &statbuf
) >= 0)
707 /* The compiler supports the try_source_version
708 and try_target_version. It's better than
710 free (javac_source_target
);
712 resultp
->nowarn_option
= (nowarn_option
[0] != '\0');
713 resultp
->source_option
= try_source_version
;
714 resultp
->target_option
=
715 (try_target_version
== compiler_target_version
? 0 :
717 resultp
->usable
= true;
721 free (javac_source_target
);
727 cleanup_temp_dir (tmpdir
);
730 free (compiled_file_name
);
731 free (conftest_file_name
);
734 resultp
->tested
= true;
737 *usablep
= resultp
->usable
;
738 if (resultp
->nowarn_option
)
739 strcpy (nowarn_option_out
, " -Xlint:-options");
741 nowarn_option_out
[0] = '\0';
742 sprintf (source_option_out
, " -source %s%d",
743 resultp
->source_option
<= 8 ? "1." : "",
744 resultp
->source_option
);
745 if (resultp
->target_option
== 0)
746 target_option_out
[0] = '\0';
748 sprintf (target_option_out
, " -target %s%d",
749 resultp
->target_option
<= 8 ? "1." : "",
750 resultp
->target_option
);
755 is_javac_present (void)
757 static bool javac_tested
;
758 static bool javac_present
;
762 /* Test for presence of javac: "javac 2> /dev/null ; test $? -le 2" */
768 exitstatus
= execute ("javac", "javac", argv
, NULL
,
769 false, false, true, true,
771 javac_present
= (exitstatus
== 0 || exitstatus
== 1 || exitstatus
== 2);
775 return javac_present
;
778 /* Test whether javac can be used and whether it needs a -source and/or
779 -target option, as well as an option to inhibit warnings.
780 Return a failure indicator (true upon error). */
782 is_javac_usable (const char *source_version
, const char *target_version
,
784 char nowarn_option_out
[17],
785 char source_option_out
[20], char target_option_out
[20])
787 /* The cache depends on the source_version and target_version. */
790 /*bool*/ unsigned int tested
: 1;
791 /*bool*/ unsigned int usable
: 1;
792 /*bool*/ unsigned int nowarn_option
: 1;
793 unsigned int source_option
: 7;
794 unsigned int target_option
: 7;
796 static struct result_t result_cache
[SOURCE_VERSION_BOUND
][TARGET_VERSION_BOUND
];
797 struct result_t
*resultp
;
799 resultp
= &result_cache
[source_version_index (source_version
)]
800 [target_version_index (target_version
)];
801 if (!resultp
->tested
)
803 /* Canonicalize source_version and target_version, for easier
805 int try_source_version
= 6 + source_version_index (source_version
);
806 int try_target_version
= 6 + target_version_index (target_version
);
808 if (try_source_version
<= try_target_version
)
811 struct temp_dir
*tmpdir
;
812 char *conftest_file_name
;
813 char *compiled_file_name
;
814 const char *java_sources
[1];
815 const char *nowarn_option
;
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
, "class conftest {}"))
826 free (conftest_file_name
);
827 cleanup_temp_dir (tmpdir
);
832 xconcatenated_filename (tmpdir
->dir_name
, "conftest.class", NULL
);
833 register_temp_file (tmpdir
, compiled_file_name
);
835 /* See the discussion in javacomp.m4. */
836 nowarn_option
= "-Xlint:-options";
838 java_sources
[0] = conftest_file_name
;
839 if ((!compile_using_javac (java_sources
, 1,
841 false, source_version
,
842 false, target_version
,
844 false, false, false, true)
845 && stat (compiled_file_name
, &statbuf
) >= 0)
846 || (nowarn_option
= NULL
,
847 unlink (compiled_file_name
),
848 (!compile_using_javac (java_sources
, 1,
850 false, source_version
,
851 false, target_version
,
853 false, false, false, true)
854 && stat (compiled_file_name
, &statbuf
) >= 0)))
856 /* javac compiled conftest.java successfully. */
857 int compiler_cfversion
=
858 get_classfile_version (compiled_file_name
);
859 int compiler_target_version
= compiler_cfversion
- 44;
861 /* It is hard to determine the compiler_source_version. This
862 would require a list of code snippets that can be compiled only
863 with a specific '-source' option and up, and this list would
864 need to grow every 6 months.
865 Also, javac may point to a shell script that already includes a
867 Therefore, pass a '-source' option always. */
868 char source_option
[20];
869 sprintf (source_option
, "%s%d",
870 try_source_version
<= 8 ? "1." : "",
873 /* And pass a '-target' option as well, if needed.
874 (All supported javac versions support both, see the table in
876 char target_option
[20];
877 sprintf (target_option
, "%s%d",
878 try_target_version
<= 8 ? "1." : "",
881 unlink (compiled_file_name
);
883 java_sources
[0] = conftest_file_name
;
884 if (!compile_using_javac (java_sources
, 1,
888 try_target_version
!= compiler_target_version
,
891 false, false, false, true)
892 && stat (compiled_file_name
, &statbuf
) >= 0)
894 /* The compiler directly supports the desired source_version
895 and target_version. Perfect. */
896 resultp
->nowarn_option
= (nowarn_option
!= NULL
);
897 resultp
->source_option
= try_source_version
;
898 resultp
->target_option
=
899 (try_target_version
== compiler_target_version
? 0 :
901 resultp
->usable
= true;
905 /* If the desired source_version or target_version were too
906 large for the compiler, there's nothing else we can do. */
907 unsigned int compiler_version
;
913 argv
[1] = "-version";
916 get_compiler_version ("javac", argv
[0], argv
);
919 if (try_source_version
<= compiler_version
920 && try_target_version
<= compiler_version
)
922 /* Increase try_source_version and compiler_version until
923 the compiler accepts these values. This is necessary
924 to make e.g. try_source_version = 6 work with Java 12
925 or newer, or try_source_version = 7 work with Java 20
930 try_source_version <= try_target_version. */
931 if (try_source_version
== try_target_version
)
932 try_target_version
++;
933 try_source_version
++;
934 if (try_source_version
> compiler_version
)
937 sprintf (source_option
, "%s%d",
938 try_source_version
<= 8 ? "1." : "",
941 sprintf (target_option
, "%s%d",
942 try_target_version
<= 8 ? "1." : "",
945 unlink (compiled_file_name
);
947 java_sources
[0] = conftest_file_name
;
948 if (!compile_using_javac (java_sources
, 1,
952 try_target_version
!= compiler_target_version
,
955 false, false, false, true)
956 && stat (compiled_file_name
, &statbuf
) >= 0)
958 /* The compiler supports the try_source_version
959 and try_target_version. It's better than
961 resultp
->nowarn_option
= (nowarn_option
!= NULL
);
962 resultp
->source_option
= try_source_version
;
963 resultp
->target_option
=
964 (try_target_version
== compiler_target_version
? 0 :
966 resultp
->usable
= true;
974 cleanup_temp_dir (tmpdir
);
976 free (compiled_file_name
);
977 free (conftest_file_name
);
980 resultp
->tested
= true;
983 *usablep
= resultp
->usable
;
984 if (resultp
->nowarn_option
)
985 strcpy (nowarn_option_out
, "-Xlint:-options");
987 nowarn_option_out
[0] = '\0';
988 sprintf (source_option_out
, "%s%d",
989 resultp
->source_option
<= 8 ? "1." : "",
990 resultp
->source_option
);
991 if (resultp
->target_option
== 0)
992 target_option_out
[0] = '\0';
994 sprintf (target_option_out
, "%s%d",
995 resultp
->target_option
<= 8 ? "1." : "",
996 resultp
->target_option
);
1000 /* ============================= Main function ============================= */
1003 compile_java_class (const char * const *java_sources
,
1004 unsigned int java_sources_count
,
1005 const char * const *classpaths
,
1006 unsigned int classpaths_count
,
1007 const char *source_version
,
1008 const char *target_version
,
1009 const char *directory
,
1010 bool optimize
, bool debug
,
1011 bool use_minimal_classpath
,
1015 char *old_JAVA_HOME
;
1017 /* Map source_version 1.1 ... 1.5 to 1.6. */
1018 if (source_version
[0] == '1' && source_version
[1] == '.'
1019 && (source_version
[2] >= '1' && source_version
[2] <= '5')
1020 && source_version
[3] == '\0')
1021 source_version
= "1.6";
1023 /* Map target_version 1.1 ... 1.5 to 1.6. */
1024 if (target_version
!= NULL
1025 && target_version
[0] == '1' && target_version
[1] == '.'
1026 && (target_version
[2] >= '1' && target_version
[2] <= '5')
1027 && target_version
[3] == '\0')
1028 target_version
= "1.6";
1031 const char *javac
= getenv ("JAVAC");
1032 if (javac
!= NULL
&& javac
[0] != '\0')
1034 bool usable
= false;
1035 char nowarn_option
[17];
1036 char source_option
[30];
1037 char target_option
[30];
1039 if (target_version
== NULL
)
1040 target_version
= default_target_version ();
1042 if (is_envjavac_usable (javac
,
1043 source_version
, target_version
,
1046 source_option
, target_option
))
1054 char *old_classpath
;
1055 char *javac_with_options
;
1057 /* Set CLASSPATH. */
1059 set_classpath (classpaths
, classpaths_count
, false, verbose
);
1061 javac_with_options
=
1062 xasprintf ("%s%s%s%s", javac
,
1063 nowarn_option
, source_option
, target_option
);
1064 assume (javac_with_options
!= NULL
);
1066 err
= compile_using_envjavac (javac_with_options
,
1067 java_sources
, java_sources_count
,
1068 directory
, optimize
, debug
, verbose
,
1071 free (javac_with_options
);
1073 /* Reset CLASSPATH. */
1074 reset_classpath (old_classpath
);
1081 /* Unset the JAVA_HOME environment variable. */
1082 old_JAVA_HOME
= getenv ("JAVA_HOME");
1083 if (old_JAVA_HOME
!= NULL
)
1085 old_JAVA_HOME
= xstrdup (old_JAVA_HOME
);
1086 unsetenv ("JAVA_HOME");
1089 if (is_javac_present ())
1091 bool usable
= false;
1092 char nowarn_option
[17];
1093 char source_option
[20];
1094 char target_option
[20];
1096 if (target_version
== NULL
)
1097 target_version
= default_target_version ();
1099 if (is_javac_usable (source_version
, target_version
,
1102 source_option
, target_option
))
1110 char *old_classpath
;
1112 /* Set CLASSPATH. We don't use the "-classpath ..." option because
1113 in JDK 1.1.x its argument should also contain the JDK's
1114 classes.zip, but we don't know its location. (In JDK 1.3.0 it
1117 set_classpath (classpaths
, classpaths_count
, use_minimal_classpath
,
1120 err
= compile_using_javac (java_sources
, java_sources_count
,
1121 nowarn_option
[0] != '\0' ? nowarn_option
: NULL
,
1122 true, source_option
,
1123 target_option
[0] != '\0', target_option
,
1124 directory
, optimize
, debug
, verbose
,
1127 /* Reset CLASSPATH. */
1128 reset_classpath (old_classpath
);
1134 error (0, 0, _("Java compiler not found, try setting $JAVAC"));
1138 if (old_JAVA_HOME
!= NULL
)
1140 xsetenv ("JAVA_HOME", old_JAVA_HOME
, 1);
1141 free (old_JAVA_HOME
);