incompatible_windows_escape_jvm_flags: on Windows, enables tokenization and escaping of jvm_flags #7486
Description
Description
Add --incompatible_windows_escape_jvm_flags flag (default: false). This flag only affects builds on Windows.
This flag has no effect on Linux/macOS/non-Windows.
Background
When you build a java_binary or java_test on Windows, one of the outputs is an .exe file. This is called the launcher, and this is what you run with "bazel run" and "bazel test". The launcher's purpose is to set up the environment, compute the JVM command line (classpath, JVM flags, etc.) and launch the JVM.
The target-specific data (such as the classpath, main class name, but also the jvm_flags
attribute from the BUILD-file) are embedded into the launcher as binary data. When you run the launcher, it will compute the command line to run the JVM as a subprocess (using the CreateProcessW system call), and that involves escaping the JVM flags so they can safely be passed to the subprcoess.
The new flag
The --incompatible_windows_escape_jvm_flags flag affects how Bazel builds the launcher:
- whether or not Bazel will Bash-tokenize the jvm_flags before embedding them in the launcher, and
- whether the launcher will escape these flags using the correct escaping logic or the buggy one.
When the flag is enabled:
-
Bazel will Bash-tokenize java_binary.jvm_flags and java_test.jvm_flags (as documented by the Build Encyclopedia) before embedding them into the launcher.
-
The launcher will properly escape these flags when it runs the JVM as a subprocess (using launcher_util::WindowsEscapeArg2).
-
The result is that the jvm_flags declared in the BUILD file will arrive to the Java program as intended.
When the flag is disabled:
-
Bazel does not Bash-tokenize the jvm_flags before embedding them in the launcher.
-
The launcher escapes the flags with a Bash-like escaping logic (launcher_util::WindowsEscapeArg)
which cannot properly quote and escape everything. -
The result is that the jvm_flags declared in the BUILD file might get messed up as they are passed to the JVM, or the launcher may not even be able to run the JVM.
Related bug: #7072
Example
BUILD file:
java_binary(
name = "x",
srcs = ["A.java"],
main_class = "A",
jvm_flags = [
"-Darg0='hello world'",
r"-Darg1=\"C:\\Program\ Files\\\"",
],
)
A.java:
public class A {
public static void main(String[] args) {
System.out.printf(
"arg0=(%s)%narg1=(%s)%n",
System.getProperty("arg0"),
System.getProperty("arg1"));
}
}
The expected output of running the binary is:
arg0=(hello world)
arg1=("C:\Program Files\")
Currently the output is something like:
Error: Could not find or load main class
Migration recipe
None, as of 2019-02-21.
We don't expect any breakages when this flag is enabled. However if it breaks your build or if it breaks your java_binaries or java_tests, please let us know so we can help fixing it and provide a migration recipe.
Rollout plan
- Bazel 0.23.0 will not support this flag.
- Bazel 0.24.0 is expected to support this flag, with default value being
false
. - Bazel 0.25.0 is expected to flip this flag to true.