aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/RuleDefinitionEnvironment.java12
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java127
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_stub_template_windows.txt33
8 files changed, 145 insertions, 63 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 291bb98fb6..6236d6b643 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -732,7 +732,6 @@ java_library(
"bazel/rules/java/java_stub_template.txt",
"bazel/rules/java/java_stub_template_windows.txt",
"bazel/rules/python/python_stub_template.txt",
- "bazel/rules/sh/sh_stub_template_windows.txt",
],
deps = [
":bazel",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 42826523e1..2d13abd9ec 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -227,11 +227,19 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
registeredSkylarkProviders = ImmutableBiMap.builder();
private Map<String, String> platformRegexps = new TreeMap<>();
+ // TODO(pcloudy): Remove this field after Bazel rule definitions are not used internally.
+ private String nativeLauncherLabel;
+
public Builder setProductName(String productName) {
this.productName = productName;
return this;
}
+ public Builder setNativeLauncherLabel(String label) {
+ this.nativeLauncherLabel = label;
+ return this;
+ }
+
public void addWorkspaceFilePrefix(String contents) {
defaultWorkspaceFilePrefix.append(contents);
}
@@ -455,6 +463,14 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
}
@Override
+ public Label getLauncherLabel() {
+ if (nativeLauncherLabel == null) {
+ return null;
+ }
+ return getToolsLabel(nativeLauncherLabel);
+ }
+
+ @Override
public String getToolsRepository() {
return toolsRepository;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinitionEnvironment.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinitionEnvironment.java
index 5880e954dd..e388b86284 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinitionEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleDefinitionEnvironment.java
@@ -16,6 +16,8 @@ package com.google.devtools.build.lib.analysis;
import com.google.devtools.build.lib.cmdline.Label;
+import javax.annotation.Nullable;
+
/**
* Encapsulates the services available for implementors of the {@link RuleDefinition}
* interface.
@@ -37,4 +39,14 @@ public interface RuleDefinitionEnvironment {
* Returns the tools repository prefix.
*/
String getToolsRepository();
+
+ /**
+ * Returns the label for Bazel binary launcher.
+ * In bazel, it should be //tools/launcher:launcher, otherwise it should be null.
+ *
+ * TODO(pcloudy): Remove this after Bazel rule definitions are not used internally anymore.
+ * Related bug b/63658220
+ */
+ @Nullable
+ Label getLauncherLabel();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index e88ff5af88..e93a154d44 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -213,6 +213,7 @@ public class BazelRuleClassProvider {
.setProductName("bazel")
.setConfigurationCollectionFactory(new BazelConfigurationCollection())
.setPrelude("//tools/build_rules:prelude_bazel")
+ .setNativeLauncherLabel("//tools/launcher:launcher")
.setRunfilesPrefix(Label.DEFAULT_REPOSITORY_DIRECTORY)
.setPrerequisiteValidator(new BazelPrerequisiteValidator());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
index 02bcffae87..7ba0859968 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
@@ -13,10 +13,15 @@
// limitations under the License.
package com.google.devtools.build.lib.bazel.rules.sh;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses.ShRule;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder;
@@ -26,6 +31,10 @@ import com.google.devtools.build.lib.packages.RuleClass.Builder;
public final class BazelShBinaryRule implements RuleDefinition {
@Override
public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ Label launcher = environment.getLauncherLabel();
+ if (launcher != null) {
+ builder.add(attr("$launcher", LABEL).cfg(HOST).value(launcher));
+ }
return builder.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
index aed6ef5d10..8001a4ecd2 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
@@ -13,10 +13,15 @@
// limitations under the License.
package com.google.devtools.build.lib.bazel.rules.sh;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+
import com.google.devtools.build.lib.analysis.BaseRuleClasses;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses.ShRule;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder;
import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
@@ -27,6 +32,10 @@ import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
public final class BazelShTestRule implements RuleDefinition {
@Override
public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ Label launcher = environment.getLauncherLabel();
+ if (launcher != null) {
+ builder.add(attr("$launcher", LABEL).cfg(HOST).value(launcher));
+ }
return builder.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
index 66b0ec4a1d..47a15dec3f 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
@@ -13,7 +13,11 @@
// limitations under the License.
package com.google.devtools.build.lib.bazel.rules.sh;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.ByteSource;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
@@ -22,23 +26,23 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
import com.google.devtools.build.lib.analysis.RunfilesSupport;
+import com.google.devtools.build.lib.analysis.actions.BinaryFileWriteAction;
import com.google.devtools.build.lib.analysis.actions.ExecutableSymlinkAction;
-import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
-import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
-import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Template;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.bazel.rules.BazelConfiguration;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.util.OS;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
/**
* Implementation for the sh_binary rule.
*/
public class ShBinary implements RuleConfiguredTargetFactory {
- private static final Template STUB_SCRIPT_WINDOWS =
- Template.forResource(ShBinary.class, "sh_stub_template_windows.txt");
@Override
public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
@@ -68,7 +72,7 @@ public class ShBinary implements RuleConfiguredTargetFactory {
ruleContext.getConfiguration().legacyExternalRunfiles());
Artifact mainExecutable =
- (OS.getCurrent() == OS.WINDOWS) ? wrapperForWindows(ruleContext, symlink, src) : symlink;
+ (OS.getCurrent() == OS.WINDOWS) ? launcherForWindows(ruleContext, symlink, src) : symlink;
if (symlink != mainExecutable) {
filesToBuildBuilder.add(mainExecutable);
runfilesBuilder.addArtifact(symlink);
@@ -92,33 +96,98 @@ public class ShBinary implements RuleConfiguredTargetFactory {
.build();
}
- private static Artifact wrapperForWindows(
- RuleContext ruleContext, Artifact primaryOutput, Artifact mainFile) {
- if (primaryOutput.getFilename().endsWith(".exe")
- || primaryOutput.getFilename().endsWith(".bat")
- || primaryOutput.getFilename().endsWith(".cmd")) {
- String suffix =
- primaryOutput.getFilename().substring(primaryOutput.getFilename().length() - 4);
- if (mainFile.getFilename().endsWith(suffix)) {
+ // Write launch info to buffer, return the number of bytes written.
+ private static int writeLaunchInfo(ByteArrayOutputStream buffer, String key, String value)
+ throws IOException {
+ byte[] keyBytes = key.getBytes(UTF_8);
+ byte[] valueBytes = value.getBytes(UTF_8);
+ buffer.write(keyBytes);
+ buffer.write('=');
+ buffer.write(valueBytes);
+ buffer.write('\0');
+ return keyBytes.length + valueBytes.length + 2;
+ }
+
+ private static boolean isWindowsExecutable(Artifact artifact) {
+ return artifact.getExtension().equals("exe")
+ || artifact.getExtension().equals("cmd")
+ || artifact.getExtension().equals("bat");
+ }
+
+ private static Artifact launcherForWindows(
+ RuleContext ruleContext, Artifact primaryOutput, Artifact mainFile)
+ throws RuleErrorException {
+ if (isWindowsExecutable(mainFile)) {
+ // If the extensions don't match, we should always respect mainFile's extension.
+ if (mainFile.getExtension().equals(primaryOutput.getExtension())) {
return primaryOutput;
+ } else {
+ ruleContext.ruleError(
+ "Source file is a Windows executable file,"
+ + " target name extension should match source file extension");
+ throw new RuleErrorException();
}
}
- Artifact wrapper =
- ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".cmd");
+ // The launcher file consists of a base launcher binary and the launch information appended to
+ // the binary. The length of launch info is a signed 64-bit integer written at the end of
+ // the binary in little endian.
+ Artifact launcher = ruleContext.getPrerequisiteArtifact("$launcher", Mode.HOST);
+ Artifact bashLauncher =
+ ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".exe");
+ Artifact launchInfoFile =
+ ruleContext.getRelatedArtifact(bashLauncher.getRootRelativePath(), ".launch_info");
+
+ ByteArrayOutputStream launchInfo = new ByteArrayOutputStream();
+ Long dataSize = 0L;
+ try {
+ dataSize += writeLaunchInfo(launchInfo, "binary_type", "Bash");
+ dataSize += writeLaunchInfo(launchInfo, "workspace_name", ruleContext.getWorkspaceName());
+ dataSize +=
+ writeLaunchInfo(
+ launchInfo,
+ "bash_bin_path",
+ ruleContext
+ .getFragment(BazelConfiguration.class)
+ .getShellExecutable()
+ .getPathString());
+ dataSize += writeLaunchInfo(launchInfo, "bash_main_file", mainFile.getRunfilesPathString());
+
+ ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
+ // All Windows versions are little endian.
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ buffer.putLong(dataSize);
+
+ launchInfo.write(buffer.array());
+ } catch (IOException e) {
+ ruleContext.ruleError(e.getMessage());
+ throw new RuleErrorException();
+ }
+
ruleContext.registerAction(
- new TemplateExpansionAction(
+ new BinaryFileWriteAction(
ruleContext.getActionOwner(),
- wrapper,
- STUB_SCRIPT_WINDOWS,
- ImmutableList.of(
- Substitution.of(
- "%bash_exe_path%",
- ruleContext
- .getFragment(BazelConfiguration.class)
- .getShellExecutable()
- .getPathString())),
- true));
- return wrapper;
+ launchInfoFile,
+ ByteSource.wrap(launchInfo.toByteArray()),
+ /*makeExecutable=*/ false));
+ String path = ruleContext.getConfiguration().getActionEnvironment().getFixedEnv().get("PATH");
+ ruleContext.registerAction(
+ new SpawnAction.Builder()
+ .addInput(launcher)
+ .addInput(launchInfoFile)
+ .addOutput(bashLauncher)
+ .setShellCommand(
+ "cmd.exe /c \"copy /Y /B "
+ + launcher.getExecPathString().replace('/', '\\')
+ + "+"
+ + launchInfoFile.getExecPathString().replace('/', '\\')
+ + " "
+ + bashLauncher.getExecPathString().replace('/', '\\')
+ + " > nul\"")
+ .setEnvironment(ImmutableMap.of("PATH", path))
+ .setMnemonic("BuildBashLauncher")
+ .build(ruleContext));
+
+ return bashLauncher;
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_stub_template_windows.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_stub_template_windows.txt
deleted file mode 100644
index 5c30e7fb8c..0000000000
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/sh_stub_template_windows.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-@rem Copyright 2016 The Bazel Authors. All rights reserved.
-@rem
-@rem Licensed under the Apache License, Version 2.0 (the "License");
-@rem you may not use this file except in compliance with the License.
-@rem You may obtain a copy of the License at
-@rem
-@rem http://www.apache.org/licenses/LICENSE-2.0
-@rem
-@rem Unless required by applicable law or agreed to in writing, software
-@rem distributed under the License is distributed on an "AS IS" BASIS,
-@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-@rem See the License for the specific language governing permissions and
-@rem limitations under the License.
-@rem
-@rem This script was generated from sh_stub_template_windows.txt. Please
-@rem don't edit it directly.
-@rem See the header comments in the accompanying shell script (same path as that
-@rem of this file, minus the ".cmd" extension) for available command line flags.
-
-@echo off
-SETLOCAL ENABLEEXTENSIONS
-
-set bash_path=%bash_exe_path%
-
-rem launcher=${$0%.cmd}
-set launcher=%~dp0%~n0
-
-set sh_path=%launcher:\=/%
-
-rem replaces $ with \$ in $*, then puts it on the command line
-rem Cribbed from here: http://ss64.com/nt/syntax-replace.html
-set all_args=%*
-call %bash_path% -c "'%sh_path%' %all_args:$=\$%"