aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2017-07-28 10:22:57 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-07-31 16:05:56 +0200
commitc2c938ae2e75b5b881f06b18cce86dc87bae6fe6 (patch)
tree391b596c7ef66eeac9a0ef864f112bc6eb0f09c3
parent639bba946ea01f5cf0a2cdb51c46012a602814a1 (diff)
Apply native binary launcher to sh_binary
This change: 1. Added launcher to @bazel_tools If the host platform is Windows, we use a prebuilt launcher.exe , otherwise the launcher needs to be built with MSVC first. 2. Launching sh_binary using native launcher. Change-Id: I5a63135455057fbfe04ff0cce7ec7994ef0c347a PiperOrigin-RevId: 163442540
-rw-r--r--src/BUILD4
-rw-r--r--src/BUILD.tools18
-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
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java6
-rw-r--r--src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java4
-rw-r--r--src/test/py/bazel/BUILD4
-rw-r--r--src/test/py/bazel/launcher_test.py (renamed from src/test/py/bazel/launcher_script_test.py)80
-rw-r--r--tools/BUILD2
-rw-r--r--tools/launcher/BUILD11
-rw-r--r--tools/launcher/BUILD.tools13
17 files changed, 260 insertions, 90 deletions
diff --git a/src/BUILD b/src/BUILD
index 581b88bc91..041d6903d3 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -147,6 +147,7 @@ py_binary(
"//src/tools/android/java/com/google/devtools/build/android/idlclass:embedded_tools",
"//src/tools/android/java/com/google/devtools/build/android/dexer:embedded_tools",
"//src/tools/android/java/com/google/devtools/build/android/ziputils:embedded_tools",
+ "//src/tools/launcher:srcs",
"//src/tools/singlejar:embedded_tools",
"//src/main/cpp/util:embedded_tools",
"//src/main/native:embedded_tools",
@@ -179,12 +180,15 @@ py_binary(
# is resolved, use cc implementation of singlejar on windows
":windows": [
"//src/java_tools/singlejar:SingleJar_deploy.jar",
+ "//src/tools/launcher:launcher",
],
":windows_msys": [
"//src/java_tools/singlejar:SingleJar_deploy.jar",
+ "//src/tools/launcher:launcher",
],
":windows_msvc": [
"//src/java_tools/singlejar:SingleJar_deploy.jar",
+ "//src/tools/launcher:launcher",
],
":arm": [
"//src/java_tools/singlejar:SingleJar_deploy.jar",
diff --git a/src/BUILD.tools b/src/BUILD.tools
index d4e0a4164c..46a13e6e71 100644
--- a/src/BUILD.tools
+++ b/src/BUILD.tools
@@ -21,3 +21,21 @@ config_setting(
values = {"cpu": "x64_windows_msys"},
visibility = ["//visibility:public"],
)
+
+config_setting(
+ name = "host_windows",
+ values = {"host_cpu": "x64_windows"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "host_windows_msvc",
+ values = {"host_cpu": "x64_windows_msvc"},
+ visibility = ["//visibility:public"],
+)
+
+config_setting(
+ name = "host_windows_msys",
+ values = {"host_cpu": "x64_windows_msys"},
+ visibility = ["//visibility:public"],
+)
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:$=\$%"
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index a840876685..a8aaa9735d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -147,6 +147,12 @@ public final class BazelAnalysisMock extends AnalysisMock {
"package(default_visibility=['//visibility:public'])",
"exports_files(['precompile.py'])",
"cc_binary(name='zipper', srcs=['zip_main.cc'])");
+
+ config.create(
+ "/bazel_tools_workspace/tools/launcher/BUILD",
+ "package(default_visibility=['//visibility:public'])",
+ "cc_binary(name='launcher', srcs=['launcher_main.cc'])");
+
ccSupport().setup(config);
}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
index e8d3d5b5cd..5610d429bb 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleContextTest.java
@@ -642,7 +642,7 @@ public class SkylarkRuleContextTest extends SkylarkTestCase {
public void testGetExecutablePrerequisite() throws Exception {
SkylarkRuleContext ruleContext = createRuleContext("//foo:androidlib");
Object result = evalRuleContextCode(ruleContext, "ruleContext.executable._jarjar_bin");
- assertThat(((Artifact) result).getFilename()).matches("^jarjar_bin(\\.cmd){0,1}$");
+ assertThat(((Artifact) result).getFilename()).matches("^jarjar_bin(\\.exe){0,1}$");
}
@Test
@@ -659,7 +659,7 @@ public class SkylarkRuleContextTest extends SkylarkTestCase {
(SpawnAction)
Iterables.getOnlyElement(
ruleContext.getRuleContext().getAnalysisEnvironment().getRegisteredActions());
- assertThat(action.getCommandFilename()).matches("^.*/jarjar_bin(\\.cmd){0,1}$");
+ assertThat(action.getCommandFilename()).matches("^.*/jarjar_bin(\\.exe){0,1}$");
}
@Test
diff --git a/src/test/py/bazel/BUILD b/src/test/py/bazel/BUILD
index f744c21e1f..73bd4a383a 100644
--- a/src/test/py/bazel/BUILD
+++ b/src/test/py/bazel/BUILD
@@ -65,8 +65,8 @@ py_test(
)
py_test(
- name = "launcher_script_test",
+ name = "launcher_test",
size = "medium",
- srcs = ["launcher_script_test.py"],
+ srcs = ["launcher_test.py"],
deps = [":test_base"],
)
diff --git a/src/test/py/bazel/launcher_script_test.py b/src/test/py/bazel/launcher_test.py
index 690c7fb6d5..6c92dd7c0c 100644
--- a/src/test/py/bazel/launcher_script_test.py
+++ b/src/test/py/bazel/launcher_test.py
@@ -19,7 +19,7 @@ import unittest
from src.test.py.bazel import test_base
-class LauncherScriptTest(test_base.TestBase):
+class LauncherTest(test_base.TestBase):
def testJavaBinaryLauncher(self):
self.ScratchFile('WORKSPACE')
@@ -75,13 +75,9 @@ class LauncherScriptTest(test_base.TestBase):
# On Linux/MacOS, all sh_binary rules generate an output file with
# the same name as the rule, and this is a symlink to the file in
# `srcs`. (Bazel allows only one file in `sh_binary.srcs`.)
- # On Windows, if the rule's name and the srcs's name end with the
- # same extension, and this extension is one of ".exe", ".cmd", or
- # ".bat", then sh_binary makes a copy of the output file, with the
- # same name as the rule. Otherwise (if the rule's name doesn't end
- # with such an extension, or the extension of it doesn't match the
- # main file's) then Bazel creates a %{rulename}.cmd output which is
- # a similar launcher script to that generated by java_binary rules.
+ # On Windows, if the srcs's extension is one of ".exe", ".cmd", or
+ # ".bat", then Bazel requires the rule's name has the same
+ # extension, and the output file will be a copy of the source file.
'sh_binary(',
' name = "bin1.sh",',
' srcs = ["foo.sh"],',
@@ -112,30 +108,37 @@ class LauncherScriptTest(test_base.TestBase):
self.AssertExitCode(exit_code, 0, stderr)
bazel_bin = stdout[0]
- exit_code, _, stderr = self.RunBazel(['build', '//foo:all'])
+ exit_code, _, stderr = self.RunBazel(['build', '//foo:bin1.sh'])
self.AssertExitCode(exit_code, 0, stderr)
- bin1 = os.path.join(bazel_bin, 'foo', 'bin1.sh.cmd'
+ bin1 = os.path.join(bazel_bin, 'foo', 'bin1.sh.exe'
if self.IsWindows() else 'bin1.sh')
self.assertTrue(os.path.exists(bin1))
self.assertTrue(
os.path.isdir(os.path.join(bazel_bin, 'foo/bin1.sh.runfiles')))
+ exit_code, _, stderr = self.RunBazel(['build', '//foo:bin2.cmd'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
bin2 = os.path.join(bazel_bin, 'foo/bin2.cmd')
self.assertTrue(os.path.exists(bin2))
self.assertTrue(
os.path.isdir(os.path.join(bazel_bin, 'foo/bin2.cmd.runfiles')))
- bin3 = os.path.join(bazel_bin, 'foo', 'bin3.bat.cmd'
- if self.IsWindows() else 'bin3.bat')
- self.assertTrue(os.path.exists(bin3))
- self.assertTrue(
- os.path.isdir(os.path.join(bazel_bin, 'foo/bin3.bat.runfiles')))
+ exit_code, _, stderr = self.RunBazel(['build', '//foo:bin3.bat'])
+ if self.IsWindows():
+ self.AssertExitCode(exit_code, 1, stderr)
+ self.assertIn('target name extension should match source file extension.',
+ os.linesep.join(stderr))
+ else:
+ bin3 = os.path.join(bazel_bin, 'foo', 'bin3.bat')
+ self.assertTrue(os.path.exists(bin3))
+ self.assertTrue(
+ os.path.isdir(os.path.join(bazel_bin, 'foo/bin3.bat.runfiles')))
if self.IsWindows():
self.assertTrue(os.path.isfile(bin1))
self.assertTrue(os.path.isfile(bin2))
- self.assertTrue(os.path.isfile(bin3))
else:
self.assertTrue(os.path.islink(bin1))
self.assertTrue(os.path.islink(bin2))
@@ -148,9 +151,6 @@ class LauncherScriptTest(test_base.TestBase):
self.AssertRunfilesManifestContains(
os.path.join(bazel_bin, 'foo/bin2.cmd.runfiles/MANIFEST'),
'__main__/bar/bar.txt')
- self.AssertRunfilesManifestContains(
- os.path.join(bazel_bin, 'foo/bin3.bat.runfiles/MANIFEST'),
- '__main__/bar/bar.txt')
else:
self.assertTrue(
os.path.islink(
@@ -174,9 +174,43 @@ class LauncherScriptTest(test_base.TestBase):
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'hello batch')
- exit_code, stdout, stderr = self.RunProgram([bin3])
- self.AssertExitCode(exit_code, 0, stderr)
- self.assertEqual(stdout[0], 'hello batch')
+ def testShBinaryArgumentPassing(self):
+ self.ScratchFile('WORKSPACE')
+ self.ScratchFile('foo/BUILD', [
+ 'sh_binary(',
+ ' name = "bin",',
+ ' srcs = ["bin.sh"],',
+ ')',
+ ])
+ foo_sh = self.ScratchFile('foo/bin.sh', [
+ '#!/bin/bash',
+ '# Store arguments in a array',
+ 'args=("$@")',
+ '# Get the number of arguments',
+ 'N=${#args[@]}',
+ '# Echo each argument',
+ 'for (( i=0;i<$N;i++)); do',
+ ' echo ${args[${i}]}',
+ 'done',
+ ])
+ os.chmod(foo_sh, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
+
+ exit_code, stdout, stderr = self.RunBazel(['info', 'bazel-bin'])
+ self.AssertExitCode(exit_code, 0, stderr)
+ bazel_bin = stdout[0]
+
+ exit_code, _, stderr = self.RunBazel(['build', '//foo:bin'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ bin1 = os.path.join(bazel_bin, 'foo', 'bin.exe'
+ if self.IsWindows() else 'bin')
+ self.assertTrue(os.path.exists(bin1))
+ self.assertTrue(os.path.isdir(os.path.join(bazel_bin, 'foo/bin.runfiles')))
+
+ arguments = ['a', 'a b', '"b"', 'C:\\a\\b\\', '"C:\\a b\\c\\"']
+ exit_code, stdout, stderr = self.RunProgram([bin1] + arguments)
+ self.AssertExitCode(exit_code, 0, stderr)
+ self.assertEqual(stdout, arguments)
def testPyBinaryLauncher(self):
self.ScratchFile('WORKSPACE')
@@ -220,7 +254,7 @@ class LauncherScriptTest(test_base.TestBase):
' with open(sys.argv[1], "w") as f:',
' f.write("Hello World!")',
'else:',
- ' print "Hello World!"',
+ ' print("Hello World!")',
])
self.ScratchFile('bar/BUILD', ['exports_files(["bar.txt"])'])
self.ScratchFile('bar/bar.txt', ['hello'])
diff --git a/tools/BUILD b/tools/BUILD
index 9f9052ea10..49cd6290a7 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -19,6 +19,7 @@ filegroup(
"//tools/coverage:srcs",
"//tools/ide:srcs",
"//tools/jdk:srcs",
+ "//tools/launcher:srcs",
"//tools/platforms:srcs",
"//tools/genrule:srcs",
"//tools/cpp:srcs",
@@ -50,6 +51,7 @@ filegroup(
"//tools/j2objc:srcs",
"//tools/jdk:package-srcs",
"//tools/jdk:srcs",
+ "//tools/launcher:srcs",
"//tools/platforms:package-srcs",
"//tools/objc:srcs",
"//tools/python:srcs",
diff --git a/tools/launcher/BUILD b/tools/launcher/BUILD
new file mode 100644
index 0000000000..0158b25589
--- /dev/null
+++ b/tools/launcher/BUILD
@@ -0,0 +1,11 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+)
+
+alias(
+ name = "launcher",
+ actual = "//src/tools/launcher:launcher",
+)
diff --git a/tools/launcher/BUILD.tools b/tools/launcher/BUILD.tools
new file mode 100644
index 0000000000..8679c1a32f
--- /dev/null
+++ b/tools/launcher/BUILD.tools
@@ -0,0 +1,13 @@
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+ name = "launcher",
+ srcs = select({
+ "//src:host_windows": ["launcher.exe"],
+ "//src:host_windows_msvc": ["launcher.exe"],
+ "//src:host_windows_msys": ["launcher.exe"],
+ "//conditions:default": [
+ "//src/tools/launcher:launcher",
+ ],
+ }),
+)