From 2d3dd35cb263f6566b2924a2adae99385c440f46 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 24 Mar 2018 12:54:42 +0100 Subject: [PATCH] javacomp-script, javacomp: Fix support for Java 7, 8, 9. * lib/javaversion.h: Update comments. * lib/javacomp.h: Likewise. * lib/javacomp.c (default_target_version, source_version_index, get_goodcode_snippet, get_failcode_snippet): Recognize "9" instead of "1.9". (TARGET_VERSION_BOUND): Bump to 9. (target_version_index, corresponding_classfile_version): Recognize "9" instead of "1.9". (get_source_version_for_javac): New function. (is_envjavac_nongcj_usable, is_javac_usable): Add source_version_for_javac argument. (compile_java_class): Determine and pass source_version_for_javac. * m4/javacomp.m4: Recognize version '9' instead of '1.9'. When invoking $JAVAC or javac, pass '-source 1.6' instead of '-source 1.5' when appropriate. --- ChangeLog | 19 +++++++++ lib/javacomp.c | 105 +++++++++++++++++++++++++++++++--------------- lib/javacomp.h | 6 +-- lib/javaversion.h | 4 +- m4/javacomp.m4 | 47 +++++++++++++++------ 5 files changed, 129 insertions(+), 52 deletions(-) diff --git a/ChangeLog b/ChangeLog index 20cd7cd53d..ed98b4ff58 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2018-03-24 Bruno Haible + + javacomp-script, javacomp: Fix support for Java 7, 8, 9. + * lib/javaversion.h: Update comments. + * lib/javacomp.h: Likewise. + * lib/javacomp.c (default_target_version, source_version_index, + get_goodcode_snippet, get_failcode_snippet): Recognize "9" instead of + "1.9". + (TARGET_VERSION_BOUND): Bump to 9. + (target_version_index, corresponding_classfile_version): Recognize "9" + instead of "1.9". + (get_source_version_for_javac): New function. + (is_envjavac_nongcj_usable, is_javac_usable): Add + source_version_for_javac argument. + (compile_java_class): Determine and pass source_version_for_javac. + * m4/javacomp.m4: Recognize version '9' instead of '1.9'. When invoking + $JAVAC or javac, pass '-source 1.6' instead of '-source 1.5' when + appropriate. + 2018-03-23 Jim Meyering test-version-etc.sh: port to diff without -c diff --git a/lib/javacomp.c b/lib/javacomp.c index f9e7292d0c..1b19f17126 100644 --- a/lib/javacomp.c +++ b/lib/javacomp.c @@ -99,9 +99,12 @@ default_target_version (void) /* Determine the version from the found JVM. */ java_version_cache = javaexec_version (); if (java_version_cache == NULL - || !(java_version_cache[0] == '1' && java_version_cache[1] == '.' - && (java_version_cache[2] >= '1' && java_version_cache[2] <= '9') - && java_version_cache[3] == '\0')) + || !((java_version_cache[0] == '1' + && java_version_cache[1] == '.' + && java_version_cache[2] >= '1' && java_version_cache[2] <= '8' + && java_version_cache[3] == '\0') + || (java_version_cache[0] == '9' + && java_version_cache[1] == '\0'))) java_version_cache = "1.1"; } return java_version_cache; @@ -119,10 +122,12 @@ source_version_index (const char *source_version) if ((source_version[2] >= '3' && source_version[2] <= '5') && source_version[3] == '\0') return source_version[2] - '3'; - if ((source_version[2] >= '7' && source_version[2] <= '9') + if ((source_version[2] >= '7' && source_version[2] <= '8') && source_version[3] == '\0') return source_version[2] - '4'; } + else if (source_version[0] == '9' && source_version[1] == '\0') + return 5; error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class")); return 0; } @@ -141,7 +146,7 @@ get_goodcode_snippet (const char *source_version) return "class conftest { void foo () { switch (\"A\") {} } }\n"; if (strcmp (source_version, "1.8") == 0) return "class conftest { void foo () { Runnable r = () -> {}; } }\n"; - if (strcmp (source_version, "1.9") == 0) + if (strcmp (source_version, "9") == 0) return "interface conftest { private void foo () {} }\n"; error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class")); return NULL; @@ -163,7 +168,7 @@ get_failcode_snippet (const char *source_version) return "class conftestfail { void foo () { Runnable r = () -> {}; } }\n"; if (strcmp (source_version, "1.8") == 0) return "interface conftestfail { private void foo () {} }\n"; - if (strcmp (source_version, "1.9") == 0) + if (strcmp (source_version, "9") == 0) return NULL; error (EXIT_FAILURE, 0, _("invalid source_version argument to compile_java_class")); return NULL; @@ -172,14 +177,16 @@ get_failcode_snippet (const char *source_version) /* ======================= Target version dependent ======================= */ /* Convert a target version to an index. */ -#define TARGET_VERSION_BOUND 6 /* exclusive upper bound */ +#define TARGET_VERSION_BOUND 9 /* exclusive upper bound */ static unsigned int target_version_index (const char *target_version) { if (target_version[0] == '1' && target_version[1] == '.' - && (target_version[2] >= '1' && target_version[2] <= '6') + && (target_version[2] >= '1' && target_version[2] <= '8') && target_version[3] == '\0') return target_version[2] - '1'; + else if (target_version[0] == '9' && target_version[1] == '\0') + return 8; error (EXIT_FAILURE, 0, _("invalid target_version argument to compile_java_class")); return 0; } @@ -205,12 +212,28 @@ corresponding_classfile_version (const char *target_version) return 51; if (strcmp (target_version, "1.8") == 0) return 52; - if (strcmp (target_version, "1.9") == 0) + if (strcmp (target_version, "9") == 0) return 53; error (EXIT_FAILURE, 0, _("invalid target_version argument to compile_java_class")); return 0; } +/* Return the source version to pass to javac. */ +static const char * +get_source_version_for_javac (const char *source_version, + const char *target_version) +{ + /* The javac option '-source 1.5' has the same meaning as '-source 1.6', + but since Java 9 supports only the latter, prefer the latter if a + target_version >= 1.6 is requested. */ + if (strcmp (source_version, "1.5") == 0 + && !(target_version[0] == '1' && target_version[1] == '.' + && (target_version[2] >= '1' && target_version[2] <= '5') + && target_version[3] == '\0')) + return "1.6"; + return source_version; +} + /* ======================== Compilation subroutines ======================== */ /* Try to compile a set of Java sources with $JAVAC. @@ -1081,6 +1104,7 @@ is_envjavac_oldgcj_14_13_usable (const char *javac, static bool is_envjavac_nongcj_usable (const char *javac, const char *source_version, + const char *source_version_for_javac, const char *target_version, bool *usablep, bool *source_option_p, bool *target_option_p) @@ -1136,7 +1160,7 @@ is_envjavac_nongcj_usable (const char *javac, /* $JAVAC compiled conftest.java successfully. */ /* Try adding -source option if it is useful. */ char *javac_source = - xasprintf ("%s -source %s", javac, source_version); + xasprintf ("%s -source %s", javac, source_version_for_javac); unlink (compiled_file_name); @@ -1188,8 +1212,8 @@ is_envjavac_nongcj_usable (const char *javac, tmpdir->dir_name, false, false, false, true)) /* $JAVAC compiled conftestfail.java successfully, and - "$JAVAC -source $source_version" rejects it. So the - -source option is useful. */ + "$JAVAC -source $source_version_for_javac" rejects it. + So the -source option is useful. */ resultp->source_option = true; } } @@ -1220,7 +1244,7 @@ is_envjavac_nongcj_usable (const char *javac, successfully. */ /* Try adding -source option if it is useful. */ char *javac_target_source = - xasprintf ("%s -source %s", javac_target, source_version); + xasprintf ("%s -source %s", javac_target, source_version_for_javac); unlink (compiled_file_name); @@ -1276,7 +1300,7 @@ is_envjavac_nongcj_usable (const char *javac, true)) /* "$JAVAC -target $target_version" compiled conftestfail.java successfully, and - "$JAVAC -target $target_version -source $source_version" + "$JAVAC -target $target_version -source $source_version_for_javac" rejects it. So the -source option is useful. */ resultp->source_option = true; } @@ -1294,7 +1318,7 @@ is_envjavac_nongcj_usable (const char *javac, -target and -source options. (Supported by Sun javac 1.4 and higher.) */ char *javac_target_source = - xasprintf ("%s -source %s", javac_target, source_version); + xasprintf ("%s -source %s", javac_target, source_version_for_javac); unlink (compiled_file_name); @@ -1306,7 +1330,7 @@ is_envjavac_nongcj_usable (const char *javac, && get_classfile_version (compiled_file_name) <= corresponding_classfile_version (target_version)) { - /* "$JAVAC -target $target_version -source $source_version" + /* "$JAVAC -target $target_version -source $source_version_for_javac" compiled conftest.java successfully. */ resultp->source_option = true; resultp->target_option = true; @@ -1826,7 +1850,9 @@ is_javac_present (void) -target option. Return a failure indicator (true upon error). */ static bool -is_javac_usable (const char *source_version, const char *target_version, +is_javac_usable (const char *source_version, + const char *source_version_for_javac, + const char *target_version, bool *usablep, bool *source_option_p, bool *target_option_p) { /* The cache depends on the source_version and target_version. */ @@ -1871,7 +1897,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - false, source_version, + false, source_version_for_javac, false, target_version, tmpdir->dir_name, false, false, false, true) && stat (compiled_file_name, &statbuf) >= 0 @@ -1884,7 +1910,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - true, source_version, + true, source_version_for_javac, false, target_version, tmpdir->dir_name, false, false, false, true) && stat (compiled_file_name, &statbuf) >= 0 @@ -1917,7 +1943,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - false, source_version, + false, source_version_for_javac, false, target_version, tmpdir->dir_name, false, false, false, true) @@ -1927,13 +1953,13 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (compile_using_javac (java_sources, 1, - true, source_version, + true, source_version_for_javac, false, target_version, tmpdir->dir_name, false, false, false, true)) /* javac compiled conftestfail.java successfully, and - "javac -source $source_version" rejects it. So the - -source option is useful. */ + "javac -source $source_version_for_javac" rejects it. + So the -source option is useful. */ resultp->source_option = true; } } @@ -1949,7 +1975,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - false, source_version, + false, source_version_for_javac, true, target_version, tmpdir->dir_name, false, false, false, true) @@ -1964,7 +1990,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - true, source_version, + true, source_version_for_javac, true, target_version, tmpdir->dir_name, false, false, false, true) @@ -1999,7 +2025,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - false, source_version, + false, source_version_for_javac, true, target_version, tmpdir->dir_name, false, false, false, true) @@ -2009,13 +2035,13 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (compile_using_javac (java_sources, 1, - true, source_version, + true, source_version_for_javac, true, target_version, tmpdir->dir_name, false, false, false, true)) /* "javac -target $target_version" compiled conftestfail.java successfully, and - "javac -target $target_version -source $source_version" + "javac -target $target_version -source $source_version_for_javac" rejects it. So the -source option is useful. */ resultp->source_option = true; } @@ -2034,7 +2060,7 @@ is_javac_usable (const char *source_version, const char *target_version, java_sources[0] = conftest_file_name; if (!compile_using_javac (java_sources, 1, - true, source_version, + true, source_version_for_javac, true, target_version, tmpdir->dir_name, false, false, false, true) @@ -2042,7 +2068,7 @@ is_javac_usable (const char *source_version, const char *target_version, && get_classfile_version (compiled_file_name) <= corresponding_classfile_version (target_version)) { - /* "javac -target $target_version -source $source_version" + /* "javac -target $target_version -source $source_version_for_javac" compiled conftest.java successfully. */ resultp->source_option = true; resultp->target_option = true; @@ -2113,10 +2139,14 @@ compile_java_class (const char * const *java_sources, bool target_option = false; bool fsource_option = false; bool ftarget_option = false; + const char *source_version_for_javac; if (target_version == NULL) target_version = default_target_version (); + source_version_for_javac = + get_source_version_for_javac (source_version, target_version); + if (is_envjavac_gcj (javac)) { /* It's a version of gcj. */ @@ -2163,7 +2193,9 @@ compile_java_class (const char * const *java_sources, { /* It's not gcj. Assume the classfile versions are correct. */ if (is_envjavac_nongcj_usable (javac, - source_version, target_version, + source_version, + source_version_for_javac, + target_version, &usable, &source_option, &target_option)) { @@ -2187,7 +2219,7 @@ compile_java_class (const char * const *java_sources, : xasprintf ("%s%s%s%s%s%s%s%s%s", javac, source_option ? " -source " : "", - source_option ? source_version : "", + source_option ? source_version_for_javac : "", target_option ? " -target " : "", target_option ? target_version : "", fsource_option ? " -fsource=" : "", @@ -2296,11 +2328,16 @@ compile_java_class (const char * const *java_sources, bool usable = false; bool source_option = false; bool target_option = false; + const char *source_version_for_javac; if (target_version == NULL) target_version = default_target_version (); - if (is_javac_usable (source_version, target_version, + source_version_for_javac = + get_source_version_for_javac (source_version, target_version); + + if (is_javac_usable (source_version, source_version_for_javac, + target_version, &usable, &source_option, &target_option)) { err = true; @@ -2320,7 +2357,7 @@ compile_java_class (const char * const *java_sources, verbose); err = compile_using_javac (java_sources, java_sources_count, - source_option, source_version, + source_option, source_version_for_javac, target_option, target_version, directory, optimize, debug, verbose, false); diff --git a/lib/javacomp.h b/lib/javacomp.h index 3d0a02d615..3d73a9205b 100644 --- a/lib/javacomp.h +++ b/lib/javacomp.h @@ -31,7 +31,7 @@ 1.6 (not supported) 1.7 switch(string) 1.8 lambdas - 1.9 private interface methods + 9 private interface methods target_version can be: classfile version: 1.1 45.3 1.2 46.0 @@ -41,7 +41,7 @@ 1.6 50.0 1.7 51.0 1.8 52.0 - 1.9 53.0 + 9 53.0 target_version can also be given as NULL. In this case, the required target_version is determined from the found JVM (see javaversion.h). Specifying target_version is useful when building a library (.jar) that is @@ -53,7 +53,7 @@ - target_version < 1.6 with source_version >= 1.6, or - target_version < 1.7 with source_version >= 1.7, or - target_version < 1.8 with source_version >= 1.8, or - - target_version < 1.9 with source_version >= 1.9, + - target_version < 9 with source_version >= 9, because even Sun's/Oracle's javac doesn't support these combinations. It is redundant to ask for a target_version > source_version, since the smaller target_version = source_version will also always work and newer JVMs diff --git a/lib/javaversion.h b/lib/javaversion.h index e4646e2f5e..86cbd1a33e 100644 --- a/lib/javaversion.h +++ b/lib/javaversion.h @@ -26,8 +26,8 @@ extern "C" { /* Return information about the Java version used by execute_java_class(). This is the value of System.getProperty("java.specification.version"). - Some possible values are: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6. Return NULL if - the Java version cannot be determined. */ + Some possible values are: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 9. + Return NULL if the Java version cannot be determined. */ extern char * javaexec_version (void); diff --git a/m4/javacomp.m4 b/m4/javacomp.m4 index 1ed9afca93..720630fb24 100644 --- a/m4/javacomp.m4 +++ b/m4/javacomp.m4 @@ -18,7 +18,7 @@ dnl with or without modifications, as long as this notice is preserved. # 1.6 (not supported) # 1.7 switch(string) # 1.8 lambdas -# 1.9 private interface methods +# 9 private interface methods # Instead of source-version 1.6, use 1.5, since Java 6 did not introduce any # language changes. See # https://docs.oracle.com/javase/8/docs/technotes/guides/language/enhancements.html @@ -32,7 +32,7 @@ dnl with or without modifications, as long as this notice is preserved. # 1.6 50.0 # 1.7 51.0 # 1.8 52.0 -# 1.9 53.0 +# 9 53.0 # The classfile version of a .class file can be determined through the "file" # command. More portably, the classfile major version can be determined through # "od -A n -t d1 -j 7 -N 1 classfile". @@ -43,11 +43,11 @@ dnl with or without modifications, as long as this notice is preserved. # 1.2 JDK/JRE 1.2 # 1.3 JDK/JRE 1.3, gij 3.3, 3.4 # 1.4 JDK/JRE 1.4, gij 4.0, 4.1 -# 1.5 JDK/JRE 1.5 -# 1.6 JDK/JRE 1.6 -# 1.7 JDK/JRE 1.7 -# 1.8 JDK/JRE 1.8 -# 1.9 JDK/JRE 1.9 +# 1.5 JDK/JRE 5 +# 1.6 JDK/JRE 6 +# 1.7 JDK/JRE 7 +# 1.8 JDK/JRE 8 +# 9 JDK/JRE 9 # Note: gij >= 3.3 can in some cases handle classes compiled with -target 1.4, # and gij >= 4.1 can in some cases partially handle classes compiled with # -target 1.5, but I have no idea how complete this support is. @@ -59,7 +59,10 @@ dnl with or without modifications, as long as this notice is preserved. # It is unreasonable to ask for: # - target-version < 1.4 with source-version >= 1.4, or # - target-version < 1.5 with source-version >= 1.5, or -# - target-version < 1.6 with source-version >= 1.6, +# - target_version < 1.6 with source_version >= 1.6, or +# - target_version < 1.7 with source_version >= 1.7, or +# - target_version < 1.8 with source_version >= 1.8, or +# - target_version < 9 with source_version >= 9, # because even Sun's/Oracle's javac doesn't support these combinations. # # It is redundant to ask for a target-version > source-version, since the @@ -111,7 +114,7 @@ changequote([,])dnl CLASSPATH=.${CLASSPATH:+$CLASSPATH_SEPARATOR$CLASSPATH} $CONF_JAVA conftestver 2>&AS_MESSAGE_LOG_FD }` case "$target_version" in - 1.1 | 1.2 | 1.3 | 1.4 | 1.5 | 1.6 | 1.7 | 1.8 | 1.9) ;; + 1.1 | 1.2 | 1.3 | 1.4 | 1.5 | 1.6 | 1.7 | 1.8 | 9) ;; null) dnl JDK 1.1.X returns null. target_version=1.1 ;; @@ -134,7 +137,7 @@ changequote([,])dnl failcode='class conftestfail { void foo () { Runnable r = () -> {}; } }' ;; 1.8) goodcode='class conftest { void foo () { Runnable r = () -> {}; } }' failcode='interface conftestfail { private void foo () {} }' ;; - 1.9) goodcode='interface conftest { private void foo () {} }' + 9) goodcode='interface conftest { private void foo () {} }' failcode='class conftestfail syntax error' ;; *) AC_MSG_ERROR([invalid source-version argument to gt_@&t@JAVACOMP: $source_version]) ;; esac @@ -147,7 +150,7 @@ changequote([,])dnl 1.6) cfversion=50 ;; 1.7) cfversion=51 ;; 1.8) cfversion=52 ;; - 1.9) cfversion=53 ;; + 9) cfversion=53 ;; *) AC_MSG_ERROR([invalid target-version argument to gt_@&t@JAVACOMP: $target_version]) ;; esac # Function to output the classfile version of a file (8th byte) in decimal. @@ -217,8 +220,8 @@ changequote([,])dnl dnl -target 1.6 only possible with -source 1.3/1.4/1.5/1.6 dnl -target 1.7 only possible with -source 1.3/1.4/1.5/1.6/1.7 dnl - dnl javac 1.9: -target 1.6 1.7 1.8 1.9 default: 1.9 - dnl -source 1.6 1.7 1.8 1.9 default: 1.9 + dnl javac 9: -target 1.6 1.7 1.8 9 default: 9 + dnl -source 1.6 1.7 1.8 9 default: 9 dnl -target 1.6 only possible with -source 1.6 dnl -target 1.7 only possible with -source 1.6/1.7 dnl -target 1.8 only possible with -source 1.6/1.7/1.8 @@ -364,6 +367,15 @@ changequote([,])dnl else dnl It's not gcj. Assume the classfile versions are correct. dnl Try $JAVAC. + dnl The javac option '-source 1.5' has the same meaning as '-source 1.6', + dnl but since Java 9 supports only the latter, prefer the latter if a + dnl target_version >= 1.6 is requested. + if test "$source_version" = 1.5; then + case "$target_version" in + 1.1 | 1.2 | 1.3 | 1.4 | 1.5) ;; + *) source_version='1.6' ;; + esac + fi rm -f conftest.class if { echo "$as_me:__oline__: $JAVAC -d . conftest.java" >&AS_MESSAGE_LOG_FD $JAVAC -d . conftest.java >&AS_MESSAGE_LOG_FD 2>&1 @@ -559,6 +571,15 @@ changequote([,])dnl if { javac -version >/dev/null 2>/dev/null || test $? -le 2; } \ && ( if javac -help 2>&1 >/dev/null | grep at.dms.kjc.Main >/dev/null && javac -help 2>/dev/null | grep 'released.*2000' >/dev/null ; then exit 1; else exit 0; fi ); then dnl OK, javac works. + dnl The javac option '-source 1.5' has the same meaning as '-source 1.6', + dnl but since Java 9 supports only the latter, prefer the latter if a + dnl target_version >= 1.6 is requested. + if test "$source_version" = 1.5; then + case "$target_version" in + 1.1 | 1.2 | 1.3 | 1.4 | 1.5) ;; + *) source_version='1.6' ;; + esac + fi dnl Now test whether it supports the desired target-version and dnl source-version. rm -f conftest.class -- 2.39.5