Skip to content

Commit 460ca7b

Browse files
committed
[GR-42402] Refine support for javaPreviewNeeded.
PullRequest: mx/1529
2 parents 4097a4c + 3702af5 commit 460ca7b

File tree

3 files changed

+68
-8
lines changed

3 files changed

+68
-8
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,19 @@ In other words, there should be no back-and-forth to the same repo.
595595
Java projects may use language or runtime features which are considered _preview features_ in certain Java versions, in which case preview features must be enabled for compilation (`--enable-preview`).
596596
This is specified using the `javaPreviewNeeded` attribute, which is a version specification in the same format as `javaCompliance`, for example: `"javaPreviewNeeded": "19..20"`
597597
If the compiling JDK matches that version or version range, preview features are enabled for compilation.
598+
Given that javac and the JVM must be on the same JDK version for preview features (see [here](https://nipafx.dev/enable-preview-language-features/#same-version-for-feature-compiler-and-jvm) for details),
599+
compiling a project with preview features will force the javac `-source` and `-target` options to `N` where `N` is
600+
the minimum of:
601+
* the version of the JDK being used for compilation (i.e. `JAVA_HOME`) and
602+
* the lowest version where `--enable-preview` is not needed.
603+
604+
The following table of examples should make this clearer:
605+
606+
| JDK | javaPreviewNeeded | -target / -source | --enable-preview |
607+
| ----|-------------------|-------------------|------------------|
608+
| 19 | 19+ | 19 | Yes |
609+
| 20 | 19+ | 20 | Yes |
610+
| 20 | 19 | 20 | No |
611+
| 21 | 19 | 20 | No |
612+
| 22 | 20 | 21 | No |
613+
| 22 | 19..20 | 21 | No |

mx.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6920,10 +6920,15 @@ def __init__(self, suite, name, subDir, srcDirs, deps, javaCompliance, workingSe
69206920
Project.__init__(self, suite, name, subDir, srcDirs, deps, workingSets, d, theLicense, testProject=testProject, **kwArgs)
69216921
ClasspathDependency.__init__(self, **kwArgs)
69226922
if javaCompliance is None:
6923-
abort('javaCompliance property required for Java project ' + name)
6923+
self.abort('javaCompliance property required for Java project')
69246924
self.javaCompliance = JavaCompliance(javaCompliance, context=self)
69256925
javaPreviewNeeded = kwArgs.get('javaPreviewNeeded')
6926-
self.javaPreviewNeeded = JavaCompliance(javaPreviewNeeded, context=self) if javaPreviewNeeded else None
6926+
if javaPreviewNeeded:
6927+
self.javaPreviewNeeded = JavaCompliance(javaPreviewNeeded, context=self)
6928+
if self.javaPreviewNeeded.value > self.javaCompliance.value:
6929+
self.abort(f'javaCompliance ({self.javaCompliance}) cannot be lower than javaPreviewNeeded ({self.javaPreviewNeeded})')
6930+
else:
6931+
self.javaPreviewNeeded = None
69276932
# The annotation processors defined by this project
69286933
self.definedAnnotationProcessors = None
69296934
self.declaredAnnotationProcessors = []
@@ -7786,6 +7791,28 @@ def __init__(self, jdk, extraJavacArgs):
77867791
self.jdk = jdk
77877792
self.extraJavacArgs = extraJavacArgs if extraJavacArgs else []
77887793

7794+
@staticmethod
7795+
def get_release_args(jdk_compliance, compliance, javaPreviewNeeded):
7796+
"""
7797+
Gets ``-target``, ``-source`` and ``--enable-preview`` javac arguments based on
7798+
`jdk_compliance`, `compliance` and `javaPreviewNeeded`.
7799+
"""
7800+
enable_preview = []
7801+
if javaPreviewNeeded:
7802+
if javaPreviewNeeded._high_bound():
7803+
out_of_preview = javaPreviewNeeded.highest_specified_value() + 1
7804+
if jdk_compliance.value >= out_of_preview:
7805+
c = str(out_of_preview)
7806+
else:
7807+
c = str(jdk_compliance.value)
7808+
enable_preview = ['--enable-preview']
7809+
else:
7810+
c = str(jdk_compliance)
7811+
enable_preview = ['--enable-preview']
7812+
else:
7813+
c = str(compliance)
7814+
return ['-target', c, '-source', c] + enable_preview
7815+
77897816
def prepare(self, sourceFiles, project, outputDir, classPath, processorPath, sourceGenDir, jnigenDir,
77907817
disableApiRestrictions, warningsAsErrors, forceDeprecationAsWarning, showTasks, postCompileActions):
77917818
javacArgs = ['-g', '-d', outputDir]
@@ -7803,10 +7830,8 @@ def prepare(self, sourceFiles, project, outputDir, classPath, processorPath, sou
78037830
javacArgs += ['-processorpath', processorPath, '-s', sourceGenDir]
78047831
else:
78057832
javacArgs += ['-proc:none']
7806-
c = str(compliance)
7807-
javacArgs += ['-target', c, '-source', c]
7808-
if project.javaPreviewNeeded and self.jdk.javaCompliance in project.javaPreviewNeeded:
7809-
javacArgs.append('--enable-preview')
7833+
7834+
javacArgs += JavacLikeCompiler.get_release_args(self.jdk.javaCompliance, compliance, project.javaPreviewNeeded)
78107835
if _opts.very_verbose:
78117836
javacArgs.append('-verbose')
78127837

@@ -18303,7 +18328,7 @@ def alarm_handler(signum, frame):
1830318328
abort(1, killsig=signal.SIGINT)
1830418329

1830518330
# The version must be updated for every PR (checked in CI)
18306-
version = VersionSpec("6.12.1") # [GR-41841] Update all digests to sha-512.
18331+
version = VersionSpec("6.12.2") # GR-42402 - Refine support for javaPreviewNeeded.
1830718332

1830818333
currentUmask = None
1830918334
_mx_start_datetime = datetime.utcnow()

mx_gate.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import mx_javacompliance
4242
import sys
4343
from mx_urlrewrites import rewriteurl
44+
from mx_javacompliance import JavaCompliance
4445
from collections import OrderedDict
4546

4647
"""
@@ -514,6 +515,24 @@ def _run_mx_suite_tests():
514515
"""
515516
mx_javacompliance._test()
516517

518+
# (JDK, project_compliance, javaPreviewNeeded) -> expected javac args
519+
get_release_args_data = {
520+
(19, '19+', None): ['-target', '19', '-source', '19'],
521+
(20, '19+', None): ['-target', '19', '-source', '19'],
522+
(19, '19+', '19+'): ['-target', '19', '-source', '19', '--enable-preview'],
523+
(20, '19+', '19+'): ['-target', '20', '-source', '20', '--enable-preview'],
524+
(20, '19+', '19'): ['-target', '20', '-source', '20'],
525+
(21, '19+', '19'): ['-target', '20', '-source', '20'],
526+
(22, '19+', '20'): ['-target', '21', '-source', '21'],
527+
(22, '19+', '19..20'): ['-target', '21', '-source', '21'],
528+
}
529+
for k, expect in get_release_args_data.items():
530+
jdk_compliance = JavaCompliance(k[0])
531+
project_compliance = JavaCompliance(k[1])
532+
javaPreviewNeeded = JavaCompliance(k[2]) if k[2] else None
533+
actual = mx.JavacLikeCompiler.get_release_args(jdk_compliance, project_compliance, javaPreviewNeeded)
534+
assert actual == expect, f'{k}: {actual} != {expect}'
535+
517536
if mx.is_windows():
518537
def win(s, min_length=0):
519538
extra = min_length - len(s)
@@ -1548,7 +1567,7 @@ def _visit_deps(dep, edge):
15481567
exclude_dirs.extend(p.source_dirs())
15491568
exclude_dirs.append(p.source_gen_dir())
15501569

1551-
javaCompliance = max([p.javaCompliance for p in includes]) if includes else mx.JavaCompliance('1.7')
1570+
javaCompliance = max([p.javaCompliance for p in includes]) if includes else JavaCompliance('1.7')
15521571

15531572
jacoco_exec = get_jacoco_dest_file()
15541573
if not os.path.exists(jacoco_exec) and not args.skip_coverage:

0 commit comments

Comments
 (0)