Summary
Update the Java launcher to support launching single-file source-code programs.
Problem
(For full details and examples, see JEP 330).
The need to perform separate "compile" and "execute" steps for simple programs makes it harder to learn how to use Java, and harder to deploy simple programs as executable code.
Solution
Update the Java launcher to be able to launch single file programs, by recognizing the use of a source file name on the command line, so that it can be compiled and subsequently executed.
In addition, update the launcher to make it easier to leverage the "shebang" mechanism often found on Unix-derived systems to execute single-file programs.
Discussion
The solution introduces a new --source
version option to
force source-file mode and/or to specify the version of the source
language and API used in the source file. As part of the operation
of source-file mode, an implicit --release
version option
is passed to the internal invocation of the platform compiler, javac.
The javac --release
option is closely related to the long-standing
javac -source
option, and so there is some risk of confusion
between the new launcher --source
option and the javac
-source
option, for those who are familiar with the latter.
It has been considered to rename or alias the new launcher
--source
option as --release
, leveraging the analogy with
the javac option. However, while a --source
option for the
launcher can be neatly described as enabling "source-file mode"
there is no such easy explanation for --release
. Furthermore,
introducing --release
version as a launcher option
might lead users to believe it has an impact on the runtime
when it is used, which is definitely not the case.
Additionally, the use of --release
as a launcher option,
albeit with different semantics, has already been considered and
rejected. (See JEP 12.)
Finally, unlike all other options that are supported both by
the launcher and by the compiler (including all the path-related
options and module system options), the new launcher option
is not a direct analog of either the javac -source
option or
--release
option, which significantly reduces the incentive
to choose either one for that reason.
The decision is therefore to use --source
as the least
confusing of the two alternatives.
Specification
The change is a combination of two parts:
- An enhancement to the interpretation of what previously has been the "main class" on the command line.
- A new
--source
version option
First, the launcher identifies the first argument (if any) on the command line that is neither an option nor a part of an option ... i.e. the argument that previously has always identified the name of the main class to be invoked.
Then, if that argument identifies an existing file with an extension of .java
it is assumed to identify a source file.
Or, if the argument identifies an existing file and a new --source
version option
is also present on the command line, the argument is assumed to be a source file
regardless of the file's extension. The version identifies the language version of
the source code in the file.
If either of the preceding conditions identify the argument as a source file, the launcher proceeds in source-file mode as follows:
In source-file mode, any additional command-line options are processed as follows:
The launcher scans the options specified before the source file for any that are relevant in order to compile the source file. This includes:
--class-path
,--module-path
,--add-exports
,--add-modules
,--limit-modules
,--patch-module
,--upgrade-module-path
, and any variant forms of those options. It also includes the new--enable-preview
option, described in JEP 12.No provision is made to pass any additional options to the compiler, such as
-processor
or-Werror
.Command-line argument files (@-files) may be used in the standard way. Long lists of arguments for either the VM or the program being invoked may be placed in files which are specified on the command-line by prefixing the filename with an
@
character.
In source-file mode, compilation proceeds as follows:
Any command-line options that are relevant to the compilation environment are taken into account.
No other source files are found and compiled, as if the source path is set to an empty value.
Annotation processing is disabled, as if
-proc:none
is in effect.If a version is specified, the value is used as the argument for an implicit
--release
option for the compilation. This sets both the source version accepted by compiler and the system API that may be used by the code in the source file.The source file is compiled in the context of an unnamed module.
The source file should contain one or more top-level classes, the first of which is taken as the class to be executed.
The compiler does not enforce the optional restriction defined at the end of JLS §7.6, that a type in a named package should exist in a file whose name is composed from the type name followed by the
.java
extension.If the source file contains errors, appropriate error messages are written to the standard error stream, and the launcher exits with a non-zero exit code.
In source-file mode, execution proceeds as follows:
The class to be executed is the first top-level class found in the source file. It must contain a declaration of the standard
public static void main(String[])
method.The compiled classes are loaded by a custom class loader, that delegates to the application class loader. (This implies that classes appearing on the application class path cannot refer to any classes declared in the source file.)
The compiled classes are executed in the context of an unnamed module, and as if
--add-modules=ALL-DEFAULT
is in effect (in addition to any other--add-module
options that may be have been specified on the command line.)Any arguments appearing after the name of the file on the command line are passed to the standard
main
method in the obvious way.It is an error if there is a class on the application class path whose name is the same as that of the class to be executed.
Note that there is a potential minor ambiguity when using a simple command-line
like java HelloWorld.java
. Previously, HelloWorld.java
would have been
interpreted as a class called java
in a package called HelloWorld
, but which
is now resolved in favor of a file called HelloWorld.java
if such a file
exists.
The new --source
version option, and the enhanced behavior for determining
the main class to be executed, do not affect the VM or JNI interface.
Command-line help
The primary command-line help, generated by --help
, is modified as follows:
7a8
> or java [options] source-file [args]
9,10c10,12
< Arguments following the main class, -jar <jarfile>, -m or --module
< <module>/<mainclass> are passed as the arguments to main class.
---
> Arguments following the main class, source-file, -jar <jarfile>,
> -m or --module <module>/<mainclass> are passed as the arguments to
> main class.
The additional command-line help, generated by --help-extra
, is modified as follows:
58a59,60
> --source <version>
> specify the Java language version expected in source-file mode
"Shebang" files
"Shebang" files are
a mechanism provided by some Unix-derived systems to execute a file
with an executable named in the first line of the file, which must begin
with the two ASCII characters #!
. Any content on the first line after the
name of the executable is typically passed as an initial argument, along
with the name of the file, to the nominated executable.
To support this mechanism for Java source files, the source-code launcher makes two accommodations:
When the launcher reads the source file, if the first line begins with ASCII
#!
, then the contents of that line up to but not including the first newline are ignored when determining the source code to be passed to the compiler.Some operating systems pass the text on the first line after the name of the executable as a single argument to the executable. With that in mind, if the launcher encounters an option beginning
--source
and containing whitespace, it is split into a series of words, separated by whitespace, before being further analyzed by the launcher.
- csr of
-
JDK-8201274 Launch Single-File Source-Code Programs
-
- Resolved
-
- relates to
-
JDK-8306915 Implementation of JEP Launch Multi-File Source-Code Programs
-
- Closed
-