aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/bazel/rules
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/bazel/rules')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java73
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfiguration.java70
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java235
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java272
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java159
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java49
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java48
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java50
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcBinary.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibrary.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTest.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java422
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java52
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java77
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRule.java219
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleAction.java62
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinary.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java51
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBuildInfoFactory.java61
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImport.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java53
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibrary.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java51
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPlugin.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java173
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java341
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTest.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java54
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt195
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTest.java57
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java69
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java41
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java113
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java101
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java44
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java82
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShTest.java53
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java113
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java91
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java85
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java127
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java135
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java34
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceConfiguredTargetFactory.java37
47 files changed, 4300 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java
new file mode 100644
index 0000000000..a1b27fee82
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelBaseRuleClasses.java
@@ -0,0 +1,73 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LICENSE;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * The foundational rule templates to help in real rule construction. Only attributes truly common
+ * to all rules go in here. Attributes such as "out", "outs", "src" and "srcs" exhibit enough
+ * variation that we declare them explicitly for each rule. This leads to stricter error checking
+ * and prevents users from inadvertently using an attribute that doesn't actually do anything.
+ */
+public class BazelBaseRuleClasses {
+ public static final ImmutableSet<String> ALLOWED_RULE_CLASSES =
+ ImmutableSet.of("filegroup", "genrule", "Fileset");
+
+ /**
+ * A base rule for all binary rules.
+ */
+ @BlazeRule(name = "$binary_base_rule",
+ type = RuleClassType.ABSTRACT)
+ public static final class BinaryBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("args", STRING_LIST)
+ .nonconfigurable("policy decision: should be consistent across configurations"))
+ .add(attr("output_licenses", LICENSE))
+ .add(attr("$is_executable", BOOLEAN).value(true)
+ .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target"))
+ .build();
+ }
+ }
+
+ /**
+ * Rule class for rules in error.
+ */
+ @BlazeRule(name = "$error_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { BaseRuleClasses.BaseRule.class })
+ public static final class ErrorRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .publicByDefault()
+ .build();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfiguration.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfiguration.java
new file mode 100644
index 0000000000..63aa4e3d2e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfiguration.java
@@ -0,0 +1,70 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
+import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * Bazel-specific configuration fragment.
+ */
+public class BazelConfiguration extends Fragment {
+ /**
+ * Loader for Google-specific settings.
+ */
+ public static class Loader implements ConfigurationFragmentFactory {
+ @Override
+ public Fragment create(ConfigurationEnvironment env, BuildOptions buildOptions)
+ throws InvalidConfigurationException {
+ return new BazelConfiguration();
+ }
+
+ @Override
+ public Class<? extends Fragment> creates() {
+ return BazelConfiguration.class;
+ }
+ }
+
+ public BazelConfiguration() {
+ }
+
+ @Override
+ public String getName() {
+ return "Bazel";
+ }
+
+ @Override
+ public String cacheKey() {
+ return "";
+ }
+
+ @Override
+ public void defineExecutables(ImmutableMap.Builder<String, PathFragment> builder) {
+ if (OS.getCurrent() == OS.WINDOWS) {
+ String path = System.getenv("BAZEL_SH");
+ if (path != null) {
+ builder.put("sh", new PathFragment(path));
+ return;
+ }
+ }
+ builder.put("sh", new PathFragment("/bin/bash"));
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java
new file mode 100644
index 0000000000..1472b43043
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelConfigurationCollection.java
@@ -0,0 +1,235 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Table;
+import com.google.devtools.build.lib.analysis.ConfigurationCollectionFactory;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection.ConfigurationHolder;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection.Transitions;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationKey;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.ConfigurationFactory;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.config.PackageProviderForConfigurations;
+import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses.CppTransition;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
+import com.google.devtools.build.lib.packages.Attribute.Transition;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.syntax.Label;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * Configuration collection used by the rules Bazel knows.
+ */
+public class BazelConfigurationCollection implements ConfigurationCollectionFactory {
+ @Override
+ @Nullable
+ public BuildConfiguration createConfigurations(
+ ConfigurationFactory configurationFactory,
+ PackageProviderForConfigurations loadedPackageProvider,
+ BuildOptions buildOptions,
+ Map<String, String> clientEnv,
+ EventHandler errorEventListener,
+ boolean performSanityCheck) throws InvalidConfigurationException {
+
+ // We cache all the related configurations for this target configuration in a cache that is
+ // dropped at the end of this method call. We instead rely on the cache for entire collections
+ // for caching the target and related configurations, and on a dedicated host configuration
+ // cache for the host configuration.
+ Cache<String, BuildConfiguration> cache =
+ CacheBuilder.newBuilder().<String, BuildConfiguration>build();
+
+ // Target configuration
+ BuildConfiguration targetConfiguration = configurationFactory.getConfiguration(
+ loadedPackageProvider, buildOptions, clientEnv, false, cache);
+ if (targetConfiguration == null) {
+ return null;
+ }
+
+ BuildConfiguration dataConfiguration = targetConfiguration;
+
+ // Host configuration
+ // Note that this passes in the dataConfiguration, not the target
+ // configuration. This is intentional.
+ BuildConfiguration hostConfiguration = getHostConfigurationFromRequest(configurationFactory,
+ loadedPackageProvider, clientEnv, dataConfiguration, buildOptions);
+ if (hostConfiguration == null) {
+ return null;
+ }
+
+ // Sanity check that the implicit labels are all in the transitive closure of explicit ones.
+ // This also registers all targets in the cache entry and validates them on subsequent requests.
+ Set<Label> reachableLabels = new HashSet<>();
+ if (performSanityCheck) {
+ // We allow the package provider to be null for testing.
+ for (Label label : buildOptions.getAllLabels().values()) {
+ try {
+ collectTransitiveClosure(loadedPackageProvider, reachableLabels, label);
+ } catch (NoSuchThingException e) {
+ // We've loaded the transitive closure of the labels-to-load above, and made sure that
+ // there are no errors loading it, so this can't happen.
+ throw new IllegalStateException(e);
+ }
+ }
+ sanityCheckImplicitLabels(reachableLabels, targetConfiguration);
+ sanityCheckImplicitLabels(reachableLabels, hostConfiguration);
+ }
+
+ BuildConfiguration result = setupTransitions(
+ targetConfiguration, dataConfiguration, hostConfiguration);
+ result.reportInvalidOptions(errorEventListener);
+ return result;
+ }
+
+ /**
+ * Gets the correct host configuration for this build. The behavior
+ * depends on the value of the --distinct_host_configuration flag.
+ *
+ * <p>With --distinct_host_configuration=false, we use identical configurations
+ * for the host and target, and you can ignore everything below. But please
+ * note: if you're cross-compiling for k8 on a piii machine, your build will
+ * fail. This is a stopgap measure.
+ *
+ * <p>Currently, every build is (in effect) a cross-compile, in the strict
+ * sense that host and target configurations are unequal, thus we do not
+ * issue a "cross-compiling" warning. (Perhaps we should?)
+ * *
+ * @param requestConfig the requested target (not host!) configuration for
+ * this build.
+ * @param buildOptions the configuration options used for the target configuration
+ */
+ @Nullable
+ private BuildConfiguration getHostConfigurationFromRequest(
+ ConfigurationFactory configurationFactory,
+ PackageProviderForConfigurations loadedPackageProvider, Map<String, String> clientEnv,
+ BuildConfiguration requestConfig, BuildOptions buildOptions)
+ throws InvalidConfigurationException {
+ BuildConfiguration.Options commonOptions = buildOptions.get(BuildConfiguration.Options.class);
+ if (!commonOptions.useDistinctHostConfiguration) {
+ return requestConfig;
+ } else {
+ BuildConfiguration hostConfig = configurationFactory.getHostConfiguration(
+ loadedPackageProvider, clientEnv, buildOptions, /*fallback=*/false);
+ if (hostConfig == null) {
+ return null;
+ }
+ return hostConfig;
+ }
+ }
+
+ static BuildConfiguration setupTransitions(BuildConfiguration targetConfiguration,
+ BuildConfiguration dataConfiguration, BuildConfiguration hostConfiguration) {
+ Set<BuildConfiguration> allConfigurations = ImmutableSet.of(targetConfiguration,
+ dataConfiguration, hostConfiguration);
+
+ Table<BuildConfiguration, Transition, ConfigurationHolder> transitionBuilder =
+ HashBasedTable.create();
+ for (BuildConfiguration from : allConfigurations) {
+ for (ConfigurationTransition transition : ConfigurationTransition.values()) {
+ BuildConfiguration to;
+ if (transition == ConfigurationTransition.HOST) {
+ to = hostConfiguration;
+ } else if (transition == ConfigurationTransition.DATA && from == targetConfiguration) {
+ to = dataConfiguration;
+ } else {
+ to = from;
+ }
+ transitionBuilder.put(from, transition, new ConfigurationHolder(to));
+ }
+ }
+
+ // TODO(bazel-team): This makes LIPO totally not work. Just a band-aid until we get around to
+ // implementing a way for the C++ rules to contribute this transition to the configuration
+ // collection.
+ for (BuildConfiguration config : allConfigurations) {
+ transitionBuilder.put(config, CppTransition.LIPO_COLLECTOR, new ConfigurationHolder(config));
+ transitionBuilder.put(config, CppTransition.TARGET_CONFIG_FOR_LIPO,
+ new ConfigurationHolder(config.isHostConfiguration() ? null : config));
+ }
+
+ for (BuildConfiguration config : allConfigurations) {
+ Transitions outgoingTransitions =
+ new BuildConfigurationCollection.Transitions(config, transitionBuilder.row(config));
+ // We allow host configurations to be shared between target configurations. In that case, the
+ // transitions may already be set.
+ // TODO(bazel-team): Check that the transitions are identical, or even better, change the
+ // code to set the host configuration transitions before we even create the target
+ // configuration.
+ if (config.isHostConfiguration() && config.getTransitions() != null) {
+ continue;
+ }
+ config.setConfigurationTransitions(outgoingTransitions);
+ }
+
+ return targetConfiguration;
+ }
+
+ /**
+ * Checks that the implicit labels are reachable from the loaded labels. The loaded labels are
+ * those returned from {@link BuildConfigurationKey#getLabelsToLoadUnconditionally()}, and the
+ * implicit ones are those that need to be available for late-bound attributes.
+ */
+ private void sanityCheckImplicitLabels(Collection<Label> reachableLabels,
+ BuildConfiguration config) throws InvalidConfigurationException {
+ for (Map.Entry<String, Label> entry : config.getImplicitLabels().entries()) {
+ if (!reachableLabels.contains(entry.getValue())) {
+ throw new InvalidConfigurationException("The required " + entry.getKey()
+ + " target is not transitively reachable from a command-line option: '"
+ + entry.getValue() + "'");
+ }
+ }
+ }
+
+ private void collectTransitiveClosure(PackageProviderForConfigurations loadedPackageProvider,
+ Set<Label> reachableLabels, Label from) throws NoSuchThingException {
+ if (!reachableLabels.add(from)) {
+ return;
+ }
+ Target fromTarget = loadedPackageProvider.getLoadedTarget(from);
+ if (fromTarget instanceof Rule) {
+ Rule rule = (Rule) fromTarget;
+ if (rule.getRuleClassObject().hasAttr("srcs", Type.LABEL_LIST)) {
+ // TODO(bazel-team): refine this. This visits "srcs" reachable under *any* configuration,
+ // not necessarily the configuration actually applied to the rule. We should correlate the
+ // two. However, doing so requires faithfully reflecting the configuration transitions that
+ // might happen as we traverse the dependency chain.
+ for (List<Label> labelsForConfiguration :
+ AggregatingAttributeMapper.of(rule).visitAttribute("srcs", Type.LABEL_LIST)) {
+ for (Label label : labelsForConfiguration) {
+ collectTransitiveClosure(loadedPackageProvider, reachableLabels, label);
+ }
+ }
+ }
+ }
+ }
+}
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
new file mode 100644
index 0000000000..1280bdb9a7
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -0,0 +1,272 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider.PrerequisiteValidator;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.ConfigRuleClasses;
+import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
+import com.google.devtools.build.lib.analysis.config.FragmentOptions;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.constraints.EnvironmentRule;
+import com.google.devtools.build.lib.bazel.rules.common.BazelActionListenerRule;
+import com.google.devtools.build.lib.bazel.rules.common.BazelExtraActionRule;
+import com.google.devtools.build.lib.bazel.rules.common.BazelFilegroupRule;
+import com.google.devtools.build.lib.bazel.rules.common.BazelTestSuiteRule;
+import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.genrule.BazelGenRuleRule;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaBinaryRule;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaBuildInfoFactory;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaImportRule;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaLibraryRule;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaPluginRule;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaTestRule;
+import com.google.devtools.build.lib.bazel.rules.objc.BazelIosTestRule;
+import com.google.devtools.build.lib.bazel.rules.sh.BazelShBinaryRule;
+import com.google.devtools.build.lib.bazel.rules.sh.BazelShLibraryRule;
+import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.sh.BazelShTestRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.HttpArchiveRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.HttpJarRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.LocalRepositoryRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.MavenJarRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.PackageGroup;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.rules.cpp.CcToolchainRule;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppConfigurationLoader;
+import com.google.devtools.build.lib.rules.cpp.CppOptions;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
+import com.google.devtools.build.lib.rules.java.JavaConfigurationLoader;
+import com.google.devtools.build.lib.rules.java.JavaCpuSupplier;
+import com.google.devtools.build.lib.rules.java.JavaImportBaseRule;
+import com.google.devtools.build.lib.rules.java.JavaOptions;
+import com.google.devtools.build.lib.rules.java.JavaToolchainRule;
+import com.google.devtools.build.lib.rules.java.Jvm;
+import com.google.devtools.build.lib.rules.java.JvmConfigurationLoader;
+import com.google.devtools.build.lib.rules.objc.IosApplicationRule;
+import com.google.devtools.build.lib.rules.objc.IosDeviceRule;
+import com.google.devtools.build.lib.rules.objc.ObjcBinaryRule;
+import com.google.devtools.build.lib.rules.objc.ObjcBundleLibraryRule;
+import com.google.devtools.build.lib.rules.objc.ObjcBundleRule;
+import com.google.devtools.build.lib.rules.objc.ObjcCommandLineOptions;
+import com.google.devtools.build.lib.rules.objc.ObjcConfigurationLoader;
+import com.google.devtools.build.lib.rules.objc.ObjcFrameworkRule;
+import com.google.devtools.build.lib.rules.objc.ObjcImportRule;
+import com.google.devtools.build.lib.rules.objc.ObjcLibraryRule;
+import com.google.devtools.build.lib.rules.objc.ObjcOptionsRule;
+import com.google.devtools.build.lib.rules.objc.ObjcProtoLibraryRule;
+import com.google.devtools.build.lib.rules.objc.ObjcRuleClasses;
+import com.google.devtools.build.lib.rules.objc.ObjcXcodeprojRule;
+import com.google.devtools.build.lib.rules.workspace.BindRule;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.syntax.SkylarkType;
+
+/**
+ * A rule class provider implementing the rules Bazel knows.
+ */
+public class BazelRuleClassProvider {
+
+ /**
+ * Used by the build encyclopedia generator.
+ */
+ public static ConfiguredRuleClassProvider create() {
+ ConfiguredRuleClassProvider.Builder builder =
+ new ConfiguredRuleClassProvider.Builder();
+ setup(builder);
+ return builder.build();
+ }
+
+ public static final JavaCpuSupplier JAVA_CPU_SUPPLIER = new JavaCpuSupplier() {
+ @Override
+ public String getJavaCpu(BuildOptions buildOptions, ConfigurationEnvironment env)
+ throws InvalidConfigurationException {
+ JavaOptions javaOptions = buildOptions.get(JavaOptions.class);
+ return javaOptions.javaCpu == null ? "default" : javaOptions.javaCpu;
+ }
+ };
+
+ private static class BazelPrerequisiteValidator implements PrerequisiteValidator {
+ @Override
+ public void validate(RuleContext.Builder context,
+ ConfiguredTarget prerequisite, Attribute attribute) {
+ validateDirectPrerequisiteVisibility(context, prerequisite, attribute.getName());
+ }
+
+ private void validateDirectPrerequisiteVisibility(
+ RuleContext.Builder context, ConfiguredTarget prerequisite, String attrName) {
+ Rule rule = context.getRule();
+ Target prerequisiteTarget = prerequisite.getTarget();
+ Label prerequisiteLabel = prerequisiteTarget.getLabel();
+ // We don't check the visibility of late-bound attributes, because it would break some
+ // features.
+ if (!context.getRule().getLabel().getPackageName().equals(
+ prerequisite.getTarget().getLabel().getPackageName())
+ && !context.isVisible(prerequisite)) {
+ if (!context.getConfiguration().checkVisibility()) {
+ context.ruleWarning(String.format("Target '%s' violates visibility of target "
+ + "'%s'. Continuing because --nocheck_visibility is active",
+ rule.getLabel(), prerequisiteLabel));
+ } else {
+ // Oddly enough, we use reportError rather than ruleError here.
+ context.reportError(rule.getLocation(),
+ String.format("Target '%s' is not visible from target '%s'. Check "
+ + "the visibility declaration of the former target if you think "
+ + "the dependency is legitimate",
+ prerequisiteLabel, rule.getLabel()));
+ }
+ }
+
+ if (prerequisiteTarget instanceof PackageGroup) {
+ if (!attrName.equals("visibility")) {
+ context.reportError(rule.getAttributeLocation(attrName),
+ "in " + attrName + " attribute of " + rule.getRuleClass()
+ + " rule " + rule.getLabel() + ": package group '"
+ + prerequisiteLabel + "' is misplaced here "
+ + "(they are only allowed in the visibility attribute)");
+ }
+ }
+ }
+ }
+
+ /**
+ * List of all build option classes in Blaze.
+ */
+ // TODO(bazel-team): make this private, remove from tests, then BuildOptions.of can be merged
+ // into RuleClassProvider.
+ @VisibleForTesting
+ @SuppressWarnings("unchecked")
+ public static final ImmutableList<Class<? extends FragmentOptions>> BUILD_OPTIONS =
+ ImmutableList.of(
+ BuildConfiguration.Options.class,
+ CppOptions.class,
+ JavaOptions.class,
+ ObjcCommandLineOptions.class
+ );
+
+ /**
+ * Java objects accessible from Skylark rule implementations using this module.
+ */
+ private static final ImmutableMap<String, SkylarkType> skylarkBuiltinJavaObects =
+ ImmutableMap.of(
+ "jvm", SkylarkType.of(Jvm.class),
+ "java_configuration", SkylarkType.of(JavaConfiguration.class),
+ "cpp", SkylarkType.of(CppConfiguration.class));
+
+ public static void setup(ConfiguredRuleClassProvider.Builder builder) {
+ builder
+ .addBuildInfoFactory(new BazelJavaBuildInfoFactory())
+ .setConfigurationCollectionFactory(new BazelConfigurationCollection())
+ .setPrerequisiteValidator(new BazelPrerequisiteValidator())
+ .setSkylarkAccessibleJavaClasses(skylarkBuiltinJavaObects);
+
+ for (Class<? extends FragmentOptions> fragmentOptions : BUILD_OPTIONS) {
+ builder.addConfigurationOptions(fragmentOptions);
+ }
+
+ builder.addRuleDefinition(BaseRuleClasses.BaseRule.class);
+ builder.addRuleDefinition(BaseRuleClasses.RuleBase.class);
+ builder.addRuleDefinition(BazelBaseRuleClasses.BinaryBaseRule.class);
+ builder.addRuleDefinition(BaseRuleClasses.TestBaseRule.class);
+ builder.addRuleDefinition(BazelBaseRuleClasses.ErrorRule.class);
+
+ builder.addRuleDefinition(EnvironmentRule.class);
+
+ builder.addRuleDefinition(ConfigRuleClasses.ConfigBaseRule.class);
+ builder.addRuleDefinition(ConfigRuleClasses.ConfigSettingRule.class);
+
+ builder.addRuleDefinition(BazelFilegroupRule.class);
+ builder.addRuleDefinition(BazelTestSuiteRule.class);
+ builder.addRuleDefinition(BazelGenRuleRule.class);
+
+ builder.addRuleDefinition(BazelShRuleClasses.ShRule.class);
+ builder.addRuleDefinition(BazelShLibraryRule.class);
+ builder.addRuleDefinition(BazelShBinaryRule.class);
+ builder.addRuleDefinition(BazelShTestRule.class);
+
+ builder.addRuleDefinition(CcToolchainRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcLinkingRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcDeclRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcBaseRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcBinaryBaseRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcBinaryRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcTestRule.class);
+
+ builder.addRuleDefinition(BazelCppRuleClasses.CcLibraryBaseRule.class);
+ builder.addRuleDefinition(BazelCppRuleClasses.CcLibraryRule.class);
+
+
+ builder.addRuleDefinition(BazelJavaRuleClasses.BaseJavaBinaryRule.class);
+ builder.addRuleDefinition(BazelJavaRuleClasses.IjarBaseRule.class);
+ builder.addRuleDefinition(BazelJavaRuleClasses.JavaBaseRule.class);
+ builder.addRuleDefinition(JavaImportBaseRule.class);
+ builder.addRuleDefinition(BazelJavaRuleClasses.JavaRule.class);
+ builder.addRuleDefinition(BazelJavaBinaryRule.class);
+ builder.addRuleDefinition(BazelJavaLibraryRule.class);
+ builder.addRuleDefinition(BazelJavaImportRule.class);
+ builder.addRuleDefinition(BazelJavaTestRule.class);
+ builder.addRuleDefinition(BazelJavaPluginRule.class);
+ builder.addRuleDefinition(JavaToolchainRule.class);
+
+ builder.addRuleDefinition(BazelIosTestRule.class);
+ builder.addRuleDefinition(IosDeviceRule.class);
+ builder.addRuleDefinition(ObjcBinaryRule.class);
+ builder.addRuleDefinition(ObjcBundleRule.class);
+ builder.addRuleDefinition(ObjcBundleLibraryRule.class);
+ builder.addRuleDefinition(ObjcFrameworkRule.class);
+ builder.addRuleDefinition(ObjcImportRule.class);
+ builder.addRuleDefinition(ObjcLibraryRule.class);
+ builder.addRuleDefinition(ObjcOptionsRule.class);
+ builder.addRuleDefinition(ObjcProtoLibraryRule.class);
+ builder.addRuleDefinition(ObjcXcodeprojRule.class);
+ builder.addRuleDefinition(ObjcRuleClasses.IosTestBaseRule.class);
+ builder.addRuleDefinition(ObjcRuleClasses.ObjcHasInfoplistRule.class);
+ builder.addRuleDefinition(ObjcRuleClasses.ObjcHasEntitlementsRule.class);
+ builder.addRuleDefinition(ObjcRuleClasses.ObjcCompilationRule.class);
+ builder.addRuleDefinition(ObjcRuleClasses.ObjcBaseResourcesRule.class);
+ builder.addRuleDefinition(IosApplicationRule.class);
+
+ builder.addRuleDefinition(BazelExtraActionRule.class);
+ builder.addRuleDefinition(BazelActionListenerRule.class);
+
+ builder.addRuleDefinition(BindRule.class);
+ builder.addRuleDefinition(HttpArchiveRule.class);
+ builder.addRuleDefinition(HttpJarRule.class);
+ builder.addRuleDefinition(LocalRepositoryRule.class);
+ builder.addRuleDefinition(MavenJarRule.class);
+ builder.addRuleDefinition(NewLocalRepositoryRule.class);
+
+ builder.addConfigurationFragment(new BazelConfiguration.Loader());
+ builder.addConfigurationFragment(new CppConfigurationLoader(
+ Functions.<String>identity()));
+ builder.addConfigurationFragment(new JvmConfigurationLoader(JAVA_CPU_SUPPLIER));
+ builder.addConfigurationFragment(new JavaConfigurationLoader(JAVA_CPU_SUPPLIER));
+ builder.addConfigurationFragment(new ObjcConfigurationLoader());
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
new file mode 100644
index 0000000000..214b3679a3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRulesModule.java
@@ -0,0 +1,159 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.eventbus.Subscribe;
+import com.google.devtools.build.lib.actions.ActionContextConsumer;
+import com.google.devtools.build.lib.actions.ActionContextProvider;
+import com.google.devtools.build.lib.actions.ActionGraph;
+import com.google.devtools.build.lib.actions.ActionInputFileCache;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.Executor.ActionContext;
+import com.google.devtools.build.lib.actions.ExecutorInitException;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.rules.cpp.CppCompileActionContext;
+import com.google.devtools.build.lib.rules.cpp.CppLinkActionContext;
+import com.google.devtools.build.lib.rules.cpp.LocalGccStrategy;
+import com.google.devtools.build.lib.rules.cpp.LocalLinkStrategy;
+import com.google.devtools.build.lib.runtime.BlazeModule;
+import com.google.devtools.build.lib.runtime.BlazeRuntime;
+import com.google.devtools.build.lib.runtime.Command;
+import com.google.devtools.build.lib.runtime.GotOptionsEvent;
+import com.google.devtools.common.options.Option;
+import com.google.devtools.common.options.OptionsBase;
+import com.google.devtools.common.options.OptionsProvider;
+
+import java.util.Map;
+
+/**
+ * Module implementing the rule set of Bazel.
+ */
+public class BazelRulesModule extends BlazeModule {
+ /**
+ * Execution options affecting how we execute the build actions (but not their semantics).
+ */
+ public static class BazelExecutionOptions extends OptionsBase {
+ @Option(
+ name = "spawn_strategy",
+ defaultValue = "standalone",
+ category = "strategy",
+ help = "Specify how spawn actions are executed by default."
+ + "'standalone' means run all of them locally."
+ + "'sandboxed' means run them in namespaces based sandbox (available only on Linux)")
+ public String spawnStrategy;
+
+ @Option(
+ name = "genrule_strategy",
+ defaultValue = "standalone",
+ category = "strategy",
+ help = "Specify how to execute genrules."
+ + "'standalone' means run all of them locally."
+ + "'sandboxed' means run them in namespaces based sandbox (available only on Linux)")
+
+ public String genruleStrategy;
+ }
+
+ private static class BazelActionContextConsumer implements ActionContextConsumer {
+ BazelExecutionOptions options;
+
+ private BazelActionContextConsumer(BazelExecutionOptions options) {
+ this.options = options;
+
+ }
+ @Override
+ public Map<String, String> getSpawnActionContexts() {
+ ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+
+ builder.put("Genrule", options.genruleStrategy);
+
+ // TODO(bazel-team): put this in getActionContexts (key=SpawnActionContext.class) instead
+ builder.put("", options.spawnStrategy);
+
+ return builder.build();
+ }
+
+ @Override
+ public Map<Class<? extends ActionContext>, String> getActionContexts() {
+ ImmutableMap.Builder<Class<? extends ActionContext>, String> builder =
+ ImmutableMap.builder();
+ builder.put(CppCompileActionContext.class, "");
+ builder.put(CppLinkActionContext.class, "");
+ return builder.build();
+ }
+ }
+
+ private class BazelActionContextProvider implements ActionContextProvider {
+ @Override
+ public Iterable<ActionContext> getActionContexts() {
+ return ImmutableList.of(
+ new LocalGccStrategy(optionsProvider),
+ new LocalLinkStrategy());
+ }
+
+ @Override
+ public void executorCreated(Iterable<ActionContext> usedContexts)
+ throws ExecutorInitException {
+ }
+
+ @Override
+ public void executionPhaseStarting(ActionInputFileCache actionInputFileCache,
+ ActionGraph actionGraph, Iterable<Artifact> topLevelArtifacts)
+ throws ExecutorInitException, InterruptedException {
+ }
+
+ @Override
+ public void executionPhaseEnding() {
+ }
+ }
+
+ private BlazeRuntime runtime;
+ private OptionsProvider optionsProvider;
+
+ @Override
+ public void beforeCommand(BlazeRuntime blazeRuntime, Command command) {
+ this.runtime = blazeRuntime;
+ runtime.getEventBus().register(this);
+ }
+
+ @Override
+ public Iterable<Class<? extends OptionsBase>> getCommandOptions(Command command) {
+ return command.builds()
+ ? ImmutableList.<Class<? extends OptionsBase>>of(BazelExecutionOptions.class)
+ : ImmutableList.<Class<? extends OptionsBase>>of();
+ }
+
+ @Override
+ public ActionContextConsumer getActionContextConsumer() {
+ return new BazelActionContextConsumer(
+ optionsProvider.getOptions(BazelExecutionOptions.class));
+ }
+
+ @Override
+ public ActionContextProvider getActionContextProvider() {
+ return new BazelActionContextProvider();
+ }
+
+ @Subscribe
+ public void gotOptions(GotOptionsEvent event) {
+ optionsProvider = event.getOptions();
+ }
+
+ @Override
+ public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) {
+ BazelRuleClassProvider.setup(builder);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java
new file mode 100644
index 0000000000..eba1553ac8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelActionListenerRule.java
@@ -0,0 +1,47 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.common;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.extra.ActionListener;
+
+/**
+ * Rule definition for action_listener rule.
+ */
+@BlazeRule(name = "action_listener",
+ ancestors = { BaseRuleClasses.RuleBase.class },
+ factoryClass = ActionListener.class)
+public final class BazelActionListenerRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .add(attr("mnemonics", STRING_LIST).mandatory())
+ .add(attr("extra_actions", LABEL_LIST).mandatory()
+ .allowedRuleClasses("extra_action")
+ .allowedFileTypes())
+ .removeAttribute("deps")
+ .removeAttribute("data")
+ .removeAttribute(":action_listener")
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java
new file mode 100644
index 0000000000..fa73f9308e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelExtraActionRule.java
@@ -0,0 +1,49 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.common;
+
+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.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.extra.ExtraActionFactory;
+
+/**
+ * Rule definition for extra_action rule.
+ */
+@BlazeRule(name = "extra_action",
+ ancestors = { BaseRuleClasses.RuleBase.class },
+ factoryClass = ExtraActionFactory.class)
+public final class BazelExtraActionRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .add(attr("tools", LABEL_LIST).cfg(HOST).allowedFileTypes().exec())
+ .add(attr("out_templates", STRING_LIST))
+ .add(attr("cmd", STRING).mandatory())
+ .add(attr("requires_action_output", BOOLEAN))
+ .removeAttribute("deps")
+ .removeAttribute(":action_listener")
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java
new file mode 100644
index 0000000000..0ff5cd061e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelFilegroupRule.java
@@ -0,0 +1,48 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.common;
+
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.DATA;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.LICENSE;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.filegroup.Filegroup;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+/**
+ * Rule object implementing "filegroup".
+ */
+@BlazeRule(name = "filegroup",
+ ancestors = { BaseRuleClasses.BaseRule.class },
+ factoryClass = Filegroup.class)
+public final class BazelFilegroupRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ // filegroup ignores any filtering set with setSrcsAllowedFiles.
+ return builder
+ .add(attr("srcs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+ .add(attr("data", LABEL_LIST).cfg(DATA).allowedFileTypes(FileTypeSet.ANY_FILE))
+ .add(attr("output_licenses", LICENSE))
+ .add(attr("path", STRING))
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java
new file mode 100644
index 0000000000..54db469910
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/common/BazelTestSuiteRule.java
@@ -0,0 +1,50 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.common;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.test.TestSuite;
+
+/**
+ * Rule object implementing "test_suite".
+ */
+@BlazeRule(name = "test_suite",
+ ancestors = { BaseRuleClasses.BaseRule.class },
+ factoryClass = TestSuite.class)
+public final class BazelTestSuiteRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .override(attr("testonly", BOOLEAN).value(true)
+ .nonconfigurable("policy decision: should be consistent across configurations"))
+ .add(attr("tests", LABEL_LIST).orderIndependent().allowedFileTypes()
+ .nonconfigurable("policy decision: should be consistent across configurations"))
+ .add(attr("suites", LABEL_LIST).orderIndependent().allowedFileTypes()
+ .nonconfigurable("policy decision: should be consistent across configurations"))
+ // This magic attribute contains all *test rules in the package, iff
+ // tests=[] and suites=[]:
+ .add(attr("$implicit_tests", LABEL_LIST)
+ .nonconfigurable("Accessed in TestTargetUtils without config context"))
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcBinary.java
new file mode 100644
index 0000000000..e3f62a15de
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcBinary.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.cpp;
+
+import com.google.devtools.build.lib.rules.cpp.CcBinary;
+
+/**
+ * Factory class for the {@code cc_binary} rule.
+ */
+public class BazelCcBinary extends CcBinary {
+ public BazelCcBinary() {
+ super(BazelCppSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibrary.java
new file mode 100644
index 0000000000..ae3880699b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibrary.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.cpp;
+
+import com.google.devtools.build.lib.rules.cpp.CcLibrary;
+
+/**
+ * Factory class for the {@code cc_library} rule.
+ */
+public class BazelCcLibrary extends CcLibrary {
+ public BazelCcLibrary() {
+ super(BazelCppSemantics.INSTANCE);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTest.java
new file mode 100644
index 0000000000..f42b1dc1a9
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcTest.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.cpp;
+
+import com.google.devtools.build.lib.rules.cpp.CcTest;
+
+/**
+ * Factory class for the {@code cc_test} rule.
+ */
+public class BazelCcTest extends CcTest {
+ public BazelCcTest() {
+ super(BazelCppSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
new file mode 100644
index 0000000000..4a1f3b6659
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppRuleClasses.java
@@ -0,0 +1,422 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.cpp;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromFunctions;
+import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST_DICT;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+import static com.google.devtools.build.lib.packages.Type.TRISTATE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ALWAYS_LINK_LIBRARY;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ALWAYS_LINK_PIC_LIBRARY;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ARCHIVE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.ASSEMBLER_WITH_C_PREPROCESSOR;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.CPP_HEADER;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.CPP_SOURCE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.C_SOURCE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.OBJECT_FILE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.PIC_ARCHIVE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.PIC_OBJECT_FILE;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.SHARED_LIBRARY;
+import static com.google.devtools.build.lib.rules.cpp.CppFileTypes.VERSIONED_SHARED_LIBRARY;
+
+import com.google.common.base.Predicates;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
+import com.google.devtools.build.lib.packages.Attribute.LateBoundLabel;
+import com.google.devtools.build.lib.packages.Attribute.Transition;
+import com.google.devtools.build.lib.packages.AttributeMap;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.RawAttributeMapper;
+import com.google.devtools.build.lib.packages.Rule;
+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;
+import com.google.devtools.build.lib.packages.TriState;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.rules.cpp.CcLibrary;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.util.FileTypeSet;
+import com.google.devtools.build.lib.view.config.crosstool.CrosstoolConfig.LipoMode;
+
+/**
+ * Rule class definitions for C++ rules.
+ */
+public class BazelCppRuleClasses {
+ static final SafeImplicitOutputsFunction CC_LIBRARY_DYNAMIC_LIB =
+ fromTemplates("%{dirname}lib%{basename}.so");
+
+ static final SafeImplicitOutputsFunction CC_BINARY_IMPLICIT_OUTPUTS =
+ fromFunctions(CppRuleClasses.CC_BINARY_STRIPPED, CppRuleClasses.CC_BINARY_DEBUG_PACKAGE);
+
+ static final FileTypeSet ALLOWED_SRC_FILES = FileTypeSet.of(
+ CPP_SOURCE,
+ C_SOURCE,
+ CPP_HEADER,
+ ASSEMBLER_WITH_C_PREPROCESSOR,
+ ARCHIVE,
+ PIC_ARCHIVE,
+ ALWAYS_LINK_LIBRARY,
+ ALWAYS_LINK_PIC_LIBRARY,
+ SHARED_LIBRARY,
+ VERSIONED_SHARED_LIBRARY,
+ OBJECT_FILE,
+ PIC_OBJECT_FILE);
+
+ static final String[] DEPS_ALLOWED_RULES = new String[] {
+ "cc_library",
+ };
+
+ /**
+ * Miscellaneous configuration transitions. It would be better not to have this - please don't add
+ * to it.
+ */
+ public static enum CppTransition implements Transition {
+ /**
+ * The configuration for LIPO information collection. Requesting this from a configuration that
+ * does not have lipo optimization enabled may result in an exception.
+ */
+ LIPO_COLLECTOR,
+
+ /**
+ * The corresponding (target) configuration.
+ */
+ TARGET_CONFIG_FOR_LIPO;
+
+ @Override
+ public boolean defaultsToSelf() {
+ return false;
+ }
+ }
+
+ private static final RuleClass.Configurator<BuildConfiguration, Rule> LIPO_ON_DEMAND =
+ new RuleClass.Configurator<BuildConfiguration, Rule>() {
+ @Override
+ public BuildConfiguration apply(Rule rule, BuildConfiguration configuration) {
+ BuildConfiguration toplevelConfig =
+ configuration.getConfiguration(CppTransition.TARGET_CONFIG_FOR_LIPO);
+ // If LIPO is enabled, override the default configuration.
+ if (toplevelConfig != null
+ && toplevelConfig.getFragment(CppConfiguration.class).isLipoOptimization()
+ && !configuration.isHostConfiguration()
+ && !configuration.getFragment(CppConfiguration.class).isLipoContextCollector()) {
+ // Switch back to data when the cc_binary is not the LIPO context.
+ return (rule.getLabel().equals(
+ toplevelConfig.getFragment(CppConfiguration.class).getLipoContextLabel()))
+ ? toplevelConfig
+ : configuration.getTransitions().getConfiguration(ConfigurationTransition.DATA);
+ }
+ return configuration;
+ }
+ };
+
+ /**
+ * Label of a pseudo-filegroup that contains all crosstool and libcfiles for
+ * all configurations, as specified on the command-line.
+ */
+ public static final String CROSSTOOL_LABEL = "//tools/defaults:crosstool";
+
+ public static final LateBoundLabel<BuildConfiguration> CC_TOOLCHAIN =
+ new LateBoundLabel<BuildConfiguration>(CROSSTOOL_LABEL) {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.getFragment(CppConfiguration.class).getCcToolchainRuleLabel();
+ }
+ };
+
+ public static final LateBoundLabel<BuildConfiguration> DEFAULT_MALLOC =
+ new LateBoundLabel<BuildConfiguration>() {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.getFragment(CppConfiguration.class).customMalloc();
+ }
+ };
+
+ public static final LateBoundLabel<BuildConfiguration> STL =
+ new LateBoundLabel<BuildConfiguration>() {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ return getStl(rule, configuration);
+ }
+ };
+
+ /**
+ * Implementation for the :lipo_context_collector attribute.
+ */
+ public static final LateBoundLabel<BuildConfiguration> LIPO_CONTEXT_COLLECTOR =
+ new LateBoundLabel<BuildConfiguration>() {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ // This attribute connects a target to the LIPO context target configured with the
+ // lipo input collector configuration.
+ CppConfiguration cppConfiguration = configuration.getFragment(CppConfiguration.class);
+ return !cppConfiguration.isLipoContextCollector()
+ && (cppConfiguration.getLipoMode() == LipoMode.BINARY)
+ ? cppConfiguration.getLipoContextLabel()
+ : null;
+ }
+ };
+
+ /**
+ * Returns the STL prerequisite of the rule.
+ *
+ * <p>If rule has an implicit $stl attribute returns STL version set on the
+ * command line or if not set, the value of the $stl attribute. Returns
+ * {@code null} otherwise.
+ */
+ private static Label getStl(Rule rule, BuildConfiguration original) {
+ Label stl = null;
+ if (rule.getRuleClassObject().hasAttr("$stl", Type.LABEL)) {
+ Label stlConfigLabel = original.getFragment(CppConfiguration.class).getStl();
+ Label stlRuleLabel = RawAttributeMapper.of(rule).get("$stl", Type.LABEL);
+ if (stlConfigLabel == null) {
+ stl = stlRuleLabel;
+ } else if (!stlConfigLabel.equals(rule.getLabel()) && stlRuleLabel != null) {
+ // prevents self-reference and a cycle through standard STL in the dependency graph
+ stl = stlConfigLabel;
+ }
+ }
+ return stl;
+ }
+
+ /**
+ * Common attributes for all rules that create C++ links. This may
+ * include non-cc_* rules (e.g. py_binary).
+ */
+ @BlazeRule(name = "$cc_linking_rule",
+ type = RuleClassType.ABSTRACT)
+ public static final class CcLinkingRule implements RuleDefinition {
+ @Override
+ @SuppressWarnings("unchecked")
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr(":cc_toolchain", LABEL).value(CC_TOOLCHAIN))
+ .setPreferredDependencyPredicate(Predicates.<String>or(CPP_SOURCE, C_SOURCE, CPP_HEADER))
+ .build();
+ }
+ }
+
+ /**
+ * Common attributes for C++ rules.
+ */
+ @BlazeRule(name = "$cc_base_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { CcLinkingRule.class })
+ public static final class CcBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("copts", STRING_LIST))
+ .add(attr("$stl", LABEL).value(env.getLabel("//tools/cpp:stl")))
+ .add(attr(":stl", LABEL).value(STL))
+ .build();
+ }
+ }
+
+ /**
+ * Helper rule class.
+ */
+ @BlazeRule(name = "$cc_decl_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { BaseRuleClasses.RuleBase.class })
+ public static final class CcDeclRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("abi", STRING).value("$(ABI)"))
+ .add(attr("abi_deps", LABEL_LIST_DICT))
+ .add(attr("defines", STRING_LIST))
+ .add(attr("includes", STRING_LIST))
+ .add(attr(":lipo_context_collector", LABEL)
+ .cfg(CppTransition.LIPO_COLLECTOR)
+ .value(LIPO_CONTEXT_COLLECTOR))
+ .build();
+ }
+ }
+
+ /**
+ * Helper rule class.
+ */
+ @BlazeRule(name = "$cc_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { CcDeclRule.class, CcBaseRule.class })
+ public static final class CcRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("srcs", LABEL_LIST)
+ .direct_compile_time_input()
+ .allowedFileTypes(ALLOWED_SRC_FILES))
+ .override(attr("deps", LABEL_LIST)
+ .allowedRuleClasses(DEPS_ALLOWED_RULES)
+ .allowedFileTypes()
+ .skipAnalysisTimeFileTypeCheck())
+ .add(attr("linkopts", STRING_LIST))
+ .add(attr("nocopts", STRING))
+ .add(attr("hdrs_check", STRING).value("strict"))
+ .add(attr("linkstatic", BOOLEAN).value(true))
+ .override(attr("$stl", LABEL).value(new Attribute.ComputedDefault() {
+ @Override
+ public Object getDefault(AttributeMap rule) {
+ // Every cc_rule depends implicitly on STL to make
+ // sure that the correct headers are used for inclusion. The only exception is
+ // STL itself to avoid cycles in the dependency graph.
+ Label stl = env.getLabel("//tools/cpp:stl");
+ return rule.getLabel().equals(stl) ? null : stl;
+ }
+ }))
+ .build();
+ }
+ }
+
+ /**
+ * Helper rule class.
+ */
+ @BlazeRule(name = "$cc_binary_base",
+ type = RuleClassType.ABSTRACT,
+ ancestors = CcRule.class)
+ public static final class CcBinaryBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("malloc", LABEL)
+ .value(env.getLabel("//tools/cpp:malloc"))
+ .allowedFileTypes()
+ .allowedRuleClasses("cc_library"))
+ .add(attr(":default_malloc", LABEL).value(DEFAULT_MALLOC))
+ .add(attr("stamp", TRISTATE).value(TriState.AUTO))
+ .build();
+ }
+ }
+
+ /**
+ * Rule definition for cc_binary rules.
+ */
+ @BlazeRule(name = "cc_binary",
+ ancestors = { CcBinaryBaseRule.class,
+ BazelBaseRuleClasses.BinaryBaseRule.class },
+ factoryClass = BazelCcBinary.class)
+ public static final class CcBinaryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setImplicitOutputsFunction(CC_BINARY_IMPLICIT_OUTPUTS)
+ .add(attr("linkshared", BOOLEAN).value(false)
+ .nonconfigurable("used to *determine* the rule's configuration"))
+ .cfg(LIPO_ON_DEMAND)
+ .build();
+ }
+ }
+
+ /**
+ * Implementation for the :lipo_context attribute.
+ */
+ private static final LateBoundLabel<BuildConfiguration> LIPO_CONTEXT =
+ new LateBoundLabel<BuildConfiguration>() {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ Label result = configuration.getFragment(CppConfiguration.class).getLipoContextLabel();
+ return (rule == null || rule.getLabel().equals(result)) ? null : result;
+ }
+ };
+
+ /**
+ * Rule definition for cc_test rules.
+ */
+ @BlazeRule(name = "cc_test",
+ type = RuleClassType.TEST,
+ ancestors = { CcBinaryBaseRule.class, BaseRuleClasses.TestBaseRule.class },
+ factoryClass = BazelCcTest.class)
+ public static final class CcTestRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setImplicitOutputsFunction(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE)
+ .override(attr("linkstatic", BOOLEAN).value(false))
+ .override(attr("stamp", TRISTATE).value(TriState.NO))
+ .add(attr(":lipo_context", LABEL).value(LIPO_CONTEXT))
+ .build();
+ }
+ }
+
+ /**
+ * Helper rule class.
+ */
+ @BlazeRule(name = "$cc_library",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { CcRule.class })
+ public static final class CcLibraryBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("hdrs", LABEL_LIST).orderIndependent().direct_compile_time_input()
+ .allowedFileTypes(CPP_HEADER))
+ .add(attr("linkstamp", LABEL).allowedFileTypes(CPP_SOURCE, C_SOURCE))
+ .build();
+ }
+ }
+
+ /**
+ * Rule definition for the cc_library rule.
+ */
+ @BlazeRule(name = "cc_library",
+ ancestors = { CcLibraryBaseRule.class},
+ factoryClass = BazelCcLibrary.class)
+ public static final class CcLibraryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ SafeImplicitOutputsFunction implicitOutputsFunction = new SafeImplicitOutputsFunction() {
+ @Override
+ public Iterable<String> getImplicitOutputs(AttributeMap rule) {
+ boolean alwaysLink = rule.get("alwayslink", Type.BOOLEAN);
+ boolean linkstatic = rule.get("linkstatic", Type.BOOLEAN);
+ SafeImplicitOutputsFunction staticLib = fromTemplates(
+ alwaysLink
+ ? "%{dirname}lib%{basename}.lo"
+ : "%{dirname}lib%{basename}.a");
+ SafeImplicitOutputsFunction allLibs =
+ linkstatic || CcLibrary.appearsToHaveNoObjectFiles(rule)
+ ? staticLib
+ : fromFunctions(staticLib, CC_LIBRARY_DYNAMIC_LIB);
+ return allLibs.getImplicitOutputs(rule);
+ }
+ };
+
+ return builder
+ .setImplicitOutputsFunction(implicitOutputsFunction)
+ .add(attr("alwayslink", BOOLEAN).
+ nonconfigurable("value is referenced in an ImplicitOutputsFunction"))
+ .add(attr("implements", LABEL_LIST)
+ .allowedFileTypes()
+ .allowedRuleClasses("cc_public_library$headers"))
+ .override(attr("linkstatic", BOOLEAN).value(false)
+ .nonconfigurable("value is referenced in an ImplicitOutputsFunction"))
+ .build();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java
new file mode 100644
index 0000000000..3771e6c8be
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCppSemantics.java
@@ -0,0 +1,52 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.cpp;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.rules.cpp.CppCompilationContext.Builder;
+import com.google.devtools.build.lib.rules.cpp.CppCompileActionBuilder;
+import com.google.devtools.build.lib.rules.cpp.CppCompileActionContext;
+import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
+import com.google.devtools.build.lib.rules.cpp.CppHelper;
+import com.google.devtools.build.lib.rules.cpp.CppSemantics;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * C++ compilation semantics.
+ */
+public class BazelCppSemantics implements CppSemantics {
+ public static final CppSemantics INSTANCE = new BazelCppSemantics();
+
+ private BazelCppSemantics() {
+ }
+
+ @Override
+ public PathFragment getEffectiveSourcePath(Artifact source) {
+ return source.getRootRelativePath();
+ }
+
+ @Override
+ public void finalizeCompileActionBuilder(
+ RuleContext ruleContext, CppCompileActionBuilder actionBuilder) {
+ actionBuilder.setCppConfiguration(ruleContext.getFragment(CppConfiguration.class));
+ actionBuilder.setActionContext(CppCompileActionContext.class);
+ actionBuilder.addTransitiveMandatoryInputs(CppHelper.getToolchain(ruleContext).getCompile());
+ }
+
+ @Override
+ public void setupCompilationContext(RuleContext ruleContext, Builder contextBuilder) {
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java
new file mode 100644
index 0000000000..eabb4e9834
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/BazelGenRuleRule.java
@@ -0,0 +1,77 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.genrule;
+
+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.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.LICENSE;
+import static com.google.devtools.build.lib.packages.Type.OUTPUT_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.AttributeMap;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.Type;
+
+/**
+ * Rule definition for the genrule rule.
+ */
+@BlazeRule(name = "genrule",
+ ancestors = { BaseRuleClasses.RuleBase.class },
+ factoryClass = GenRule.class)
+public final class BazelGenRuleRule implements RuleDefinition {
+ public static final String GENRULE_SETUP_LABEL = "//tools/genrule:genrule-setup.sh";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setOutputToGenfiles()
+ .add(attr("srcs", LABEL_LIST)
+ .direct_compile_time_input()
+ .legacyAllowAnyFileType())
+ .add(attr("tools", LABEL_LIST).cfg(HOST).legacyAllowAnyFileType())
+ .add(attr("$genrule_setup", LABEL).cfg(HOST).value(env.getLabel(GENRULE_SETUP_LABEL)))
+ .add(attr("outs", OUTPUT_LIST).mandatory())
+ .add(attr("cmd", STRING).mandatory())
+ .add(attr("output_to_bindir", BOOLEAN).value(false)
+ .nonconfigurable("policy decision: no reason for this to depend on the configuration"))
+ .add(attr("local", BOOLEAN).value(false))
+ .add(attr("message", STRING))
+ .add(attr("output_licenses", LICENSE))
+ .add(attr("executable", BOOLEAN).value(false))
+ .add(attr("stamp", BOOLEAN).value(false))
+ .add(attr("heuristic_label_expansion", BOOLEAN).value(true))
+ .add(attr("$is_executable", BOOLEAN)
+ .nonconfigurable("Called from RunCommand.isExecutable, which takes a Target")
+ .value(
+ new Attribute.ComputedDefault("outs", "executable") {
+ @Override
+ public Object getDefault(AttributeMap rule) {
+ return (rule.get("outs", Type.OUTPUT_LIST).size() == 1)
+ && rule.get("executable", BOOLEAN);
+ }
+ }))
+ .removeAttribute("data")
+ .removeAttribute("deps")
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRule.java
new file mode 100644
index 0000000000..d70f9a7298
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRule.java
@@ -0,0 +1,219 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.genrule;
+
+import static com.google.devtools.build.lib.analysis.RunfilesProvider.withData;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.CommandHelper;
+import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
+import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.MakeVariableExpander.ExpansionException;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+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.TransitiveInfoCollection;
+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;
+import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.syntax.Label;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of genrule.
+ */
+public class GenRule implements RuleConfiguredTargetFactory {
+
+ public static final String GENRULE_SETUP_CMD =
+ "source tools/genrule/genrule-setup.sh; ";
+
+ private Artifact getExecutable(RuleContext ruleContext, NestedSet<Artifact> filesToBuild) {
+ if (Iterables.size(filesToBuild) == 1) {
+ Artifact out = Iterables.getOnlyElement(filesToBuild);
+ if (ruleContext.attributes().get("executable", Type.BOOLEAN)) {
+ return out;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext) {
+ final List<Artifact> resolvedSrcs = Lists.newArrayList();
+
+ final NestedSet<Artifact> filesToBuild =
+ NestedSetBuilder.wrap(Order.STABLE_ORDER, ruleContext.getOutputArtifacts());
+ if (filesToBuild.isEmpty()) {
+ ruleContext.attributeError("outs", "Genrules without outputs don't make sense");
+ }
+ if (ruleContext.attributes().get("executable", Type.BOOLEAN)
+ && Iterables.size(filesToBuild) > 1) {
+ ruleContext.attributeError("executable",
+ "if genrules produce executables, they are allowed only one output. "
+ + "If you need the executable=1 argument, then you should split this genrule into "
+ + "genrules producing single outputs");
+ }
+
+ ImmutableMap.Builder<Label, Iterable<Artifact>> labelMap = ImmutableMap.builder();
+ for (TransitiveInfoCollection dep : ruleContext.getPrerequisites("srcs", Mode.TARGET)) {
+ Iterable<Artifact> files = dep.getProvider(FileProvider.class).getFilesToBuild();
+ Iterables.addAll(resolvedSrcs, files);
+ labelMap.put(dep.getLabel(), files);
+ }
+
+ CommandHelper commandHelper = new CommandHelper(ruleContext, ruleContext
+ .getPrerequisites("tools", Mode.HOST, FilesToRunProvider.class), labelMap.build());
+
+ if (ruleContext.hasErrors()) {
+ return null;
+ }
+
+ String baseCommand = commandHelper.resolveCommandAndExpandLabels(
+ ruleContext.attributes().get("heuristic_label_expansion", Type.BOOLEAN), false);
+
+ // Adds the genrule environment setup script before the actual shell command
+ String command = GENRULE_SETUP_CMD + baseCommand;
+
+ command = resolveCommand(ruleContext, command, resolvedSrcs, filesToBuild);
+
+ String message = ruleContext.attributes().get("message", Type.STRING);
+ if (message.isEmpty()) {
+ message = "Executing genrule";
+ }
+
+ ImmutableMap<String, String> env =
+ ruleContext.getConfiguration().getDefaultShellEnvironment();
+
+ Map<String, String> executionInfo = Maps.newLinkedHashMap();
+ executionInfo.putAll(TargetUtils.getExecutionInfo(ruleContext.getRule()));
+
+ if (ruleContext.attributes().get("local", Type.BOOLEAN)) {
+ executionInfo.put("local", "");
+ }
+
+ NestedSetBuilder<Artifact> inputs = NestedSetBuilder.stableOrder();
+ inputs.addAll(resolvedSrcs);
+ inputs.addAll(commandHelper.getResolvedTools());
+ FilesToRunProvider genruleSetup =
+ ruleContext.getPrerequisite("$genrule_setup", Mode.HOST, FilesToRunProvider.class);
+ inputs.addAll(genruleSetup.getFilesToRun());
+ List<String> argv = commandHelper.buildCommandLine(command, inputs, ".genrule_script.sh");
+
+ if (ruleContext.attributes().get("stamp", Type.BOOLEAN)) {
+ inputs.add(ruleContext.getAnalysisEnvironment().getStableWorkspaceStatusArtifact());
+ inputs.add(ruleContext.getAnalysisEnvironment().getVolatileWorkspaceStatusArtifact());
+ }
+
+ ruleContext.registerAction(new GenRuleAction(
+ ruleContext.getActionOwner(), inputs.build(), filesToBuild, argv, env,
+ ImmutableMap.copyOf(executionInfo), commandHelper.getRemoteRunfileManifestMap(),
+ message + ' ' + ruleContext.getLabel()));
+
+ RunfilesProvider runfilesProvider = withData(
+ // No runfiles provided if not a data dependency.
+ Runfiles.EMPTY,
+ // We only need to consider the outputs of a genrule
+ // No need to visit the dependencies of a genrule. They cross from the target into the host
+ // configuration, because the dependencies of a genrule are always built for the host
+ // configuration.
+ new Runfiles.Builder().addTransitiveArtifacts(filesToBuild).build());
+
+ return new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(filesToBuild)
+ .setRunfilesSupport(null, getExecutable(ruleContext, filesToBuild))
+ .addProvider(RunfilesProvider.class, runfilesProvider)
+ .build();
+ }
+
+ private String resolveCommand(final RuleContext ruleContext, final String command,
+ final List<Artifact> resolvedSrcs, final NestedSet<Artifact> filesToBuild) {
+ return ruleContext.expandMakeVariables("cmd", command, new ConfigurationMakeVariableContext(
+ ruleContext.getRule().getPackage(), ruleContext.getConfiguration()) {
+ @Override
+ public String lookupMakeVariable(String name) throws ExpansionException {
+ if (name.equals("SRCS")) {
+ return Artifact.joinExecPaths(" ", resolvedSrcs);
+ } else if (name.equals("<")) {
+ return expandSingletonArtifact(resolvedSrcs, "$<", "input file");
+ } else if (name.equals("OUTS")) {
+ return Artifact.joinExecPaths(" ", filesToBuild);
+ } else if (name.equals("@")) {
+ return expandSingletonArtifact(filesToBuild, "$@", "output file");
+ } else if (name.equals("@D")) {
+ // The output directory. If there is only one filename in outs,
+ // this expands to the directory containing that file. If there are
+ // multiple filenames, this variable instead expands to the
+ // package's root directory in the genfiles tree, even if all the
+ // generated files belong to the same subdirectory!
+ if (Iterables.size(filesToBuild) == 1) {
+ Artifact outputFile = Iterables.getOnlyElement(filesToBuild);
+ PathFragment relativeOutputFile = outputFile.getExecPath();
+ if (relativeOutputFile.segmentCount() <= 1) {
+ // This should never happen, since the path should contain at
+ // least a package name and a file name.
+ throw new IllegalStateException("$(@D) for genrule " + ruleContext.getLabel()
+ + " has less than one segment");
+ }
+ return relativeOutputFile.getParentDirectory().getPathString();
+ } else {
+ PathFragment dir;
+ if (ruleContext.getRule().hasBinaryOutput()) {
+ dir = ruleContext.getConfiguration().getBinFragment();
+ } else {
+ dir = ruleContext.getConfiguration().getGenfilesFragment();
+ }
+ PathFragment relPath = ruleContext.getRule().getLabel().getPackageFragment();
+ return dir.getRelative(relPath).getPathString();
+ }
+ } else {
+ return super.lookupMakeVariable(name);
+ }
+ }
+ }
+ );
+ }
+
+ // Returns the path of the sole element "artifacts", generating an exception
+ // with an informative error message iff the set is not a singleton.
+ //
+ // Used to expand "$<", "$@"
+ private String expandSingletonArtifact(Iterable<Artifact> artifacts,
+ String variable,
+ String artifactName)
+ throws ExpansionException {
+ if (Iterables.isEmpty(artifacts)) {
+ throw new ExpansionException("variable '" + variable
+ + "' : no " + artifactName);
+ } else if (Iterables.size(artifacts) > 1) {
+ throw new ExpansionException("variable '" + variable
+ + "' : more than one " + artifactName);
+ }
+ return Iterables.getOnlyElement(artifacts).getExecPathString();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleAction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleAction.java
new file mode 100644
index 0000000000..0a9b3e77a1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/genrule/GenRuleAction.java
@@ -0,0 +1,62 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.genrule;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ActionExecutionContext;
+import com.google.devtools.build.lib.actions.ActionOwner;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ExecException;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.analysis.actions.CommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.util.List;
+
+/**
+ * A spawn action for genrules. Genrules are handled specially in that inputs and outputs are
+ * checked for directories.
+ */
+public final class GenRuleAction extends SpawnAction {
+
+ private static final ResourceSet GENRULE_RESOURCES =
+ // Not chosen scientifically/carefully. 300MB memory, 100% CPU, 20% of total I/O.
+ new ResourceSet(300, 1.0, 0.0);
+
+ public GenRuleAction(ActionOwner owner,
+ Iterable<Artifact> inputs,
+ Iterable<Artifact> outputs,
+ List<String> argv,
+ ImmutableMap<String, String> environment,
+ ImmutableMap<String, String> executionInfo,
+ ImmutableMap<PathFragment, Artifact> runfilesManifests,
+ String progressMessage) {
+ super(owner, inputs, outputs, GENRULE_RESOURCES,
+ CommandLine.of(argv, false), environment, executionInfo, progressMessage,
+ runfilesManifests,
+ "Genrule", null);
+ }
+
+ @Override
+ protected void internalExecute(
+ ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException {
+ EventHandler reporter = actionExecutionContext.getExecutor().getEventHandler();
+ checkInputsForDirectories(reporter, actionExecutionContext.getMetadataHandler());
+ super.internalExecute(actionExecutionContext);
+ checkOutputsForDirectories(reporter);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinary.java
new file mode 100644
index 0000000000..04713c2837
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinary.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.devtools.build.lib.rules.java.JavaBinary;
+
+/**
+ * Implementation of {@code java_binary} with Bazel semantics.
+ */
+public class BazelJavaBinary extends JavaBinary {
+ public BazelJavaBinary() {
+ super(BazelJavaSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java
new file mode 100644
index 0000000000..279cbdbe26
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinaryRule.java
@@ -0,0 +1,51 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.BaseJavaBinaryRule;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.AttributeMap;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+
+/**
+ * Rule definition for the java_binary rule.
+ */
+@BlazeRule(name = "java_binary",
+ ancestors = { BaseJavaBinaryRule.class,
+ BazelBaseRuleClasses.BinaryBaseRule.class },
+ factoryClass = BazelJavaBinary.class)
+public final class BazelJavaBinaryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setImplicitOutputsFunction(BazelJavaRuleClasses.JAVA_BINARY_IMPLICIT_OUTPUTS)
+ .override(attr("$is_executable", BOOLEAN).nonconfigurable("automatic").value(
+ new Attribute.ComputedDefault() {
+ @Override
+ public Object getDefault(AttributeMap rule) {
+ return rule.get("create_executable", BOOLEAN);
+ }
+ }))
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBuildInfoFactory.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBuildInfoFactory.java
new file mode 100644
index 0000000000..db33897f73
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBuildInfoFactory.java
@@ -0,0 +1,61 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.rules.java.BuildInfoPropertiesTranslator;
+import com.google.devtools.build.lib.rules.java.GenericBuildInfoPropertiesTranslator;
+import com.google.devtools.build.lib.rules.java.JavaBuildInfoFactory;
+
+import java.util.Map;
+
+/**
+ * BuildInfoFactory for Java.
+ */
+public class BazelJavaBuildInfoFactory extends JavaBuildInfoFactory {
+ private static final Map<String, String> VOLATILE_KEYS = ImmutableMap
+ .<String, String>builder()
+ .put("build.time", "%BUILD_TIME%")
+ .put("build.timestamp.as.int", "%BUILD_TIMESTAMP%")
+ .put("build.timestamp", "%BUILD_TIMESTAMP%")
+ .build();
+
+ private static final Map<String, String> NONVOLATILE_KEYS = ImmutableMap
+ .<String, String>builder()
+ .build();
+
+ private static final Map<String, String> REDACTED_KEYS = ImmutableMap
+ .<String, String>builder()
+ .put("build.time", "Thu Jan 01 00:00:00 1970 (0)")
+ .put("build.timestamp.as.int", "0")
+ .put("build.timestamp", "Thu Jan 01 00:00:00 1970 (0)")
+ .build();
+
+ @Override
+ protected BuildInfoPropertiesTranslator createVolatileTranslator() {
+ return new GenericBuildInfoPropertiesTranslator(VOLATILE_KEYS);
+ }
+
+ @Override
+ protected BuildInfoPropertiesTranslator createNonVolatileTranslator() {
+ return new GenericBuildInfoPropertiesTranslator(NONVOLATILE_KEYS);
+ }
+
+ @Override
+ protected BuildInfoPropertiesTranslator createRedactedTranslator() {
+ return new GenericBuildInfoPropertiesTranslator(REDACTED_KEYS);
+ }
+
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImport.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImport.java
new file mode 100644
index 0000000000..6c7dcd4291
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImport.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.devtools.build.lib.rules.java.JavaImport;
+
+/**
+ * Implementation of {@code java_import} with Bazel semantics.
+ */
+public class BazelJavaImport extends JavaImport {
+ public BazelJavaImport() {
+ super(BazelJavaSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java
new file mode 100644
index 0000000000..132df238e7
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaImportRule.java
@@ -0,0 +1,53 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import static com.google.devtools.build.lib.packages.Attribute.ANY_EDGE;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.IjarBaseRule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.rules.java.JavaImportBaseRule;
+
+/**
+ * Rule definition for the java_import rule.
+ */
+@BlazeRule(name = "java_import",
+ ancestors = { JavaImportBaseRule.class, IjarBaseRule.class },
+ factoryClass = BazelJavaImport.class)
+public final class BazelJavaImportRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ /* <!-- #BLAZE_RULE(java_import).ATTRIBUTE(exports) -->
+ Targets to make available to users of this rule.
+ ${SYNOPSIS}
+ See <a href="#java_library.exports">java_library.exports</a>.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("exports", LABEL_LIST)
+ .allowedRuleClasses(ImmutableSet.of(
+ "java_library", "java_import", "cc_library", "cc_binary"))
+ .allowedFileTypes() // none allowed
+ .validityPredicate(ANY_EDGE))
+ .build();
+
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibrary.java
new file mode 100644
index 0000000000..6af9450c9c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibrary.java
@@ -0,0 +1,26 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.devtools.build.lib.rules.java.JavaLibrary;
+
+/**
+ * Implementation of {@code java_library} with Bazel semantics.
+ */
+public class BazelJavaLibrary extends JavaLibrary {
+ public BazelJavaLibrary() {
+ super(BazelJavaSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java
new file mode 100644
index 0000000000..04c8a0f5fa
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaLibraryRule.java
@@ -0,0 +1,51 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+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.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.JavaRule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+
+/**
+ * Common attributes for Java rules.
+ */
+@BlazeRule(name = "java_library",
+ ancestors = { JavaRule.class },
+ factoryClass = BazelJavaLibrary.class)
+public final class BazelJavaLibraryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
+
+ return builder
+ .setImplicitOutputsFunction(BazelJavaRuleClasses.JAVA_LIBRARY_IMPLICIT_OUTPUTS)
+ .add(attr("exports", LABEL_LIST)
+ .allowedRuleClasses(BazelJavaRuleClasses.ALLOWED_RULES_IN_DEPS)
+ .allowedFileTypes(/*May not have files in exports!*/))
+ .add(attr("neverlink", BOOLEAN).value(false))
+ .override(attr("javacopts", STRING_LIST))
+ .add(attr("exported_plugins", LABEL_LIST).cfg(HOST).allowedRuleClasses("java_plugin")
+ .legacyAllowAnyFileType())
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPlugin.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPlugin.java
new file mode 100644
index 0000000000..e6d3478568
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPlugin.java
@@ -0,0 +1,27 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.devtools.build.lib.rules.java.JavaPlugin;
+
+/**
+ * Implementation of the {@code java_plugin} rule for bazel.
+ */
+public class BazelJavaPlugin extends JavaPlugin {
+
+ public BazelJavaPlugin() {
+ super(BazelJavaSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
new file mode 100644
index 0000000000..cbb941164b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaPluginRule.java
@@ -0,0 +1,47 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+
+/**
+ * Rule definition for the java_plugin rule.
+ */
+@BlazeRule(name = "java_plugin",
+ ancestors = { BazelJavaLibraryRule.class },
+ factoryClass = BazelJavaPlugin.class)
+public final class BazelJavaPluginRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setImplicitOutputsFunction(BazelJavaRuleClasses.JAVA_LIBRARY_IMPLICIT_OUTPUTS)
+ .override(builder.copy("deps").validityPredicate(Attribute.ANY_EDGE))
+ .override(builder.copy("srcs").validityPredicate(Attribute.ANY_EDGE))
+ .add(attr("processor_class", STRING))
+ .removeAttribute("runtime_deps")
+ .removeAttribute("exports")
+ .removeAttribute("exported_plugins")
+ .build();
+ }
+}
+
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
new file mode 100644
index 0000000000..663b82ac92
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -0,0 +1,173 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+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.ImplicitOutputsFunction.fromFunctions;
+import static com.google.devtools.build.lib.packages.Type.BOOLEAN;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.packages.Type.STRING_LIST;
+import static com.google.devtools.build.lib.packages.Type.TRISTATE;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.cpp.BazelCppRuleClasses;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.PredicateWithMessage;
+import com.google.devtools.build.lib.packages.Rule;
+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;
+import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint;
+import com.google.devtools.build.lib.packages.TriState;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+import java.util.Set;
+
+/**
+ * Rule class definitions for Java rules.
+ */
+public class BazelJavaRuleClasses {
+
+ public static final PredicateWithMessage<Rule> JAVA_PACKAGE_NAMES = new PackageNameConstraint(
+ PackageNameConstraint.ANY_SEGMENT, "java", "javatests");
+
+ public static final ImplicitOutputsFunction JAVA_BINARY_IMPLICIT_OUTPUTS =
+ fromFunctions(JavaSemantics.JAVA_BINARY_CLASS_JAR, JavaSemantics.JAVA_BINARY_SOURCE_JAR,
+ JavaSemantics.JAVA_BINARY_DEPLOY_JAR, JavaSemantics.JAVA_BINARY_DEPLOY_SOURCE_JAR);
+
+ static final ImplicitOutputsFunction JAVA_LIBRARY_IMPLICIT_OUTPUTS =
+ fromFunctions(JavaSemantics.JAVA_LIBRARY_CLASS_JAR, JavaSemantics.JAVA_LIBRARY_SOURCE_JAR);
+
+ /**
+ * Common attributes for rules that depend on ijar.
+ */
+ @BlazeRule(name = "$ijar_base_rule",
+ type = RuleClassType.ABSTRACT)
+ public static final class IjarBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("$ijar", LABEL).cfg(HOST).exec().value(env.getLabel("//tools/defaults:ijar")))
+ .setPreferredDependencyPredicate(JavaSemantics.JAVA_SOURCE)
+ .build();
+ }
+ }
+
+
+ /**
+ * Common attributes for Java rules.
+ */
+ @BlazeRule(name = "$java_base_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { IjarBaseRule.class })
+ public static final class JavaBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr(":jvm", LABEL).cfg(HOST).value(JavaSemantics.JVM))
+ .add(attr(":host_jdk", LABEL).cfg(HOST).value(JavaSemantics.HOST_JDK))
+ .add(attr(":java_toolchain", LABEL).value(JavaSemantics.JAVA_TOOLCHAIN))
+ .add(attr("$java_langtools", LABEL).cfg(HOST)
+ .value(env.getLabel("//tools/defaults:java_langtools")))
+ .add(attr("$javac_bootclasspath", LABEL).cfg(HOST)
+ .value(env.getLabel(JavaSemantics.JAVAC_BOOTCLASSPATH_LABEL)))
+ .add(attr("$javabuilder", LABEL).cfg(HOST)
+ .value(env.getLabel(JavaSemantics.JAVABUILDER_LABEL)))
+ .add(attr("$singlejar", LABEL).cfg(HOST)
+ .value(env.getLabel(JavaSemantics.SINGLEJAR_LABEL)))
+ .build();
+ }
+ }
+
+ static final Set<String> ALLOWED_RULES_IN_DEPS = ImmutableSet.of(
+ "cc_binary", // NB: linkshared=1
+ "cc_library",
+ "genrule",
+ "genproto", // TODO(bazel-team): we should filter using providers instead (skylark rule).
+ "java_import",
+ "java_library",
+ "sh_binary",
+ "sh_library");
+
+ /**
+ * Common attributes for Java rules.
+ */
+ @BlazeRule(name = "$java_rule",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { BaseRuleClasses.RuleBase.class, JavaBaseRule.class })
+ public static final class JavaRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .override(builder.copy("deps")
+ .allowedFileTypes(JavaSemantics.JAR)
+ .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
+ .skipAnalysisTimeFileTypeCheck())
+ .add(attr("runtime_deps", LABEL_LIST)
+ .allowedFileTypes(JavaSemantics.JAR)
+ .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
+ .skipAnalysisTimeFileTypeCheck())
+ .add(attr("srcs", LABEL_LIST)
+ .orderIndependent()
+ .direct_compile_time_input()
+ .allowedFileTypes(JavaSemantics.JAVA_SOURCE, JavaSemantics.JAR,
+ JavaSemantics.SOURCE_JAR, JavaSemantics.PROPERTIES))
+ .add(attr("resources", LABEL_LIST).orderIndependent()
+ .allowedFileTypes(FileTypeSet.ANY_FILE))
+ .add(attr("plugins", LABEL_LIST).cfg(HOST).allowedRuleClasses("java_plugin")
+ .legacyAllowAnyFileType())
+ .add(attr(":java_plugins", LABEL_LIST)
+ .cfg(HOST)
+ .allowedRuleClasses("java_plugin")
+ .silentRuleClassFilter()
+ .value(JavaSemantics.JAVA_PLUGINS))
+ .add(attr("javacopts", STRING_LIST))
+ .build();
+ }
+ }
+
+ /**
+ * Base class for rule definitions producing Java binaries.
+ */
+ @BlazeRule(name = "$base_java_binary",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { JavaRule.class,
+ // java_binary and java_test require the crosstool C++ runtime
+ // libraries (libstdc++.so, libgcc_s.so).
+ // TODO(bazel-team): Add tests for Java+dynamic runtime.
+ BazelCppRuleClasses.CcLinkingRule.class })
+ public static final class BaseJavaBinaryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, final RuleDefinitionEnvironment env) {
+ return builder
+ .add(attr("classpath_resources", LABEL_LIST).legacyAllowAnyFileType())
+ .add(attr("jvm_flags", STRING_LIST))
+ .add(attr("main_class", STRING))
+ .add(attr("create_executable", BOOLEAN).nonconfigurable("internal").value(true))
+ .add(attr("deploy_manifest_lines", STRING_LIST))
+ .add(attr("stamp", TRISTATE).value(TriState.AUTO))
+ .add(attr(":java_launcher", LABEL).value(JavaSemantics.JAVA_LAUNCHER)) // blaze flag
+ .build();
+ }
+ }
+}
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
new file mode 100644
index 0000000000..b301161088
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
@@ -0,0 +1,341 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.AnalysisEnvironment;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
+import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.ComputedSubstitution;
+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.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder;
+import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression;
+import com.google.devtools.build.lib.rules.java.DirectDependencyProvider;
+import com.google.devtools.build.lib.rules.java.DirectDependencyProvider.Dependency;
+import com.google.devtools.build.lib.rules.java.JavaCommon;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts;
+import com.google.devtools.build.lib.rules.java.JavaCompilationHelper;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
+import com.google.devtools.build.lib.rules.java.JavaHelper;
+import com.google.devtools.build.lib.rules.java.JavaPrimaryClassProvider;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.rules.java.JavaUtil;
+import com.google.devtools.build.lib.rules.java.Jvm;
+import com.google.devtools.build.lib.rules.test.InstrumentedFilesCollector.InstrumentationSpec;
+import com.google.devtools.build.lib.util.FileType;
+import com.google.devtools.build.lib.util.FileTypeSet;
+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.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Semantics for Bazel Java rules
+ */
+public class BazelJavaSemantics implements JavaSemantics {
+
+ public static final BazelJavaSemantics INSTANCE = new BazelJavaSemantics();
+
+ private static final Template STUB_SCRIPT =
+ Template.forResource(BazelJavaSemantics.class, "java_stub_template.txt");
+
+ public static final InstrumentationSpec GREEDY_COLLECTION_SPEC = new InstrumentationSpec(
+ FileTypeSet.of(FileType.of(".sh"), JavaSemantics.JAVA_SOURCE),
+ "srcs", "deps", "data");
+
+ private BazelJavaSemantics() {
+ }
+
+ private boolean isJavaBinaryOrJavaTest(RuleContext ruleContext) {
+ String ruleClass = ruleContext.getRule().getRuleClass();
+ return ruleClass.equals("java_binary") || ruleClass.equals("java_test");
+ }
+
+ @Override
+ public void checkRule(RuleContext ruleContext, JavaCommon javaCommon) {
+ if (isJavaBinaryOrJavaTest(ruleContext)) {
+ checkMainClass(ruleContext, javaCommon);
+ }
+ }
+
+ private String getMainClassInternal(RuleContext ruleContext) {
+ return ruleContext.getRule().isAttrDefined("main_class", Type.STRING)
+ ? ruleContext.attributes().get("main_class", Type.STRING) : "";
+ }
+
+ private void checkMainClass(RuleContext ruleContext, JavaCommon javaCommon) {
+ boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ String mainClass = getMainClassInternal(ruleContext);
+
+ if (!createExecutable && !mainClass.isEmpty()) {
+ ruleContext.ruleError("main class must not be specified when executable is not created");
+ }
+
+ if (createExecutable && mainClass.isEmpty()) {
+ if (javaCommon.getSrcsArtifacts().isEmpty()) {
+ ruleContext.ruleError(
+ "need at least one of 'main_class', 'use_testrunner' or Java source files");
+ }
+ mainClass = javaCommon.determinePrimaryClass(javaCommon.getSrcsArtifacts());
+ if (mainClass == null) {
+ ruleContext.ruleError("cannot determine main class for launching "
+ + "(found neither a source file '" + ruleContext.getTarget().getName()
+ + ".java', nor a main_class attribute, and package name "
+ + "doesn't include 'java' or 'javatests')");
+ }
+ }
+ }
+
+ @Override
+ public String getMainClass(RuleContext ruleContext, JavaCommon javaCommon) {
+ checkMainClass(ruleContext, javaCommon);
+ return getMainClassInternal(ruleContext);
+ }
+
+ @Override
+ public ImmutableList<Artifact> collectResources(RuleContext ruleContext) {
+ if (!ruleContext.getRule().isAttrDefined("resources", Type.LABEL_LIST)) {
+ return ImmutableList.of();
+ }
+
+ return ruleContext.getPrerequisiteArtifacts("resources", Mode.TARGET).list();
+ }
+
+ @Override
+ public Artifact createInstrumentationMetadataArtifact(
+ AnalysisEnvironment analysisEnvironment, Artifact outputJar) {
+ return null;
+ }
+
+ @Override
+ public void buildJavaCommandLine(Collection<Artifact> outputs, BuildConfiguration configuration,
+ CustomCommandLine.Builder result) {
+ }
+
+ @Override
+ public void createStubAction(RuleContext ruleContext, final JavaCommon javaCommon,
+ List<String> jvmFlags, Artifact executable, String javaStartClass,
+ String javaExecutable) {
+
+ Preconditions.checkNotNull(jvmFlags);
+ Preconditions.checkNotNull(executable);
+ Preconditions.checkNotNull(javaStartClass);
+ Preconditions.checkNotNull(javaExecutable);
+ BuildConfiguration config = ruleContext.getConfiguration();
+
+ List<Substitution> arguments = new ArrayList<>();
+ arguments.add(Substitution.of("%javabin%", javaExecutable));
+ arguments.add(Substitution.of("%needs_runfiles%",
+ config.getFragment(Jvm.class).getJavaExecutable().isAbsolute() ? "0" : "1"));
+ arguments.add(new ComputedSubstitution("%classpath%") {
+ @Override
+ public String getValue() {
+ StringBuilder buffer = new StringBuilder();
+ Iterable<Artifact> jars = javaCommon.getRuntimeClasspath();
+ appendRunfilesRelativeEntries(buffer, jars, ':');
+ return buffer.toString();
+ }
+ });
+
+ arguments.add(Substitution.of("%java_start_class%",
+ ShellEscaper.escapeString(javaStartClass)));
+ arguments.add(Substitution.ofSpaceSeparatedList("%jvm_flags%", jvmFlags));
+
+ ruleContext.registerAction(new TemplateExpansionAction(
+ ruleContext.getActionOwner(), executable, STUB_SCRIPT, arguments, true));
+ }
+
+ /**
+ * Builds a class path by concatenating the root relative paths of the artifacts separated by the
+ * delimiter. Each relative path entry is prepended with "${RUNPATH}" which will be expanded by
+ * the stub script at runtime, to either "${JAVA_RUNFILES}/" or if we are lucky, the empty
+ * string.
+ *
+ * @param buffer the buffer to use for concatenating the entries
+ * @param artifacts the entries to concatenate in the buffer
+ * @param delimiter the delimiter character to separate the entries
+ */
+ private static void appendRunfilesRelativeEntries(StringBuilder buffer,
+ Iterable<Artifact> artifacts, char delimiter) {
+ for (Artifact artifact : artifacts) {
+ if (buffer.length() > 0) {
+ buffer.append(delimiter);
+ }
+ buffer.append("${RUNPATH}");
+ buffer.append(artifact.getRootRelativePath().getPathString());
+ }
+ }
+
+ @Override
+ public void addRunfilesForBinary(RuleContext ruleContext, Artifact launcher,
+ Runfiles.Builder runfilesBuilder) {
+ }
+
+ @Override
+ public void addRunfilesForLibrary(RuleContext ruleContext, Runfiles.Builder runfilesBuilder) {
+ }
+
+ @Override
+ public void collectTargetsTreatedAsDeps(
+ RuleContext ruleContext, ImmutableList.Builder<TransitiveInfoCollection> builder) {
+ }
+
+ @Override
+ public InstrumentationSpec getCoverageInstrumentationSpec() {
+ return GREEDY_COLLECTION_SPEC.withAttributes("srcs", "deps", "data", "exports", "runtime_deps");
+ }
+
+ @Override
+ public Iterable<String> getExtraJavacOpts(RuleContext ruleContext) {
+ return ImmutableList.<String>of();
+ }
+
+ @Override
+ public void addProviders(RuleContext ruleContext,
+ JavaCommon javaCommon,
+ List<String> jvmFlags,
+ Artifact classJar,
+ Artifact srcJar,
+ Artifact gensrcJar,
+ ImmutableMap<Artifact, Artifact> compilationToRuntimeJarMap,
+ JavaCompilationHelper helper,
+ NestedSetBuilder<Artifact> filesBuilder,
+ RuleConfiguredTargetBuilder ruleBuilder) {
+ if (!isJavaBinaryOrJavaTest(ruleContext)) {
+ Artifact outputDepsProto = helper.getOutputDepsProtoArtifact();
+ if (outputDepsProto != null && helper.getStrictJavaDeps() != StrictDepsMode.OFF) {
+ ImmutableList<Dependency> strictDependencies =
+ javaCommon.computeStrictDepsFromJavaAttributes(helper.getAttributes());
+ ruleBuilder.add(DirectDependencyProvider.class,
+ new DirectDependencyProvider(strictDependencies));
+ }
+ } else {
+ boolean createExec = ruleContext.attributes().get("create_executable", Type.BOOLEAN);
+ ruleBuilder.add(JavaPrimaryClassProvider.class,
+ new JavaPrimaryClassProvider(createExec ? getMainClassInternal(ruleContext) : null));
+ }
+ }
+
+
+ @Override
+ public Iterable<String> getJvmFlags(RuleContext ruleContext, JavaCommon javaCommon,
+ Artifact launcher, List<String> userJvmFlags) {
+ return userJvmFlags;
+ }
+
+ @Override
+ public String addCoverageSupport(JavaCompilationHelper helper,
+ JavaTargetAttributes.Builder attributes,
+ Artifact executable, Artifact instrumentationMetadata,
+ JavaCompilationArtifacts.Builder javaArtifactsBuilder, String mainClass) {
+ return mainClass;
+ }
+
+ @Override
+ public boolean useStrictJavaDeps(BuildConfiguration configuration) {
+ return true;
+ }
+
+ @Override
+ public CustomCommandLine buildSingleJarCommandLine(BuildConfiguration configuration,
+ Artifact output, String mainClass, ImmutableList<String> manifestLines,
+ Iterable<Artifact> buildInfoFiles, ImmutableList<Artifact> resources,
+ Iterable<Artifact> classpath, boolean includeBuildData,
+ Compression compression, Artifact launcher) {
+ return DeployArchiveBuilder.defaultSingleJarCommandLine(output, mainClass, manifestLines,
+ buildInfoFiles, resources, classpath, includeBuildData, compression, launcher).build();
+ }
+
+ @Override
+ public Collection<Artifact> translate(RuleContext ruleContext, JavaConfiguration javaConfig,
+ List<Artifact> messages) {
+ return ImmutableList.<Artifact>of();
+ }
+
+ @Override
+ public Artifact getLauncher(RuleContext ruleContext, JavaCommon common,
+ DeployArchiveBuilder deployArchiveBuilder, Runfiles.Builder runfilesBuilder,
+ List<String> jvmFlags, JavaTargetAttributes.Builder attributesBuilder) {
+ return JavaHelper.launcherArtifactForTarget(this, ruleContext);
+ }
+
+ @Override
+ public void addDependenciesForRunfiles(RuleContext ruleContext, Runfiles.Builder builder) {
+ }
+
+ @Override
+ public boolean forceUseJavaLauncherTarget(RuleContext ruleContext) {
+ return false;
+ }
+
+ @Override
+ public void addArtifactToJavaTargetAttribute(JavaTargetAttributes.Builder builder,
+ Artifact srcArtifact) {
+ }
+
+ @Override
+ public void commonDependencyProcessing(RuleContext ruleContext,
+ JavaTargetAttributes.Builder attributes,
+ Collection<? extends TransitiveInfoCollection> deps) {
+ }
+
+ @Override
+ public Collection<ActionInput> getExtraJavaCompileOutputs(PathFragment classDirectory) {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public PathFragment getJavaResourcePath(PathFragment path) {
+ PathFragment javaPath = JavaUtil.getJavaPath(path);
+ return javaPath == null ? path : javaPath;
+ }
+
+ @Override
+ public List<String> getExtraArguments(RuleContext ruleContext, JavaCommon javaCommon) {
+ if (ruleContext.getRule().getRuleClass().equals("java_test")) {
+ if (ruleContext.getConfiguration().getTestArguments().isEmpty()
+ && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (Artifact artifact : javaCommon.getSrcsArtifacts()) {
+ PathFragment path = artifact.getRootRelativePath();
+ String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path));
+ if (className != null) {
+ builder.add(className);
+ }
+ }
+ return builder.build();
+ }
+ }
+ return ImmutableList.<String>of();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTest.java
new file mode 100644
index 0000000000..ca94814ccf
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTest.java
@@ -0,0 +1,27 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.rules.java.JavaBinary;
+
+/**
+ * An implementation of {@code java_test} rules.
+ */
+public class BazelJavaTest extends JavaBinary implements RuleConfiguredTargetFactory {
+ public BazelJavaTest() {
+ super(BazelJavaSemantics.INSTANCE);
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
new file mode 100644
index 0000000000..fe881b7dda
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
@@ -0,0 +1,54 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.java;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+import static com.google.devtools.build.lib.packages.Type.TRISTATE;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.BaseJavaBinaryRule;
+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;
+import com.google.devtools.build.lib.packages.TriState;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+
+/**
+ * Rule definition for the java_test rule.
+ */
+@BlazeRule(name = "java_test",
+ type = RuleClassType.TEST,
+ ancestors = { BaseJavaBinaryRule.class,
+ BaseRuleClasses.TestBaseRule.class },
+ factoryClass = BazelJavaTest.class)
+public final class BazelJavaTestRule implements RuleDefinition {
+
+ private static final String JUNIT4_RUNNER = "org.junit.runner.JUnitCore";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
+ return builder
+ .setImplicitOutputsFunction(BazelJavaRuleClasses.JAVA_BINARY_IMPLICIT_OUTPUTS)
+ .override(attr("main_class", STRING).value(JUNIT4_RUNNER))
+ .override(attr("stamp", TRISTATE).value(TriState.NO))
+ .override(attr(":java_launcher", LABEL).value(JavaSemantics.JAVA_LAUNCHER))
+ .build();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt
new file mode 100644
index 0000000000..a17246f81d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt
@@ -0,0 +1,195 @@
+#!/bin/bash --posix
+# Copyright 2014 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script was generated from java_stub_template.txt. Please
+# don't edit it directly.
+#
+# If present, these flags should either be at the beginning of the command
+# line, or they should be wrapped in a --wrapper_script_flag=FLAG argument.
+#
+# --debug Launch the JVM in remote debugging mode listening
+# --debug=<port> to the specified port or the port set in the
+# DEFAULT_JVM_DEBUG_PORT environment variable (e.g.
+# 'export DEFAULT_JVM_DEBUG_PORT=8000') or else the
+# default port of 5005. The JVM starts suspended
+# unless the DEFAULT_JVM_DEBUG_SUSPEND environment
+# variable is set to 'n'.
+# --main_advice=<class> Run an alternate main class with the usual main
+# program and arguments appended as arguments.
+# --main_advice_classpath=<classpath>
+# Prepend additional class path entries.
+# --jvm_flag=<flag> Pass <flag> to the "java" command itself.
+# <flag> may contain spaces. Can be used multiple times.
+# --jvm_flags=<flags> Pass space-separated flags to the "java" command
+# itself. Can be used multiple times.
+# --singlejar Start the program from the packed-up deployment
+# jar rather than from the classpath.
+# --print_javabin Print the location of java executable binary and exit.
+#
+# The remainder of the command line is passed to the program.
+
+# Make it easy to insert 'set -x' or similar commands when debugging problems with this script.
+eval "$JAVA_STUB_DEBUG"
+
+# Prevent problems where the caller has exported CLASSPATH, causing our
+# computed value to be copied into the environment and double-counted
+# against the argv limit.
+unset CLASSPATH
+
+JVM_FLAGS_CMDLINE=()
+
+# Processes an argument for the wrapper. Returns 0 if the given argument
+# was recognized as an argument for this wrapper, and 1 if it was not.
+function process_wrapper_argument() {
+ case "$1" in
+ --debug) JVM_DEBUG_PORT="${DEFAULT_JVM_DEBUG_PORT:-5005}" ;;
+ --debug=*) JVM_DEBUG_PORT="${1#--debug=}" ;;
+ --main_advice=*) MAIN_ADVICE="${1#--main_advice=}" ;;
+ --main_advice_classpath=*) MAIN_ADVICE_CLASSPATH="${1#--main_advice_classpath=}" ;;
+ --jvm_flag=*) JVM_FLAGS_CMDLINE+=( "${1#--jvm_flag=}" ) ;;
+ --jvm_flags=*) JVM_FLAGS_CMDLINE+=( ${1#--jvm_flags=} ) ;;
+ --singlejar) SINGLEJAR=1 ;;
+ --print_javabin) PRINT_JAVABIN=1 ;;
+ *)
+ return 1 ;;
+ esac
+ return 0
+}
+
+die() {
+ printf "%s: $1\n" "$0" "${@:2}" >&2
+ exit 1
+}
+
+# Parse arguments sequentially until the first unrecognized arg is encountered.
+# Scan the remaining args for --wrapper_script_flag=X options and process them.
+ARGS=()
+for ARG in "$@"; do
+ if [[ "$ARG" == --wrapper_script_flag=* ]]; then
+ process_wrapper_argument "${ARG#--wrapper_script_flag=}" \
+ || die "invalid wrapper argument '%s'" "$ARG"
+ elif [[ "${#ARGS}" > 0 ]] || ! process_wrapper_argument "$ARG"; then
+ ARGS+=( "$ARG" )
+ fi
+done
+
+# Find our runfiles tree. We need this to construct the classpath
+# (unless --singlejar was passed).
+#
+# Call this program X. X was generated by a java_binary or java_test rule.
+# X may be invoked in many ways:
+# 1a) directly by a user, with $0 in the output tree
+# 1b) via 'bazel run' (similar to case 1a)
+# 2) directly by a user, with $0 in X's runfiles tree
+# 3) by another program Y which has a data dependency on X, with $0 in Y's runfiles tree
+# 4) via 'bazel test'
+# 5) by a genrule cmd, with $0 in the output tree
+# 6) case 3 in the context of a genrule
+#
+# For case 1, $0 will be a regular file, and the runfiles tree will be
+# at $0.runfiles.
+# For case 2 or 3, $0 will be a symlink to the file seen in case 1.
+# For case 4, $JAVA_RUNFILES and $TEST_SRCDIR should already be set.
+# Case 5 is handled like case 1.
+# Case 6 is handled like case 3.
+
+case "$0" in
+ /*) self="$0" ;;
+ *) self="$PWD/$0" ;;
+esac
+
+if [[ "$SINGLEJAR" != 1 || "%needs_runfiles%" == 1 ]]; then
+ if [[ -z "$JAVA_RUNFILES" ]]; then
+ while true; do
+ if [[ -e "$self.runfiles" ]]; then
+ JAVA_RUNFILES="$self.runfiles"
+ break
+ fi
+ if [[ $self == *.runfiles/* ]]; then
+ JAVA_RUNFILES="${self%.runfiles/*}.runfiles"
+ # don't break; this value is only a last resort for case 6b
+ fi
+ if [[ ! -L "$self" ]]; then
+ break
+ fi
+ readlink="$(readlink "$self")"
+ if [[ "$readlink" = /* ]]; then
+ self="$readlink"
+ else
+ # resolve relative symlink
+ self="${self%/*}/$readlink"
+ fi
+ done
+ if [[ -n "$JAVA_RUNFILES" ]]; then
+ export TEST_SRCDIR=${TEST_SRCDIR:-$JAVA_RUNFILES}
+ elif [[ -f "${self}_deploy.jar" && "%needs_runfiles%" == 0 ]]; then
+ SINGLEJAR=1;
+ else
+ die 'Cannot locate runfiles directory. (Set $JAVA_RUNFILES to inhibit searching.)'
+ fi
+ fi
+fi
+
+# Set JAVABIN to the path to the JVM launcher.
+%javabin%
+
+if [[ "$PRINT_JAVABIN" == 1 || "%java_start_class%" == "--print_javabin" ]]; then
+ echo -n "$JAVABIN"
+ exit 0
+fi
+
+if [[ "$SINGLEJAR" == 1 ]]; then
+ CLASSPATH="${self}_deploy.jar"
+ # Check for the deploy jar now. If it doesn't exist, we can print a
+ # more helpful error message than the JVM.
+ [[ -r "$CLASSPATH" ]] \
+ || die "Option --singlejar was passed, but %s does not exist.\n (You may need to build it explicitly.)" "$CLASSPATH"
+else
+ # Create the shortest classpath we can, by making it relative if possible.
+ RUNPATH="${JAVA_RUNFILES}/"
+ RUNPATH="${RUNPATH#$PWD/}"
+ CLASSPATH=%classpath%
+fi
+
+if [[ -n "$JVM_DEBUG_PORT" ]]; then
+ JVM_DEBUG_SUSPEND=${DEFAULT_JVM_DEBUG_SUSPEND:-"y"}
+ JVM_DEBUG_FLAGS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=${JVM_DEBUG_SUSPEND},address=${JVM_DEBUG_PORT}"
+fi
+
+if [[ -n "$MAIN_ADVICE_CLASSPATH" ]]; then
+ CLASSPATH="${MAIN_ADVICE_CLASSPATH}:${CLASSPATH}"
+fi
+
+# Check if TEST_TMPDIR is available to use for scratch.
+if [[ -n "$TEST_TMPDIR" && -d "$TEST_TMPDIR" ]]; then
+ JVM_FLAGS+=" -Djava.io.tmpdir=$TEST_TMPDIR"
+fi
+
+ARGS=(
+ ${JVM_DEBUG_FLAGS}
+ ${JVM_FLAGS}
+ %jvm_flags%
+ "${JVM_FLAGS_CMDLINE[@]}"
+ ${MAIN_ADVICE}
+ %java_start_class%
+ "${ARGS[@]}")
+
+# Linux per-arg limit MAX_ARG_STRLEN == 128k!
+if (("${#CLASSPATH}" > 120000)); then
+ set +o posix # Enable process substitution.
+ exec $JAVABIN -classpath @<(echo $CLASSPATH) "${ARGS[@]}"
+else
+ exec $JAVABIN -classpath $CLASSPATH "${ARGS[@]}"
+fi
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTest.java
new file mode 100644
index 0000000000..f45ca086bf
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTest.java
@@ -0,0 +1,57 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.objc;
+
+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;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+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.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.rules.objc.IosTest;
+import com.google.devtools.build.lib.rules.objc.ObjcCommon;
+import com.google.devtools.build.lib.rules.objc.XcodeProvider;
+
+/**
+ * Implementation for ios_test rule in Bazel.
+ */
+public final class BazelIosTest extends IosTest {
+ static final String IOS_TEST_ON_BAZEL_ATTR = "$ios_test_on_bazel";
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext, ObjcCommon common,
+ XcodeProvider xcodeProvider, NestedSet<Artifact> filesToBuild) throws InterruptedException {
+ Artifact testRunner = ruleContext.getPrerequisiteArtifact(IOS_TEST_ON_BAZEL_ATTR, Mode.TARGET);
+ Runfiles runfiles = new Runfiles.Builder()
+ .addArtifact(testRunner)
+ .build();
+ RunfilesSupport runfilesSupport =
+ RunfilesSupport.withExecutable(ruleContext, runfiles, testRunner);
+
+ return new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(NestedSetBuilder.<Artifact>stableOrder()
+ .addTransitive(filesToBuild)
+ .add(testRunner)
+ .build())
+ .add(XcodeProvider.class, xcodeProvider)
+ .add(RunfilesProvider.class, RunfilesProvider.simple(runfiles))
+ .setRunfilesSupport(runfilesSupport, testRunner)
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java
new file mode 100644
index 0000000000..114d454e79
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/objc/BazelIosTestRule.java
@@ -0,0 +1,69 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.objc;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.rules.objc.ApplicationSupport;
+import com.google.devtools.build.lib.rules.objc.ObjcRuleClasses;
+import com.google.devtools.build.lib.rules.objc.XcodeSupport;
+
+/**
+ * Rule definition for the ios_test rule.
+ */
+@BlazeRule(name = "ios_test",
+ type = RuleClassType.TEST,
+ ancestors = { ObjcRuleClasses.IosTestBaseRule.class,
+ BaseRuleClasses.TestBaseRule.class },
+ factoryClass = BazelIosTest.class)
+public final class BazelIosTestRule implements RuleDefinition {
+ @Override
+ public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) {
+ return builder
+ /*<!-- #BLAZE_RULE(ios_test).IMPLICIT_OUTPUTS -->
+ <ul>
+ <li><code><var>name</var>.ipa</code>: the test bundle as an
+ <code>.ipa</code> file
+ <li><code><var>name</var>.xcodeproj/project.pbxproj: An Xcode project file which can be
+ used to develop or build on a Mac.</li>
+ </ul>
+ <!-- #END_BLAZE_RULE.IMPLICIT_OUTPUTS -->*/
+ .setImplicitOutputsFunction(
+ ImplicitOutputsFunction.fromFunctions(ApplicationSupport.IPA, XcodeSupport.PBXPROJ))
+ .add(attr(BazelIosTest.IOS_TEST_ON_BAZEL_ATTR, LABEL)
+ .value(env.getLabel("//tools/objc:ios_test_on_bazel")).exec())
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = ios_test, TYPE = TEST, FAMILY = Objective-C) -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>This rule provides a way to build iOS unit tests written in KIF, GTM and XCTest test frameworks
+on both iOS simulator and real devices.
+</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<!-- #END_BLAZE_RULE -->*/
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
new file mode 100644
index 0000000000..39d4a0c15c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShBinaryRule.java
@@ -0,0 +1,41 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.BazelBaseRuleClasses;
+import com.google.devtools.build.lib.bazel.rules.sh.BazelShRuleClasses.ShRule;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+
+/**
+ * Rule definition for the sh_binary rule.
+ */
+@BlazeRule(name = "sh_binary",
+ ancestors = { ShRule.class, BazelBaseRuleClasses.BinaryBaseRule.class },
+ factoryClass = ShBinary.class)
+public final class BazelShBinaryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder.add(
+ attr("bash_version", STRING)
+ .value(BazelShRuleClasses.DEFAULT_BASH_VERSION)
+ .allowedValues(BazelShRuleClasses.BASH_VERSION_ALLOWED_VALUES)).build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java
new file mode 100644
index 0000000000..9d9640b7b3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShLibraryRule.java
@@ -0,0 +1,113 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+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.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+
+/**
+ * Rule definition for the sh_library rule.
+ */
+@BlazeRule(name = "sh_library",
+ ancestors = { ShRule.class },
+ factoryClass = ShLibrary.class)
+public final class BazelShLibraryRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(sh_library).ATTRIBUTE(deps) -->
+ The list of other targets to be aggregated in to this "library" target.
+ <i>(List of <a href="build-ref.html#labels">labels</a>; optional)</i><br/>
+ See general comments about <code>deps</code>
+ at <a href="#common-attributes">Attributes common to all build rules</a>.
+ You should use this attribute to list other
+ <code>sh_library</code> or <code>proto_library</code> rules that provide
+ interpreted program source code depended on by the code in
+ <code>srcs</code>. If you depend on a <code>proto_library</code> target,
+ the proto sources in that target will be included in this library, but
+ no generated files will be built.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+
+ /* <!-- #BLAZE_RULE(sh_library).ATTRIBUTE(srcs) -->
+ The list of input files.
+ <i>(List of <a href="build-ref.html#labels">labels</a>,
+ optional)</i><br/>
+ You should use this attribute to list interpreted program
+ source files that belong to this package, such as additional
+ files containing Bourne shell subroutines, loaded via the shell's
+ <code>source</code> or <code>.</code> command.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE -->*/
+ .override(attr("srcs", LABEL_LIST).legacyAllowAnyFileType())
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = sh_library, TYPE = LIBRARY, FAMILY = Shell) -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>
+ The main use for this rule is to aggregate together a logical
+ "library" consisting of related scripts&mdash;programs in an
+ interpreted language that does not require compilation or linking,
+ such as the Bourne shell&mdash;and any data those programs need at
+ run-time. Such "libraries" can then be used from
+ the <code>data</code> attribute of one or
+ more <code>sh_binary</code> rules.
+</p>
+
+<p>
+ Historically, a second use was to aggregate a collection of data files
+ together, to ensure that they are available at runtime in
+ the <code>.runfiles</code> area of one or more <code>*_binary</code>
+ rules (not necessarily <code>sh_binary</code>).
+ However, the <a href="#filegroup"><code>filegroup()</code></a> rule
+ should be used now; it is intended to replace this use of
+ <code>sh_library</code>.
+</p>
+
+<p>
+ In interpreted programming languages, there's not always a clear
+ distinction between "code" and "data": after all, the program is
+ just "data" from the interpreter's point of view. For this reason
+ (and historical accident) this rule has three attributes which are
+ all essentially equivalent: <code>srcs</code>, <code>deps</code>
+ and <code>data</code>.
+ The recommended usage of each attribute is mentioned below. The
+ current implementation does not distinguish the elements of these lists.
+ All three attributes accept rules, source files and derived files.
+</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="sh_library_examples">Examples</h4>
+
+<pre class="code">
+sh_library(
+ name = "foo",
+ data = [
+ ":foo_service_script", # a sh_binary with srcs
+ ":deploy_foo", # another sh_binary with srcs
+ ],
+)
+</pre>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java
new file mode 100644
index 0000000000..6f66465726
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShRuleClasses.java
@@ -0,0 +1,101 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromTemplates;
+import static com.google.devtools.build.lib.packages.Type.LABEL_LIST;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.PredicateWithMessage;
+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;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/**
+ * Rule definitions for rule classes implementing shell support.
+ */
+public final class BazelShRuleClasses {
+
+ static final Collection<String> ALLOWED_RULES_IN_DEPS_WITH_WARNING = ImmutableSet.of(
+ "filegroup", "Fileset", "genrule", "sh_binary", "sh_test", "test_suite");
+
+ /**
+ * Common attributes for shell rules.
+ */
+ @BlazeRule(name = "$sh_target",
+ type = RuleClassType.ABSTRACT,
+ ancestors = { BaseRuleClasses.RuleBase.class })
+ public static final class ShRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .add(attr("srcs", LABEL_LIST).mandatory().legacyAllowAnyFileType())
+ .override(builder.copy("deps")
+ .allowedRuleClasses("sh_library", "proto_library")
+ .allowedRuleClassesWithWarning(ALLOWED_RULES_IN_DEPS_WITH_WARNING)
+ .allowedFileTypes())
+ .build();
+ }
+ }
+
+ /**
+ * Defines the file name of an sh_binary's implicit .sar (script package) output.
+ */
+ static final ImplicitOutputsFunction SAR_PACKAGE_FILENAME =
+ fromTemplates("%{name}.sar");
+
+ /**
+ * Convenience structure for the bash dependency combinations defined
+ * by BASH_BINARY_BINDINGS.
+ */
+ static class BashBinaryBinding {
+ public final String execPath;
+ public BashBinaryBinding(@Nullable String execPath) {
+ this.execPath = execPath;
+ }
+ }
+
+ /**
+ * Attribute value specifying the local system's bash version.
+ */
+ static final String SYSTEM_BASH_VERSION = "system";
+
+ static final Map<String, BashBinaryBinding> BASH_BINARY_BINDINGS =
+ ImmutableMap.of(
+ // "system": don't package any bash with the target, but rather use whatever is
+ // available on the system the script is run on.
+ SYSTEM_BASH_VERSION, new BashBinaryBinding("/bin/bash")
+ );
+
+ static final String DEFAULT_BASH_VERSION = SYSTEM_BASH_VERSION;
+
+ // TODO(bazel-team): refactor sh_binary and sh_base to have a common root
+ // with srcs and bash_version attributes
+ static final PredicateWithMessage<Object> BASH_VERSION_ALLOWED_VALUES =
+ new AllowedValueSet(BASH_BINARY_BINDINGS.keySet());
+}
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
new file mode 100644
index 0000000000..4a1e51f019
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/BazelShTestRule.java
@@ -0,0 +1,44 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.BlazeRule;
+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.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+
+/**
+ * Rule definition for the sh_test rule.
+ */
+@BlazeRule(name = "sh_test",
+ type = RuleClassType.TEST,
+ ancestors = { ShRule.class, BaseRuleClasses.TestBaseRule.class },
+ factoryClass = ShTest.class)
+public final class BazelShTestRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .add(attr("bash_version", STRING)
+ .value(BazelShRuleClasses.DEFAULT_BASH_VERSION)
+ .allowedValues(BazelShRuleClasses.BASH_VERSION_ALLOWED_VALUES))
+ .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
new file mode 100644
index 0000000000..4e6ba814a3
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
@@ -0,0 +1,82 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import com.google.common.collect.ImmutableList;
+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;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+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.ExecutableSymlinkAction;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+/**
+ * Implementation for the sh_binary rule.
+ */
+public class ShBinary implements RuleConfiguredTargetFactory {
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext) {
+ ImmutableList<Artifact> srcs = ruleContext.getPrerequisiteArtifacts("srcs", Mode.TARGET).list();
+ if (srcs.size() != 1) {
+ ruleContext.attributeError("srcs", "you must specify exactly one file in 'srcs'");
+ return null;
+ }
+
+ Artifact symlink = ruleContext.createOutputArtifact();
+ Artifact src = srcs.get(0);
+ Artifact executableScript = getExecutableScript(ruleContext, src);
+ // The interpretation of this deceptively simple yet incredibly generic rule is complicated
+ // by the distinction between targets and (not properly encapsulated) artifacts. It depends
+ // on the notion of other rule's "files-to-build" sets, which are undocumented, making it
+ // impossible to give a precise definition of what this rule does in all cases (e.g. what
+ // happens when srcs = ['x', 'y'] but 'x' is an empty filegroup?). This is a pervasive
+ // problem in Blaze.
+ ruleContext.registerAction(
+ new ExecutableSymlinkAction(ruleContext.getActionOwner(), executableScript, symlink));
+
+ NestedSet<Artifact> filesToBuild = NestedSetBuilder.<Artifact>stableOrder()
+ .add(src)
+ .add(executableScript) // May be the same as src, in which case set semantics apply.
+ .add(symlink)
+ .build();
+ Runfiles runfiles = new Runfiles.Builder()
+ .addTransitiveArtifacts(filesToBuild)
+ .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES)
+ .build();
+ RunfilesSupport runfilesSupport = RunfilesSupport.withExecutable(
+ ruleContext, runfiles, symlink);
+ return new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(filesToBuild)
+ .setRunfilesSupport(runfilesSupport, symlink)
+ .addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles))
+ .build();
+ }
+
+ /**
+ * Hook for sh_test to provide the executable.
+ *
+ * @param ruleContext
+ * @param src
+ */
+ protected Artifact getExecutableScript(RuleContext ruleContext, Artifact src) {
+ return src;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java
new file mode 100644
index 0000000000..e2744ea0d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java
@@ -0,0 +1,47 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+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;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+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.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+/**
+ * Implementation for the sh_library rule.
+ */
+public class ShLibrary implements RuleConfiguredTargetFactory {
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext) {
+ NestedSet<Artifact> filesToBuild = NestedSetBuilder.<Artifact>stableOrder()
+ .addAll(ruleContext.getPrerequisiteArtifacts("srcs", Mode.TARGET).list())
+ .addAll(ruleContext.getPrerequisiteArtifacts("deps", Mode.TARGET).list())
+ .addAll(ruleContext.getPrerequisiteArtifacts("data", Mode.DATA).list())
+ .build();
+ Runfiles runfiles = new Runfiles.Builder()
+ .addTransitiveArtifacts(filesToBuild)
+ .build();
+ return new RuleConfiguredTargetBuilder(ruleContext)
+ .setFilesToBuild(filesToBuild)
+ .addProvider(RunfilesProvider.class, RunfilesProvider.simple(runfiles))
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShTest.java
new file mode 100644
index 0000000000..cc965aa405
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShTest.java
@@ -0,0 +1,53 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.bazel.rules.sh;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+/**
+ * Implementation for sh_test rules.
+ */
+public class ShTest extends ShBinary implements RuleConfiguredTargetFactory {
+
+ @Override
+ protected Artifact getExecutableScript(RuleContext ruleContext, Artifact src) {
+ if (ruleContext.attributes().get("bash_version", Type.STRING)
+ .equals(BazelShRuleClasses.SYSTEM_BASH_VERSION)) {
+ return src;
+ }
+
+ // What *will* this script run with the wrapper?
+ PathFragment newOutput = src.getRootRelativePath().getParentDirectory().getRelative(
+ ruleContext.getLabel().getName() + "_runner.sh");
+ Artifact testRunner = ruleContext.getAnalysisEnvironment().getDerivedArtifact(
+ newOutput, ruleContext.getConfiguration().getBinDirectory());
+
+ String bashPath = BazelShRuleClasses.BASH_BINARY_BINDINGS
+ .get(BazelShRuleClasses.SYSTEM_BASH_VERSION).execPath;
+
+ // Generate the runner contents.
+ String runnerContents =
+ "#!/bin/bash\n"
+ + bashPath + " \"" + src.getRootRelativePath().getPathString() + "\" \"$@\"\n";
+
+ ruleContext.registerAction(
+ new FileWriteAction(ruleContext.getActionOwner(), testRunner, runnerContents, true));
+ return testRunner;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java
new file mode 100644
index 0000000000..c7f3677b1f
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpArchiveRule.java
@@ -0,0 +1,113 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * Rule definition for the http_archive rule.
+ */
+@BlazeRule(name = HttpArchiveRule.NAME,
+ type = RuleClassType.WORKSPACE,
+ ancestors = { WorkspaceBaseRule.class },
+ factoryClass = WorkspaceConfiguredTargetFactory.class)
+public class HttpArchiveRule implements RuleDefinition {
+
+ public static final String NAME = "http_archive";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(http_archive).ATTRIBUTE(url) -->
+ A URL to an archive file containing a Bazel repository
+
+ <p>This must be an http URL that ends with .zip. There is no support for authentication or
+ redirection.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("url", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(http_archive).ATTRIBUTE(sha256) -->
+ The expected SHA-256 hash of the file downloaded
+
+ <p>This must match the SHA-256 hash of the file downloaded.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("sha256", STRING).mandatory())
+ .setWorkspaceOnly()
+ .build();
+ }
+}
+
+/*<!-- #BLAZE_RULE (NAME = http_archive, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Downloads a Bazel repository as a compressed archive file, decompresses it, and makes its
+ targets available for binding.</p>
+
+<p>Only Zip-formatted archives with the .zip extension are supported.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="http_archive_examples">Examples</h4>
+
+<p>Suppose the current repository contains the source code for a chat program, rooted at the
+ directory <i>~/chat-app</i>. It needs to depend on an SSL library which is available from
+ <i>http://example.com/openssl.zip</i>. This .zip file contains the following directory
+ structure:</p>
+
+<pre class="code">
+WORKSPACE
+src/
+ BUILD
+ openssl.cc
+ openssl.h
+</pre>
+
+<p><i>src/BUILD</i> contains the following target definition:</p>
+
+<pre class="code">
+cc_library(
+ name = "openssl-lib",
+ srcs = ["openssl.cc"],
+ hdrs = ["openssl.h"],
+)
+</pre>
+
+<p>Targets in the <i>~/chat-app</i> repository can depend on this target if the following lines are
+ added to <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+http_archive(
+ name = "my-ssl",
+ url = "http://example.com/openssl.zip",
+ sha256 = "03a58ac630e59778f328af4bcc4acb4f80208ed4",
+)
+
+bind(
+ name = "openssl",
+ actual = "@my-ssl//src:openssl-lib",
+)
+</pre>
+
+<p>See <a href="#bind_examples">Bind</a> for how to use bound targets.</p>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java
new file mode 100644
index 0000000000..862c6d76d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/HttpJarRule.java
@@ -0,0 +1,91 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * Rule definition for the http_jar rule.
+ */
+@BlazeRule(name = HttpJarRule.NAME,
+ type = RuleClassType.WORKSPACE,
+ ancestors = { WorkspaceBaseRule.class },
+ factoryClass = WorkspaceConfiguredTargetFactory.class)
+public class HttpJarRule implements RuleDefinition {
+
+ public static final String NAME = "http_jar";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(http_jar).ATTRIBUTE(url) -->
+ A URL to an archive file containing a Bazel repository
+
+ <p>This must be an http or https URL that ends with .jar. Redirects are not followed.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("url", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(http_jar).ATTRIBUTE(sha256) -->
+ The expected SHA-256 of the file downloaded
+
+ <p>This must match the SHA-256 of the file downloaded.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("sha256", STRING).mandatory())
+ .setWorkspaceOnly()
+ .build();
+ }
+}
+/*<!-- #BLAZE_RULE (NAME = http_jar, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Downloads a jar from a URL and makes it available to be used as a Java dependency.</p>
+
+<p>Downloaded files must have a .jar extension.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="http_jar_examples">Examples</h4>
+
+<p>Suppose the current repository contains the source code for a chat program, rooted at the
+ directory <i>~/chat-app</i>. It needs to depend on an SSL library which is available from
+ <i>http://example.com/openssl-0.2.jar</i>.</p>
+
+<p>Targets in the <i>~/chat-app</i> repository can depend on this target if the following lines are
+ added to <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+http_jar(
+ name = "my-ssl",
+ url = "http://example.com/openssl-0.2.jar",
+ sha256 = "03a58ac630e59778f328af4bcc4acb4f80208ed4",
+)
+
+bind(
+ name = "openssl",
+ actual = "@my-ssl//jar:openssl-0.2.jar",
+)
+</pre>
+
+<p>See <a href="#bind_examples">Bind</a> for how to use bound targets.</p>
+
+<!-- #END_BLAZE_RULE -->*/ \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java
new file mode 100644
index 0000000000..b904bc5dcb
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/LocalRepositoryRule.java
@@ -0,0 +1,85 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * Rule definition for the local_repository rule.
+ */
+@BlazeRule(name = LocalRepositoryRule.NAME,
+ type = RuleClassType.WORKSPACE,
+ ancestors = { WorkspaceBaseRule.class },
+ factoryClass = WorkspaceConfiguredTargetFactory.class)
+public class LocalRepositoryRule implements RuleDefinition {
+
+ public static final String NAME = "local_repository";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(local_repository).ATTRIBUTE(path) -->
+ The path to the local repository's directory.
+
+ <p>This must be an absolute path to the directory containing the repository's
+ <i>WORKSPACE</i> file.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("path", STRING).mandatory())
+ .setWorkspaceOnly()
+ .build();
+ }
+}
+/*<!-- #BLAZE_RULE (NAME = local_repository, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Allows targets from a local directory to be bound. This means that the current repository can
+ use targets defined in this other directory. See the <a href="#bind_examples">bind section</a>
+ for more details.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="local_repository_examples">Examples</h4>
+
+<p>Suppose the current repository is a chat client, rooted at the directory <i>~/chat-app</i>. It
+ would like to use an SSL library which is defined in a different repository: <i>~/ssl</i>. The
+ SSL library has a target <code>//src:openssl-lib</code>.</p>
+
+<p>The user can add a dependency on this target by adding the following lines to
+ <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+local_repository(
+ name = "my-ssl",
+ path = "/home/user/ssl",
+)
+
+bind(
+ name = "openssl",
+ actual = "@my-ssl//src:openssl-lib",
+)
+</pre>
+
+<p>See <a href="#bind_examples">Bind</a> for how to use bound targets.</p>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java
new file mode 100644
index 0000000000..f4496dd2d8
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/MavenJarRule.java
@@ -0,0 +1,127 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+import com.google.devtools.build.lib.packages.Type;
+
+/**
+ * Rule definition for the maven_jar rule.
+ */
+@BlazeRule(name = MavenJarRule.NAME,
+ type = RuleClassType.WORKSPACE,
+ ancestors = { WorkspaceBaseRule.class },
+ factoryClass = WorkspaceConfiguredTargetFactory.class)
+public class MavenJarRule implements RuleDefinition {
+
+ public static final String NAME = "maven_jar";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(maven_jar).ATTRIBUTE(artifact_id) -->
+ The artifactId of the Maven dependency.
+
+ <p>Required.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("artifact_id", Type.STRING).mandatory())
+ /* <!-- #BLAZE_RULE(maven_jar).ATTRIBUTE(group_id) -->
+ The groupId of the Maven dependency.
+
+ <p>Required.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("group_id", Type.STRING).mandatory())
+ /* <!-- #BLAZE_RULE(maven_jar).ATTRIBUTE(version) -->
+ The version of the Maven dependency.
+
+ <p>Required.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("version", Type.STRING).mandatory())
+ /* <!-- #BLAZE_RULE(maven_jar).ATTRIBUTE(repositories) -->
+ A list of repositories to use to attempt to fetch the jar.
+
+ <p>Defaults to Maven Central ("repo1.maven.org"). If repositories are specified, they will
+ be checked in the order listed here (Maven Central will not be checked in this case,
+ unless it is on the list).</p>
+
+ <p><b>To be implemented: add a maven_repositories rule that allows a list of repositories
+ to be labeled.</b></p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("repositories", Type.STRING_LIST))
+ /* <!-- #BLAZE_RULE(maven_jar).ATTRIBUTE(exclusions) -->
+ Transitive dependencies of this dependency that should not be downloaded.
+
+ <p>Defaults to None: Bazel will download all of the dependencies requested by the Maven
+ dependency. If exclusions are specified, they will not be downloaded.</p>
+
+ <p>Exclusions are specified in the format "<group_id>:<artifact_id>", for example,
+ "com.google.guava:guava".</p>
+
+ <p><b>Not yet implemented.</b></p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("exclusions", Type.STRING_LIST))
+ .setWorkspaceOnly()
+ .build();
+ }
+}
+/*<!-- #BLAZE_RULE (NAME = maven_jar, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Downloads a jar from Maven and makes it available to be used as a Java dependency.</p>
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="http_jar_examples">Examples</h4>
+
+Suppose that the current repostory contains a java_library target that needs to depend on Guava.
+Using Maven, this dependency would be defined in the pom.xml file as:
+
+<pre>
+<dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>18.0</version>
+</dependency>
+</pre>
+
+In Bazel, the following lines can be added to the WORKSPACE file:
+
+<pre>
+maven_jar(
+ name = "guava",
+ group_id = "com.google.guava",
+ artifact_id = "guava",
+ version = "18.0",
+)
+
+bind(
+ name = "guava-jar",
+ actual = "@guava//jar"
+)
+</pre>
+
+Then the java_library can depend on <code>//external:guava-jar</code>.
+
+<p>See <a href="#bind_examples">Bind</a> for how to use bound targets.</p>
+
+<!-- #END_BLAZE_RULE -->*/
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java
new file mode 100644
index 0000000000..0061d3de11
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/NewLocalRepositoryRule.java
@@ -0,0 +1,135 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * Rule definition for the new_repository rule.
+ */
+@BlazeRule(name = NewLocalRepositoryRule.NAME,
+ type = RuleClassType.WORKSPACE,
+ ancestors = { WorkspaceBaseRule.class },
+ factoryClass = WorkspaceConfiguredTargetFactory.class)
+public class NewLocalRepositoryRule implements RuleDefinition {
+ public static final String NAME = "new_local_repository";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ /* <!-- #BLAZE_RULE(new_local_repository).ATTRIBUTE(path) -->
+ A path on the local filesystem.
+
+ <p>This must be an absolute path to an existing file or a directory.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("path", STRING).mandatory())
+ /* <!-- #BLAZE_RULE(new_local_repository).ATTRIBUTE(build_file) -->
+ A file to use as a BUILD file for this directory.
+
+ <p>This path must be relative to the build's workspace. The file does not need to be named
+ BUILD, but can be (something like BUILD.new-repo-name may work well for distinguishing it
+ from the repository's actual BUILD files.</p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("build_file", STRING).mandatory())
+ .setWorkspaceOnly()
+ .build();
+ }
+}
+/*<!-- #BLAZE_RULE (NAME = new_local_repository, TYPE = OTHER, FAMILY = General)[GENERIC_RULE] -->
+
+${ATTRIBUTE_SIGNATURE}
+
+<p>Allows a local directory to be turned into a Bazel repository. This means that the current
+ repository can define and use targets from anywhere on the filesystem.</p>
+
+<p>This rule creates a Bazel repository by creating a WORKSPACE file and subdirectory containing
+symlinks to the BUILD file and path given. The build file should create targets relative to the
+path, which can then be bound and used by the current build.
+
+${ATTRIBUTE_DEFINITION}
+
+<h4 id="new_local_repository_examples">Examples</h4>
+
+<p>Suppose the current repository is a chat client, rooted at the directory <i>~/chat-app</i>. It
+ would like to use an SSL library which is defined in a different directory: <i>~/ssl</i>.</p>
+
+<p>The user can add a dependency by creating a BUILD file for the SSL library
+(~/chat-app/BUILD.my-ssl) containing:
+
+<pre class="code">
+java_library(
+ name = "openssl",
+ srcs = glob(['ssl/*.java'])
+)
+</pre>
+
+<p>Then they can add the following lines to <i>~/chat-app/WORKSPACE</i>:</p>
+
+<pre class="code">
+new_local_repository(
+ name = "my-ssl",
+ path = "/home/user/ssl",
+ build_file = "BUILD.my-ssl",
+)
+
+bind(
+ name = "openssl",
+ actual = "@my-ssl//my-ssl:openssl",
+)
+</pre>
+
+<p>This will create a @my-ssl repository containing a my-ssl package that contains a symlink to
+/home/user/ssl named ssl (so the BUILD file must refer to paths within /home/user/ssl relative to
+ssl).</p>
+
+<p>See <a href="#bind_examples">Bind</a> for how to use bound targets.</p>
+
+<p>You can also use <code>new_local_repository</code> to include single files, not just
+directories. For example, suppose you had a jar file at /home/username/Downloads/piano.jar. You
+could add just that file to your build by adding the following to your WORKSPACE file:
+
+<pre class="code">
+new_local_repository(
+ name = "piano",
+ path = "/home/username/Downloads/piano.jar",
+ build_file = "BUILD.piano",
+)
+
+bind(
+ name = "music",
+ actual = "@piano//piano:play-music",
+)
+</pre>
+
+<p>And creating the following BUILD file:</p>
+
+<pre class="code">
+java_import(
+ name = "play-music",
+ jars = ["piano.jar"],
+)
+</pre>
+
+Then targets can depend on //external:music to use piano.jar.
+
+<!-- #END_BLAZE_RULE -->*/ \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java
new file mode 100644
index 0000000000..2719cb8993
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceBaseRule.java
@@ -0,0 +1,34 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import com.google.devtools.build.lib.analysis.BlazeRule;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+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;
+
+/**
+ * Base rule for rules in the WORKSPACE file.
+ */
+@BlazeRule(name = "$workspace_base_rule",
+ type = RuleClassType.ABSTRACT)
+public class WorkspaceBaseRule implements RuleDefinition {
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder.build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceConfiguredTargetFactory.java
new file mode 100644
index 0000000000..616222876c
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/workspace/WorkspaceConfiguredTargetFactory.java
@@ -0,0 +1,37 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.bazel.rules.workspace;
+
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
+
+/**
+ * Implementation of workspace rules. Generally, these don't have any providers, since they
+ * "forward" to the SkyFunctions which actually create the repositories and then are accessed via
+ * "normal" rules.
+ */
+public class WorkspaceConfiguredTargetFactory implements RuleConfiguredTargetFactory {
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+ return new RuleConfiguredTargetBuilder(ruleContext)
+ .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
+ .build();
+ }
+
+}