diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/bazel/rules')
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—programs in an + interpreted language that does not require compilation or linking, + such as the Bourne shell—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(); + } + +} |