Skip to content

Commit

Permalink
Windows: add --incompatible_windows_escape_jvm_flags
Browse files Browse the repository at this point in the history
Add --incompatible_windows_escape_jvm_flags flag
(default: false). This flag has no effect on
platforms other than Windows.

This flag affects how Bazel builds the launcher of
java_binary and java_test targets. (The launcher
is the .exe file that sets up the environment for
the Java program and launches the JVM.)

In particular, the flag controls whether or not
Bazel will Bash-tokenize the jvm_flags that were
declared in the BUILD file, and whether or not
these jvm_flags are escaped by the launcher when
it invokes the JVM.

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.

Incompatible flag: bazelbuild#7486

Related: bazelbuild#7072

RELNOTES[NEW]: Added --incompatible_windows_escape_jvm_flags flag: enables correct java_binary.jvm_flags and java_test.jvm_flags tokenization and escaping on Windows. (No-op on other platforms.)

Change-Id: I531cc63cdfeccbe4b6d48876cb82870c1726a723
  • Loading branch information
laszlocsomor committed Feb 21, 2019
1 parent d19d4ba commit 53bb8f1
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/google/devtools/build/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/proto",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/python",
"//src/main/java/com/google/devtools/build/lib/shell",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/skyframe",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
import com.google.devtools.build.lib.rules.java.JavaUtil;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
import com.google.devtools.build.lib.shell.ShellUtils;
import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.OS;
Expand Down Expand Up @@ -407,13 +409,32 @@ public Artifact createStubAction(
arguments.add(Substitution.ofSpaceSeparatedList("%jvm_flags%", jvmFlagsList));

if (OS.getCurrent() == OS.WINDOWS) {
boolean windowsEscapeJvmFlags =
ruleContext
.getConfiguration()
.getFragment(JavaConfiguration.class)
.windowsEscapeJvmFlags();

List<String> jvmFlagsForLauncher = jvmFlagsList;
if (windowsEscapeJvmFlags) {
try {
jvmFlagsForLauncher = new ArrayList<>(jvmFlagsList.size());
for (String f : jvmFlagsList) {
ShellUtils.tokenize(jvmFlagsForLauncher, f);
}
} catch (TokenizationException e) {
ruleContext.attributeError("jvm_flags", "could not Bash-tokenize flag: " + e);
}
}

return createWindowsExeLauncher(
ruleContext,
javaExecutable,
classpath,
javaStartClass,
jvmFlagsList,
executable);
jvmFlagsForLauncher,
executable,
windowsEscapeJvmFlags);
}

ruleContext.registerAction(new TemplateExpansionAction(
Expand All @@ -426,9 +447,9 @@ private static Artifact createWindowsExeLauncher(
String javaExecutable,
NestedSet<Artifact> classpath,
String javaStartClass,
ImmutableList<String> jvmFlags,
Artifact javaLauncher) {

List<String> jvmFlags,
Artifact javaLauncher,
boolean windowsEscapeJvmFlags) {
LaunchInfo launchInfo =
LaunchInfo.builder()
.addKeyValuePair("binary_type", "Java")
Expand All @@ -448,6 +469,7 @@ private static Artifact createWindowsExeLauncher(
"classpath",
";",
Iterables.transform(classpath, Artifact.ROOT_RELATIVE_PATH_STRING))
.addKeyValuePair("escape_jvmflags", windowsEscapeJvmFlags ? "1" : "0")
// TODO(laszlocsomor): Change the Launcher to accept multiple jvm_flags entries. As of
// 2019-02-13 the Launcher accepts just one jvm_flags entry, which contains all the
// flags, joined by TAB characters. The Launcher splits up the string to get the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ public boolean alwaysGenerateOutputMapping() {
private final ImmutableList<Label> pluginList;
private final boolean requireJavaToolchainHeaderCompilerDirect;
private final boolean disallowResourceJars;
private final boolean windowsEscapeJvmFlags;

// TODO(dmarting): remove once we have a proper solution for #2539
private final boolean useLegacyBazelJavaTest;
Expand Down Expand Up @@ -213,6 +214,7 @@ public boolean alwaysGenerateOutputMapping() {
this.isJlplStrictDepsEnforced = javaOptions.isJlplStrictDepsEnforced;
this.disallowResourceJars = javaOptions.disallowResourceJars;
this.addTestSupportToCompileTimeDeps = javaOptions.addTestSupportToCompileTimeDeps;
this.windowsEscapeJvmFlags = javaOptions.windowsEscapeJvmFlags;

ImmutableList.Builder<Label> translationsBuilder = ImmutableList.builder();
for (String s : javaOptions.translationTargets) {
Expand Down Expand Up @@ -455,4 +457,8 @@ public boolean requireJavaToolchainHeaderCompilerDirect() {
public boolean disallowResourceJars() {
return disallowResourceJars;
}

public boolean windowsEscapeJvmFlags() {
return windowsEscapeJvmFlags;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,27 @@ public ImportDepsCheckingLevelConverter() {
"Disables the resource_jars attribute; use java_import and deps or runtime_deps instead.")
public boolean disallowResourceJars;

@Option(
name = "incompatible_windows_escape_jvm_flags",
defaultValue = "false",
documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
effectTags = {
OptionEffectTag.ACTION_COMMAND_LINES,
OptionEffectTag.AFFECTS_OUTPUTS,
},
metadataTags = {
OptionMetadataTag.INCOMPATIBLE_CHANGE,
OptionMetadataTag.TRIGGERED_BY_ALL_INCOMPATIBLE_CHANGES
},
help =
"On Linux/macOS/non-Windows: no-op. On Windows: this flag affects how java_binary and"
+ " java_test targets are built; in particular, how the launcher of these targets"
+ " escapes flags at the time of running the java_binary/java_test. When the flag is"
+ " true, the launcher escapes the JVM flags using Windows-style escaping (correct"
+ " behavior). When the flag is false, the launcher uses Bash-style escaping"
+ " (buggy behavior). See https://github.com/bazelbuild/bazel/issues/7072")
public boolean windowsEscapeJvmFlags;

private Label getHostJavaBase() {
if (hostJavaBase == null) {
if (useJDK11AsHostJavaBase) {
Expand Down Expand Up @@ -698,6 +719,8 @@ public FragmentOptions getHost() {

host.disallowResourceJars = disallowResourceJars;

host.windowsEscapeJvmFlags = windowsEscapeJvmFlags;

return host;
}

Expand Down
7 changes: 7 additions & 0 deletions src/test/shell/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,13 @@ sh_test(
tags = ["no_windows"],
)

sh_test(
name = "jvm_flags_escaping_test",
srcs = ["jvm_flags_escaping_test.sh"],
data = [":test-deps"],
deps = ["@bazel_tools//tools/bash/runfiles"],
)

########################################################################
# Test suites.

Expand Down
Loading

0 comments on commit 53bb8f1

Please sign in to comment.