aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/NativeLauncherUtil.java40
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java113
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java19
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java18
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java10
7 files changed, 214 insertions, 13 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/NativeLauncherUtil.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/NativeLauncherUtil.java
index 6323772b58..1e07ab52fb 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/NativeLauncherUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/NativeLauncherUtil.java
@@ -32,6 +32,12 @@ public final class NativeLauncherUtil {
private NativeLauncherUtil() {}
+ /** Write a string to launch info buffer. */
+ public static void writeLaunchInfo(ByteArrayOutputStream launchInfo, String value)
+ throws IOException {
+ launchInfo.write(value.getBytes(UTF_8));
+ }
+
/** Write a key-value pair launch info to buffer. */
public static void writeLaunchInfo(ByteArrayOutputStream launchInfo, String key, String value)
throws IOException {
@@ -42,6 +48,30 @@ public final class NativeLauncherUtil {
}
/**
+ * Write a key-value pair launch info to buffer. The method construct the value from a list of
+ * String separated by delimiter.
+ */
+ public static void writeLaunchInfo(
+ ByteArrayOutputStream launchInfo,
+ String key,
+ final Iterable<String> valueList,
+ char delimiter)
+ throws IOException {
+ launchInfo.write(key.getBytes(UTF_8));
+ launchInfo.write('=');
+ boolean isFirst = true;
+ for (String value : valueList) {
+ if (!isFirst) {
+ launchInfo.write(delimiter);
+ } else {
+ isFirst = false;
+ }
+ launchInfo.write(value.getBytes(UTF_8));
+ }
+ launchInfo.write('\0');
+ }
+
+ /**
* Write the size of all the launch info as a 64-bit integer at the end of the output stream in
* little endian.
*/
@@ -64,15 +94,17 @@ public final class NativeLauncherUtil {
*/
public static void createNativeLauncherActions(
RuleContext ruleContext, Artifact launcher, ByteArrayOutputStream launchInfo) {
+ createNativeLauncherActions(ruleContext, launcher, ByteSource.wrap(launchInfo.toByteArray()));
+ }
+
+ public static void createNativeLauncherActions(
+ RuleContext ruleContext, Artifact launcher, ByteSource launchInfo) {
Artifact launchInfoFile =
ruleContext.getRelatedArtifact(launcher.getRootRelativePath(), ".launch_info");
ruleContext.registerAction(
new BinaryFileWriteAction(
- ruleContext.getActionOwner(),
- launchInfoFile,
- ByteSource.wrap(launchInfo.toByteArray()),
- /*makeExecutable=*/ false));
+ ruleContext.getActionOwner(), launchInfoFile, launchInfo, /*makeExecutable=*/ false));
Artifact baseLauncherBinary = ruleContext.getPrerequisiteArtifact("$launcher", Mode.HOST);
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index 1b363de058..73fbf27975 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -32,6 +32,7 @@ import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
@@ -318,6 +319,10 @@ public class BazelJavaRuleClasses {
@Override
public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
+ Label launcher = env.getLauncherLabel();
+ if (launcher != null) {
+ builder.add(attr("$launcher", LABEL).cfg(HOST).value(launcher));
+ }
return builder
/* <!-- #BLAZE_RULE($base_java_binary).ATTRIBUTE(classpath_resources) -->
<em class="harmful">DO NOT USE THIS OPTION UNLESS THERE IS NO OTHER WAY)</em>
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
index 845f48102b..65956414df 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
@@ -21,6 +21,7 @@ import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+import com.google.common.io.ByteSource;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -35,6 +36,7 @@ import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Te
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.test.TestConfiguration;
import com.google.devtools.build.lib.bazel.rules.BazelConfiguration;
+import com.google.devtools.build.lib.bazel.rules.NativeLauncherUtil;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
@@ -63,7 +65,11 @@ import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.util.ShellEscaper;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -239,6 +245,15 @@ public class BazelJavaSemantics implements JavaSemantics {
}
}
+ /**
+ * In Bazel this {@code createStubAction} considers {@code javaExecutable} as a file path for the
+ * JVM binary (java).
+ */
+ @Override
+ public boolean isJavaExecutableSubstitution() {
+ return false;
+ }
+
@Override
public Artifact createStubAction(
RuleContext ruleContext,
@@ -260,7 +275,10 @@ public class BazelJavaSemantics implements JavaSemantics {
final boolean isRunfilesEnabled = ruleContext.getConfiguration().runfilesEnabled();
arguments.add(Substitution.of("%runfiles_manifest_only%", isRunfilesEnabled ? "" : "1"));
arguments.add(Substitution.of("%workspace_prefix%", workspacePrefix));
- arguments.add(Substitution.of("%javabin%", javaExecutable));
+ arguments.add(
+ Substitution.of(
+ "%javabin%",
+ JavaCommon.getJavaBinSubstitutionFromJavaExecutable(ruleContext, javaExecutable)));
arguments.add(Substitution.of("%needs_runfiles%",
JavaCommon.getJavaExecutable(ruleContext).isAbsolute() ? "0" : "1"));
@@ -312,7 +330,20 @@ public class BazelJavaSemantics implements JavaSemantics {
arguments.add(Substitution.of("%java_start_class%",
ShellEscaper.escapeString(javaStartClass)));
- arguments.add(Substitution.ofSpaceSeparatedList("%jvm_flags%", ImmutableList.copyOf(jvmFlags)));
+
+ ImmutableList<String> jvmFlagsList = ImmutableList.copyOf(jvmFlags);
+ arguments.add(Substitution.ofSpaceSeparatedList("%jvm_flags%", jvmFlagsList));
+
+ if (OS.getCurrent() == OS.WINDOWS
+ && ruleContext.getConfiguration().enableWindowsExeLauncher()) {
+ return createWindowsExeLauncher(
+ ruleContext,
+ javaExecutable,
+ classpath,
+ javaStartClass,
+ jvmFlagsList,
+ executable);
+ }
ruleContext.registerAction(new TemplateExpansionAction(
ruleContext.getActionOwner(), executable, STUB_SCRIPT, arguments, true));
@@ -345,6 +376,84 @@ public class BazelJavaSemantics implements JavaSemantics {
}
}
+ private static class JavaLaunchInfoByteSource extends ByteSource {
+ private final String workspaceName;
+ private final String javaBinPath;
+ private final String jarBinPath;
+ private final String javaStartClass;
+ private final ImmutableList<String> jvmFlags;
+ private final NestedSet<Artifact> classpath;
+
+ private JavaLaunchInfoByteSource(
+ String workspaceName,
+ String javaBinPath,
+ String jarBinPath,
+ String javaStartClass,
+ ImmutableList<String> jvmFlags,
+ NestedSet<Artifact> classpath) {
+ this.workspaceName = workspaceName;
+ this.javaBinPath = javaBinPath;
+ this.jarBinPath = jarBinPath;
+ this.javaStartClass = javaStartClass;
+ this.jvmFlags = jvmFlags;
+ this.classpath = classpath;
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ ByteArrayOutputStream launchInfo = new ByteArrayOutputStream();
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "binary_type", "Java");
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "workspace_name", workspaceName);
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "java_bin_path", javaBinPath);
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "jar_bin_path", jarBinPath);
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "java_start_class", javaStartClass);
+
+ // To be more efficient, we don't construct a key-value pair for classpath.
+ // Instead, we directly write it into launchInfo.
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "classpath=");
+ boolean isFirst = true;
+ for (Artifact artifact : classpath) {
+ if (!isFirst) {
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, ";");
+ } else {
+ isFirst = false;
+ }
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, artifact.getRootRelativePathString());
+ }
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "\0");
+
+ NativeLauncherUtil.writeLaunchInfo(launchInfo, "jvm_flags", jvmFlags, ' ');
+
+ NativeLauncherUtil.writeDataSize(launchInfo);
+ return new ByteArrayInputStream(launchInfo.toByteArray());
+ }
+ }
+
+ private static Artifact createWindowsExeLauncher(
+ RuleContext ruleContext,
+ String javaExecutable,
+ NestedSet<Artifact> classpath,
+ String javaStartClass,
+ ImmutableList<String> jvmFlags,
+ Artifact javaLauncher) {
+
+ ByteSource launchInfoSource =
+ new JavaLaunchInfoByteSource(
+ ruleContext.getWorkspaceName(),
+ javaExecutable,
+ JavaCommon.getJavaExecutable(ruleContext)
+ .getParentDirectory()
+ .getRelative("jar.exe")
+ .getPathString(),
+ javaStartClass,
+ jvmFlags,
+ classpath);
+
+ NativeLauncherUtil.createNativeLauncherActions(ruleContext, javaLauncher, launchInfoSource);
+
+ return javaLauncher;
+ }
+
private static boolean enforceExplicitJavaTestDeps(RuleContext ruleContext) {
return ruleContext.getFragment(JavaConfiguration.class).explicitJavaTestDeps();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index c28b32e0ae..cc6aff0791 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -60,6 +60,7 @@ import com.google.devtools.build.lib.rules.java.OneVersionCheckActionBuilder;
import com.google.devtools.build.lib.rules.java.SingleJarActionBuilder;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.LinkedHashSet;
@@ -127,7 +128,14 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
attributesBuilder);
Artifact instrumentationMetadata =
helper.createInstrumentationMetadata(classJar, javaArtifactsBuilder);
- Artifact executable = ruleContext.createOutputArtifact(); // the artifact for the rule itself
+ Artifact executable; // the artifact for the rule itself
+ if (OS.getCurrent() == OS.WINDOWS
+ && ruleContext.getConfiguration().enableWindowsExeLauncher()) {
+ executable =
+ ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".exe");
+ } else {
+ executable = ruleContext.createOutputArtifact();
+ }
NestedSetBuilder<Artifact> filesToBuildBuilder =
NestedSetBuilder.<Artifact>stableOrder().add(classJar).add(executable);
@@ -181,13 +189,20 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
Artifact launcher = JavaHelper.launcherArtifactForTarget(javaSemantics, ruleContext);
+ String javaExecutable;
+ if (javaSemantics.isJavaExecutableSubstitution()) {
+ javaExecutable = JavaCommon.getJavaBinSubstitution(ruleContext, launcher);
+ } else {
+ javaExecutable = JavaCommon.getJavaExecutableForStub(ruleContext, launcher);
+ }
+
javaSemantics.createStubAction(
ruleContext,
javaCommon,
getJvmFlags(ruleContext, testClass),
executable,
mainClass,
- JavaCommon.getJavaBinSubstitution(ruleContext, launcher));
+ javaExecutable);
Artifact deployJar =
ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_JAR);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
index 9a093d163c..0672fe4942 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
@@ -48,6 +48,7 @@ import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnfo
import com.google.devtools.build.lib.rules.java.ProguardHelper.ProguardOutput;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.Collection;
@@ -154,7 +155,14 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
Artifact executableForRunfiles = null;
if (createExecutable) {
// This artifact is named as the rule itself, e.g. //foo:bar_bin -> bazel-bin/foo/bar_bin
- executableForRunfiles = ruleContext.createOutputArtifact();
+ // On Windows, it's going to be bazel-bin/foo/bar_bin.exe
+ if (OS.getCurrent() == OS.WINDOWS
+ && ruleContext.getConfiguration().enableWindowsExeLauncher()) {
+ executableForRunfiles =
+ ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".exe");
+ } else {
+ executableForRunfiles = ruleContext.createOutputArtifact();
+ }
filesBuilder.add(classJar).add(executableForRunfiles);
if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
@@ -238,6 +246,12 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
Artifact executableToRun = executableForRunfiles;
if (createExecutable) {
+ String javaExecutable;
+ if (semantics.isJavaExecutableSubstitution()) {
+ javaExecutable = JavaCommon.getJavaBinSubstitution(ruleContext, launcher);
+ } else {
+ javaExecutable = JavaCommon.getJavaExecutableForStub(ruleContext, launcher);
+ }
// Create a shell stub for a Java application
executableToRun =
semantics.createStubAction(
@@ -246,7 +260,7 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
jvmFlags,
executableForRunfiles,
mainClass,
- JavaCommon.getJavaBinSubstitution(ruleContext, launcher));
+ javaExecutable);
if (!executableToRun.equals(executableForRunfiles)) {
filesBuilder.add(executableToRun);
runfilesBuilder.addArtifact(executableToRun);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
index 3490db77d7..8e7fdf2395 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java
@@ -480,10 +480,11 @@ public class JavaCommon {
}
/**
- * Returns the string that the stub should use to determine the JVM
+ * Returns the path of the java executable that the java stub should use.
+ *
* @param launcher if non-null, the cc_binary used to launch the Java Virtual Machine
*/
- public static String getJavaBinSubstitution(
+ public static String getJavaExecutableForStub(
RuleContext ruleContext, @Nullable Artifact launcher) {
Preconditions.checkState(ruleContext.getConfiguration().hasFragment(Jvm.class));
PathFragment javaExecutable;
@@ -501,8 +502,16 @@ public class JavaCommon {
javaExecutable =
PathFragment.create(PathFragment.create(ruleContext.getWorkspaceName()), javaExecutable);
}
- javaExecutable = javaExecutable.normalize();
+ return javaExecutable.normalize().getPathString();
+ }
+ /**
+ * Returns the shell command that computes `JAVABIN`.
+ * The command derives the JVM location from a given Java executable path.
+ */
+ public static String getJavaBinSubstitutionFromJavaExecutable(
+ RuleContext ruleContext, String javaExecutableStr) {
+ PathFragment javaExecutable = PathFragment.create(javaExecutableStr);
if (ruleContext.getConfiguration().runfilesEnabled()) {
String prefix = "";
if (!javaExecutable.isAbsolute()) {
@@ -514,6 +523,13 @@ public class JavaCommon {
}
}
+ /** Returns the string that the stub should use to determine the JVM binary (java) path */
+ public static String getJavaBinSubstitution(
+ RuleContext ruleContext, @Nullable Artifact launcher) {
+ return getJavaBinSubstitutionFromJavaExecutable(
+ ruleContext, getJavaExecutableForStub(ruleContext, launcher));
+ }
+
/**
* Heuristically determines the name of the primary Java class for this
* executable, based on the rule name and the "srcs" list.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
index e6f3b9b37e..9e2e719532 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
@@ -300,6 +300,10 @@ public interface JavaSemantics {
* <p>For example on Windows we use a double dispatch approach: the launcher is a batch file (and
* is created and returned by this method) which shells out to a shell script (the {@code
* executable} argument).
+ *
+ * <p>In Blaze, this method considers {@code javaExecutable} as a substitution that can be
+ * directly used to replace %javabin% in stub script, but in Bazel this method considers {@code
+ * javaExecutable} as a file path for the JVM binary (java).
*/
Artifact createStubAction(
RuleContext ruleContext,
@@ -310,6 +314,12 @@ public interface JavaSemantics {
String javaExecutable);
/**
+ * Returns true if {@code createStubAction} considers {@code javaExecutable} as a substitution.
+ * Returns false if {@code createStubAction} considers {@code javaExecutable} as a file path.
+ */
+ boolean isJavaExecutableSubstitution();
+
+ /**
* Optionally creates a file containing the relative classpaths within the runfiles tree. If
* {@link Optional#isPresent()}, then the caller should ensure the file appears in the runfiles.
*/