diff --git a/MODULE.bazel b/MODULE.bazel index 6ca96909a23f89..ca312dac65c38b 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,6 +17,7 @@ bazel_dep(name = "zstd-jni", version = "1.5.2-3") bazel_dep(name = "blake3", version = "1.3.3") bazel_dep(name = "zlib", version = "1.2.13") bazel_dep(name = "rules_cc", version = "0.0.6") +bazel_dep(name = "rules_go", version = "0.39.1") bazel_dep(name = "rules_java", version = "6.1.1") bazel_dep(name = "rules_proto", version = "5.3.0-21.7") bazel_dep(name = "rules_jvm_external", version = "5.2") diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java index b5e08f3f45b779..062c22dc443361 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java @@ -401,6 +401,7 @@ protected Class findClass(String name) throws ClassNotFoundException { || name.startsWith("com.google.common.collect.") || name.startsWith("com.google.common.base.") || name.startsWith("com.google.common.graph.") + || name.startsWith("com.google.common.regex.") || name.startsWith("org.checkerframework.shaded.dataflow.") || name.startsWith("org.checkerframework.errorprone.dataflow.") || name.startsWith("com.sun.source.") diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionLookupKeyOrProxy.java b/src/main/java/com/google/devtools/build/lib/actions/ActionLookupKeyOrProxy.java index 92b189cf5e8c3b..48f76839214673 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/ActionLookupKeyOrProxy.java +++ b/src/main/java/com/google/devtools/build/lib/actions/ActionLookupKeyOrProxy.java @@ -29,6 +29,7 @@ * are subclasses of {@link ActionLookupKeyOrProxy}. This allows callers to easily find the value * key, while remaining agnostic to what action lookup values actually exist. */ +// TODO(b/261521010): this layer of indirection is no longer needed and may be cleaned up. public interface ActionLookupKeyOrProxy extends ArtifactOwner { /** * Returns the {@link BuildConfigurationKey} for the configuration associated with this key, or diff --git a/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java b/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java index 0f7392cfe23cd3..3109e08e42025d 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java +++ b/src/main/java/com/google/devtools/build/lib/actions/SpawnMetrics.java @@ -15,6 +15,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.util.ArrayList; import java.util.HashMap; @@ -69,8 +70,9 @@ public static SpawnMetrics forLocalExecution(int wallTimeInMs) { private final int executionWallTimeInMs; private final int processOutputsTimeInMs; private final int networkTimeInMs; + // error code to duration in ms - private final Map retryTimeInMs; + private final ImmutableMap retryTimeInMs; private final long inputBytes; private final long inputFiles; private final long memoryEstimateBytes; @@ -91,7 +93,7 @@ private SpawnMetrics(Builder builder) { this.setupTimeInMs = builder.setupTimeInMs; this.uploadTimeInMs = builder.uploadTimeInMs; this.executionWallTimeInMs = builder.executionWallTimeInMs; - this.retryTimeInMs = builder.retryTimeInMs; + this.retryTimeInMs = ImmutableMap.copyOf(builder.retryTimeInMs); this.processOutputsTimeInMs = builder.processOutputsTimeInMs; this.inputBytes = builder.inputBytes; this.inputFiles = builder.inputFiles; @@ -436,8 +438,8 @@ public Builder addRetryTimeInMs(int errorCode, int retryTimeInMs) { } @CanIgnoreReturnValue - public Builder setRetryTimeInMs(Map retryTimeInMs) { - this.retryTimeInMs = new HashMap<>(retryTimeInMs); + public Builder setRetryTimeInMs(ImmutableMap retryTimeInMs) { + this.retryTimeInMs = retryTimeInMs; return this; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisOptions.java index 7cd66de8b88283..5ccce705a0a798 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisOptions.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisOptions.java @@ -93,15 +93,6 @@ public class AnalysisOptions extends OptionsBase { ) public long versionWindowForDirtyNodeGc; - @Option( - name = "experimental_skyframe_prepare_analysis", - deprecationWarning = "This flag is a no-op and will be deleted in a future release.", - defaultValue = "false", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = {OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION}, - help = "Deprecated. No-op.") - public boolean skyframePrepareAnalysis; - @Option( name = "experimental_skyframe_cpu_heavy_skykeys_thread_pool_size", defaultValue = "HOST_CPUS", diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java index ff77cf43df8f07..9166a049afae67 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java @@ -11,36 +11,20 @@ // 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.analysis; -import static com.google.common.collect.ImmutableSet.toImmutableSet; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; -import com.google.devtools.build.lib.analysis.config.ConfigurationResolver; -import com.google.devtools.build.lib.analysis.config.ConfigurationResolver.TopLevelTargetsAndConfigsResult; -import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; -import com.google.devtools.build.lib.analysis.config.TransitionResolver; -import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; -import com.google.devtools.build.lib.analysis.config.transitions.NoTransition; import com.google.devtools.build.lib.cmdline.Label; -import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.BuildType; import com.google.devtools.build.lib.packages.BuiltinProvider; import com.google.devtools.build.lib.packages.Info; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.StarlarkProviderWrapper; -import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.packages.TriState; import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.Collection; import java.util.List; /** @@ -190,58 +174,4 @@ public static void checkProvider(Class cla clazz + " is generated by @AutoValue; use " + clazz.getSuperclass() + " instead"); } } - - /** - * Given a set of *top-level* targets and a configuration collection, evaluate top level - * transitions, resolve configurations and return the appropriate pair for - * each target. - * - *

Preserves the original input ordering. - */ - public static TopLevelTargetsAndConfigsResult getTargetsWithConfigs( - BuildConfigurationValue targetConfiguration, - Collection targets, - ExtendedEventHandler eventHandler, - ConfiguredRuleClassProvider ruleClassProvider, - ConfigurationsCollector configurationsCollector) - throws InvalidConfigurationException, InterruptedException { - // We use a set here to remove duplicate nodes; this can happen for input files and package - // groups. - ImmutableSet nodes = - targets.stream() - .map(target -> new TargetAndConfiguration(target, targetConfiguration)) - .collect(toImmutableSet()); - - // We'll get the configs from ConfigurationsCollector#getConfigurations, which gets - // configurations for deps including transitions. - Multimap asDeps = - targetsToDeps(nodes, ruleClassProvider); - - return ConfigurationResolver.getConfigurationsFromExecutor( - nodes, asDeps, eventHandler, configurationsCollector); - } - - @VisibleForTesting - public static Multimap targetsToDeps( - Collection nodes, ConfiguredRuleClassProvider ruleClassProvider) { - Multimap asDeps = ArrayListMultimap.create(); - for (TargetAndConfiguration targetAndConfig : nodes) { - ConfigurationTransition transition = - TransitionResolver.evaluateTransition( - targetAndConfig.getConfiguration(), - NoTransition.INSTANCE, - targetAndConfig.getTarget(), - ruleClassProvider.getTrimmingTransitionFactory()); - if (targetAndConfig.getConfiguration() != null) { - // TODO(bazel-team): support top-level aspects - asDeps.put( - targetAndConfig.getConfiguration(), - DependencyKey.builder() - .setLabel(targetAndConfig.getLabel()) - .setTransition(transition) - .build()); - } - } - return asDeps; - } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD index a7ff85cb5efa80..e52884dbc244a5 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD +++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD @@ -82,7 +82,6 @@ java_library( ":config/transitions/patch_transition", ":config/transitions/split_transition", ":config/transitions/transition_factory", - ":configurations_collector", ":configured_object_value", ":configured_target", ":constraints/constraint_constants", @@ -290,6 +289,7 @@ java_library( ":config/build_options", ":config/config_conditions", ":config/config_matching_provider", + ":config/configuration_transition_event", ":config/core_options", ":config/execution_transition_factory", ":config/feature_set", @@ -314,7 +314,6 @@ java_library( ":config/transitions/starlark_exposed_rule_transition_factory", ":config/transitions/transition_collector", ":config/transitions/transition_factory", - ":configurations_collector", ":configured_target", ":constraints/constraint_constants", ":constraints/constraint_semantics", @@ -625,7 +624,6 @@ java_library( ":constraints/top_level_constraint_semantics", ":extra_action_artifacts_provider", ":make_environment_event", - ":target_and_configuration", ":test/coverage_report_action_factory", ":test/instrumented_files_info", ":top_level_artifact_context", @@ -673,22 +671,6 @@ java_library( ], ) -java_library( - name = "configurations_collector", - srcs = [ - "ConfigurationsCollector.java", - "ConfigurationsResult.java", - ], - deps = [ - ":config/build_configuration", - ":config/build_options", - ":config/invalid_configuration_exception", - ":dependency_key", - "//src/main/java/com/google/devtools/build/lib/events", - "//third_party:guava", - ], -) - java_library( name = "configured_object_value", srcs = ["ConfiguredObjectValue.java"], @@ -1817,6 +1799,25 @@ java_library( ], ) +java_library( + name = "config/configuration_transition_event", + srcs = ["config/ConfigurationTransitionEvent.java"], + deps = [ + "//src/main/java/com/google/devtools/build/lib/events", + "//third_party:auto_value", + ], +) + +java_library( + name = "config/configuration_value_event", + srcs = ["config/ConfigurationValueEvent.java"], + deps = [ + ":config/build_configuration", + "//src/main/java/com/google/devtools/build/lib/events", + "//third_party:auto_value", + ], +) + java_library( name = "config/core_option_converters", srcs = ["config/CoreOptionConverters.java"], diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java index 4407995f704bce..7407c3a31a240d 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java @@ -11,7 +11,6 @@ // 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.analysis; import static com.google.common.collect.ImmutableList.toImmutableList; @@ -39,7 +38,6 @@ import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.ConfigRequestedEvent; -import com.google.devtools.build.lib.analysis.config.ConfigurationResolver.TopLevelTargetsAndConfigsResult; import com.google.devtools.build.lib.analysis.config.CoreOptions; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.constraints.PlatformRestrictionsResult; @@ -72,7 +70,6 @@ import com.google.devtools.build.lib.pkgcache.PackageManager.PackageManagerStatistics; import com.google.devtools.build.lib.profiler.Profiler; import com.google.devtools.build.lib.profiler.SilentCloseable; -import com.google.devtools.build.lib.server.FailureDetails; import com.google.devtools.build.lib.server.FailureDetails.Analysis; import com.google.devtools.build.lib.server.FailureDetails.FailureDetail; import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns; @@ -246,7 +243,6 @@ public AnalysisResult update( // Prepare the analysis phase BuildConfigurationValue topLevelConfig; - TopLevelTargetsAndConfigsResult topLevelTargetsWithConfigsResult; // Configuration creation. // TODO(gregce): Consider dropping this phase and passing on-the-fly target / exec configs as // needed. This requires cleaning up the invalidation in SkyframeBuildView.setConfigurations. @@ -257,15 +253,6 @@ public AnalysisResult update( if (buildConfigurationsCreatedCallback != null) { buildConfigurationsCreatedCallback.run(topLevelConfig); } - try (SilentCloseable c = Profiler.instance().profile("AnalysisUtils.getTargetsWithConfigs")) { - topLevelTargetsWithConfigsResult = - AnalysisUtils.getTargetsWithConfigs( - topLevelConfig, - labelToTargetMap.values(), - eventHandler, - ruleClassProvider, - skyframeExecutor); - } skyframeBuildView.setConfiguration( eventHandler, topLevelConfig, viewOptions.maxConfigChangesToShow); @@ -273,24 +260,20 @@ public AnalysisResult update( eventBus.post(new MakeEnvironmentEvent(topLevelConfig.getMakeEnvironment())); eventBus.post(topLevelConfig.toBuildEvent()); - Collection topLevelTargetsWithConfigs = - topLevelTargetsWithConfigsResult.getTargetsAndConfigs(); - - for (TargetAndConfiguration pair : topLevelTargetsWithConfigs) { - if (pair.getConfiguration() != null && !pair.getConfiguration().equals(topLevelConfig)) { - // Log top-level rule transitioned configurations. - eventBus.post(new ConfigRequestedEvent(pair.getConfiguration(), topLevelConfig.checksum())); - } - } - + var configurationKey = topLevelConfig.getKey(); ImmutableList topLevelCtKeys = - topLevelTargetsWithConfigs.stream() - .map(BuildView::getConfiguredTargetKey) + labelToTargetMap.keySet().stream() + .map( + label -> + ConfiguredTargetKey.builder() + .setLabel(label) + .setConfigurationKey(configurationKey) + .build()) .collect(toImmutableList()); - ImmutableList aspectsKeys = + ImmutableList aspectKeys = createTopLevelAspectKeys( - aspects, aspectsParameters, topLevelTargetsWithConfigs, eventHandler); + aspects, aspectsParameters, labelToTargetMap.keySet(), topLevelConfig, eventHandler); getArtifactFactory().noteAnalysisStarting(); SkyframeAnalysisResult skyframeAnalysisResult; @@ -306,7 +289,7 @@ public AnalysisResult update( skyframeBuildView.analyzeAndExecuteTargets( eventHandler, topLevelCtKeys, - aspectsKeys, + aspectKeys, loadingResult.getTestsToRunLabels(), labelToTargetMap, topLevelOptions, @@ -334,7 +317,7 @@ public AnalysisResult update( eventHandler, labelToTargetMap, topLevelCtKeys, - aspectsKeys, + aspectKeys, topLevelOptions, eventBus, bugReporter, @@ -372,8 +355,7 @@ public AnalysisResult update( viewOptions, skyframeAnalysisResult, /* targetsToSkip= */ ImmutableSet.of(), - /* labelToTargetMap= */ labelToTargetMap, - topLevelTargetsWithConfigsResult.hasError(), + labelToTargetMap, /* includeExecutionPhase= */ true); } else { ImmutableSet targetsToSkip = ImmutableSet.of(); @@ -419,25 +401,17 @@ public AnalysisResult update( skyframeAnalysisResult, targetsToSkip, labelToTargetMap, - topLevelTargetsWithConfigsResult.hasError(), /* includeExecutionPhase= */ false); } logger.atInfo().log("Finished analysis"); return result; } - private static ConfiguredTargetKey getConfiguredTargetKey( - TargetAndConfiguration targetAndConfiguration) { - return ConfiguredTargetKey.builder() - .setLabel(targetAndConfiguration.getLabel()) - .setConfiguration(targetAndConfiguration.getConfiguration()) - .build(); - } - private ImmutableList createTopLevelAspectKeys( List aspects, ImmutableMap aspectsParameters, - Collection topLevelTargetsWithConfigs, + ImmutableSet

Skips targets with loading phase errors. - */ - ConfigurationsResult getConfigurations( - ExtendedEventHandler eventHandler, - BuildOptions fromOptions, - Iterable keys) - throws InvalidConfigurationException, InterruptedException; -} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationsResult.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationsResult.java deleted file mode 100644 index a50d2f74387a54..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/analysis/ConfigurationsResult.java +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2020 The Bazel Authors. 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.analysis; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; -import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; -import com.google.devtools.build.lib.analysis.config.BuildOptions; -import com.google.devtools.build.lib.events.ExtendedEventHandler; - -/** - * The result of {@link #getConfigurations(ExtendedEventHandler, BuildOptions, Iterable)} which also - * registers if an error was recorded. - */ -public class ConfigurationsResult { - private final ListMultimap configurations; - private final boolean hasError; - - private ConfigurationsResult( - ListMultimap configurations, - boolean hasError) { - this.configurations = configurations; - this.hasError = hasError; - } - - public boolean hasError() { - return hasError; - } - - public ListMultimap getConfigurationMap() { - return configurations; - } - - public static Builder newBuilder() { - return new Builder(); - } - - /** Builder for {@link ConfigurationsResult} */ - public static class Builder { - private final ListMultimap - configurations = ArrayListMultimap.create(); - private boolean hasError = false; - - public void put(BaseDependencySpecification key, BuildConfigurationValue value) { - configurations.put(key, value); - } - - public void setHasError() { - this.hasError = true; - } - - public ConfigurationsResult build() { - return new ConfigurationsResult(configurations, hasError); - } - } -} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TransitiveDependencyState.java b/src/main/java/com/google/devtools/build/lib/analysis/TransitiveDependencyState.java index ac9c872ea089cf..111b352f5ab504 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/TransitiveDependencyState.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/TransitiveDependencyState.java @@ -62,7 +62,7 @@ public final class TransitiveDependencyState { * *

More ideally, those properties would be conveyed via providers of those dependencies, but * doing so would adversely affect resting heap usage whereas {@link ConfiguredTargetAndData} is - * ephemeral. Distributed implementations will include these properties in an extra providers. It + * ephemeral. Distributed implementations will include these properties in an extra provider. It * won't affect memory because the underlying package won't exist on the node loading it remotely. * *

It's valid to obtain {@link Package}s of dependencies from this map instead of creating an diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java index 06501a54b32978..151956146f01e4 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java @@ -11,7 +11,6 @@ // 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.analysis.config; import com.google.common.annotations.VisibleForTesting; @@ -19,10 +18,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; -import com.google.devtools.build.lib.analysis.BaseDependencySpecification; -import com.google.devtools.build.lib.analysis.ConfigurationsCollector; -import com.google.devtools.build.lib.analysis.ConfigurationsResult; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.DependencyKey; import com.google.devtools.build.lib.analysis.DependencyKind; @@ -41,7 +36,6 @@ import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.AttributeTransitionData; import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper; -import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.skyframe.BuildConfigurationKey; import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException; import com.google.devtools.build.lib.skyframe.PlatformMappingValue; @@ -51,11 +45,8 @@ import com.google.devtools.build.skyframe.SkyframeLookupResult; import com.google.devtools.common.options.OptionsParsingException; import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import javax.annotation.Nullable; @@ -194,8 +185,9 @@ public ImmutableList resolveConfiguration( .forEach( d -> eventHandler.post( - new ConfigRequestedEvent( - d.getConfiguration(), ctgValue.getConfiguration().checksum()))); + ConfigurationTransitionEvent.create( + ctgValue.getConfiguration().checksum(), + d.getConfiguration().checksum()))); } return ans; } @@ -339,38 +331,6 @@ private ImmutableList collectTransitionKeys( /** * Applies a configuration transition over a set of build options. * - *

This is only for callers that can't use {@link #applyTransitionWithSkyframe}. The difference - * is {@link #applyTransitionWithSkyframe} internally computes {@code details} with Skyframe, - * while this version requires it as a precomputed input. - * - *

prework - load all default values for reading build settings in Starlark transitions (by - * design, {@link BuildOptions} never holds default values of build settings) - * - *

postwork - replay events/throw errors from transition implementation function and validate - * the outputs of the transition. This only applies to Starlark transitions. - * - * @return the build options for the transitioned configuration. - */ - public static Map applyTransitionWithoutSkyframe( - BuildOptions fromOptions, - ConfigurationTransition transition, - StarlarkBuildSettingsDetailsValue details, - ExtendedEventHandler eventHandler, - StarlarkTransitionCache starlarkTransitionCache) - throws TransitionException, InterruptedException { - if (StarlarkTransition.doesStarlarkTransition(transition)) { - return starlarkTransitionCache.computeIfAbsent( - fromOptions, transition, details, eventHandler); - } - return transition.apply(TransitionUtil.restrict(transition, fromOptions), eventHandler); - } - - /** - * Applies a configuration transition over a set of build options. - * - *

Callers should use this over {@link #applyTransitionWithoutSkyframe}. Unlike that variation, - * this would may return null if it needs more Skyframe deps. - * *

postwork - replay events/throw errors from transition implementation function and validate * the outputs of the transition. This only applies to Starlark transitions. * @@ -415,102 +375,4 @@ private static StarlarkBuildSettingsDetailsValue getStarlarkBuildSettingsDetails StarlarkBuildSettingsDetailsValue.key(starlarkBuildSettings), TransitionException.class); } - - /** - * This method allows resolution of configurations outside of a skyfunction call. - * - *

Unlike {@link #resolveConfigurations}, this doesn't expect the current context to be - * evaluating dependencies of a parent target. So this method is also suitable for top-level - * targets. - * - *

Resolution consists of applying the per-target transitions specified in {@code - * targetsToEvaluate}. This can be used, e.g., to apply {@link - * com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory}s over global - * top-level configurations. - * - *

Preserves the original input order (but merges duplicate nodes that might occur due to - * top-level configuration transitions) . Uses original (untrimmed, pre-transition) configurations - * for targets that can't be evaluated (e.g. due to loading phase errors). - * - *

This is suitable for feeding {@link - * com.google.devtools.build.lib.analysis.ConfiguredTargetValue} keys: as general principle {@link - * com.google.devtools.build.lib.analysis.ConfiguredTarget}s should have exactly as much - * information in their configurations as they need to evaluate and no more (e.g. there's no need - * for Android settings in a C++ configured target). - * - * @param defaultContext the original targets and starting configurations before applying rule - * transitions and trimming. When actual configurations can't be evaluated, these values are - * returned as defaults. See TODO below. - * @param targetsToEvaluate the inputs repackaged as dependencies, including rule-specific - * transitions - * @param eventHandler the error event handler - * @param configurationsCollector the collector which finds configurations for dependencies - */ - // TODO(bazel-team): error out early for targets that fail - failed configuration evaluations - // should never make it through analysis (and especially not seed ConfiguredTargetValues) - // TODO(gregce): merge this more with resolveConfigurations? One crucial difference is - // resolveConfigurations can null-return on missing deps since it executes inside Skyfunctions. - public static TopLevelTargetsAndConfigsResult getConfigurationsFromExecutor( - Iterable defaultContext, - Multimap targetsToEvaluate, - ExtendedEventHandler eventHandler, - ConfigurationsCollector configurationsCollector) - throws InvalidConfigurationException, InterruptedException { - - Map labelsToTargets = new HashMap<>(); - for (TargetAndConfiguration targetAndConfig : defaultContext) { - labelsToTargets.put(targetAndConfig.getLabel(), targetAndConfig.getTarget()); - } - - // Maps pairs to pairs for targets that - // could be successfully Skyframe-evaluated. - Map successfullyEvaluatedTargets = - new LinkedHashMap<>(); - boolean hasError = false; - if (!targetsToEvaluate.isEmpty()) { - for (BuildConfigurationValue fromConfig : targetsToEvaluate.keySet()) { - ConfigurationsResult configurationsResult = - configurationsCollector.getConfigurations( - eventHandler, fromConfig.getOptions(), targetsToEvaluate.get(fromConfig)); - hasError |= configurationsResult.hasError(); - for (Map.Entry evaluatedTarget : - configurationsResult.getConfigurationMap().entries()) { - Target target = labelsToTargets.get(evaluatedTarget.getKey().getLabel()); - successfullyEvaluatedTargets.put( - new TargetAndConfiguration(target, fromConfig), - new TargetAndConfiguration(target, evaluatedTarget.getValue())); - } - } - } - - LinkedHashSet result = new LinkedHashSet<>(); - for (TargetAndConfiguration originalInput : defaultContext) { - // If the configuration couldn't be determined (e.g. loading phase error), use the original. - result.add(successfullyEvaluatedTargets.getOrDefault(originalInput, originalInput)); - } - return new TopLevelTargetsAndConfigsResult(result, hasError); - } - - /** - * The result of {@link #getConfigurationsFromExecutor} which also registers if an error was - * recorded. - */ - public static class TopLevelTargetsAndConfigsResult { - private final Collection configurations; - private final boolean hasError; - - public TopLevelTargetsAndConfigsResult( - Collection configurations, boolean hasError) { - this.configurations = configurations; - this.hasError = hasError; - } - - public boolean hasError() { - return hasError; - } - - public Collection getTargetsAndConfigs() { - return configurations; - } - } } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationTransitionEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationTransitionEvent.java new file mode 100644 index 00000000000000..78ef62c82d2f44 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationTransitionEvent.java @@ -0,0 +1,39 @@ +// Copyright 2023 The Bazel Authors. 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.analysis.config; + +import com.google.auto.value.AutoValue; +import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable; + +/** Posted when there is a configuration transition. */ +@AutoValue +public abstract class ConfigurationTransitionEvent + implements Comparable, Postable { + public static ConfigurationTransitionEvent create(String parentChecksum, String childChecksum) { + return new AutoValue_ConfigurationTransitionEvent(parentChecksum, childChecksum); + } + + public abstract String parentChecksum(); + + public abstract String childChecksum(); + + @Override + public final int compareTo(ConfigurationTransitionEvent that) { + int result = parentChecksum().compareTo(that.parentChecksum()); + if (result != 0) { + return result; + } + return childChecksum().compareTo(that.childChecksum()); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationValueEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationValueEvent.java new file mode 100644 index 00000000000000..84f6c96434f6dc --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationValueEvent.java @@ -0,0 +1,27 @@ +// Copyright 2023 The Bazel Authors. 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.analysis.config; + +import com.google.auto.value.AutoValue; +import com.google.devtools.build.lib.events.ExtendedEventHandler.Postable; + +/** Posted when a {@link BuildConfigurationValue} is created. */ +@AutoValue +public abstract class ConfigurationValueEvent implements Postable { + public static ConfigurationValueEvent create(BuildConfigurationValue configuration) { + return new AutoValue_ConfigurationValueEvent(configuration); + } + + public abstract BuildConfigurationValue configuration(); +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java index 0c996c3ee2554f..c5317f2a3199c4 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/CoreOptions.java @@ -155,18 +155,6 @@ public class CoreOptions extends FragmentOptions implements Cloneable { help = "Minimum command line length before creating a parameter file.") public int minParamFileSize; - @Option( - name = "defer_param_files", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = { - OptionEffectTag.LOADING_AND_ANALYSIS, - OptionEffectTag.EXECUTION, - OptionEffectTag.ACTION_COMMAND_LINES - }, - help = "This option is deprecated and has no effect and will be removed in the future.") - public boolean deferParamFiles; - @Option( name = "experimental_extended_sanity_checks", defaultValue = "false", @@ -185,8 +173,7 @@ public class CoreOptions extends FragmentOptions implements Cloneable { effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS, OptionEffectTag.EAGERNESS_TO_EXIT}, help = "If this option is enabled, filesets crossing package boundaries are reported " - + "as errors. It does not work when check_fileset_dependencies_recursively is " - + "disabled.") + + "as errors.") public boolean strictFilesets; @Option( @@ -511,24 +498,6 @@ public ExecConfigurationDistinguisherSchemeConverter() { + "https://bazel.build/extending/rules#runfiles_features_to_avoid).") public boolean alwaysIncludeFilesToBuildInData; - @Option( - name = "check_fileset_dependencies_recursively", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - deprecationWarning = - "This flag is a no-op and fileset dependencies are always checked " - + "to ensure correctness of builds.", - effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}) - public boolean checkFilesetDependenciesRecursively; - - @Option( - name = "experimental_skyframe_native_filesets", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = {OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION}, - deprecationWarning = "This flag is a no-op and skyframe-native-filesets is always true.") - public boolean skyframeNativeFileset; - @Option( name = "run_under", defaultValue = "null", @@ -989,16 +958,6 @@ public OutputPathsConverter() { + " of failing. This is to help use cquery diagnose failures in select.") public boolean debugSelectsAlwaysSucceed; - @Option( - name = "experimental_throttle_action_cache_check", - defaultValue = "true", - converter = BooleanConverter.class, - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - metadataTags = OptionMetadataTag.EXPERIMENTAL, - effectTags = {OptionEffectTag.EXECUTION}, - help = "Whether to throttle the check whether an action is cached.") - public boolean throttleActionCacheCheck; - /** Ways configured targets may provide the {@link Fragment}s they require. */ public enum IncludeConfigFragmentsEnum { /** diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/AttributeConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/AttributeConfiguration.java index c927e3c38467a0..88d68224308699 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/AttributeConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/AttributeConfiguration.java @@ -14,6 +14,7 @@ package com.google.devtools.build.lib.analysis.producers; import com.google.auto.value.AutoOneOf; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.packages.PackageGroup; import com.google.devtools.build.lib.skyframe.BuildConfigurationKey; @@ -28,6 +29,13 @@ enum Kind { * target is known, it should be verified to be a {@link PackageGroup}. */ VISIBILITY, + /** + * The configuration is null. + * + *

This is only applied when the dependency is in the same package as the parent and it is + * not configurable. The value in this case stores any transition keys. + */ + NULL_TRANSITION_KEYS, /** * There is a single configuration. * @@ -46,6 +54,8 @@ enum Kind { abstract void visibility(); + abstract ImmutableList nullTransitionKeys(); + abstract BuildConfigurationKey unary(); abstract ImmutableMap split(); @@ -53,6 +63,7 @@ enum Kind { public int count() { switch (kind()) { case VISIBILITY: + case NULL_TRANSITION_KEYS: case UNARY: return 1; case SPLIT: @@ -65,6 +76,10 @@ static AttributeConfiguration ofVisibility() { return AutoOneOf_AttributeConfiguration.visibility(); } + static AttributeConfiguration ofNullTransitionKeys(ImmutableList transitionKeys) { + return AutoOneOf_AttributeConfiguration.nullTransitionKeys(transitionKeys); + } + static AttributeConfiguration ofUnary(BuildConfigurationKey key) { return AutoOneOf_AttributeConfiguration.unary(key); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD index 95ed8f1824bb75..a32c92ed850464 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD @@ -22,6 +22,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:config/build_options", "//src/main/java/com/google/devtools/build/lib/analysis:config/config_conditions", "//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider", + "//src/main/java/com/google/devtools/build/lib/analysis:config/configuration_transition_event", "//src/main/java/com/google/devtools/build/lib/analysis:config/invalid_configuration_exception", "//src/main/java/com/google/devtools/build/lib/analysis:config/starlark_transition_cache", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/composing_transition", diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java index c9d91a559ce06a..b303b9673623fe 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java @@ -13,8 +13,9 @@ // limitations under the License. package com.google.devtools.build.lib.analysis.producers; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; +import com.google.devtools.build.lib.analysis.InconsistentNullConfigException; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; import com.google.devtools.build.lib.analysis.TransitiveDependencyState; import com.google.devtools.build.lib.analysis.config.ConfigConditions; @@ -99,7 +100,7 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { .setLabel(configLabels.get(i)) .setConfiguration(targetAndConfiguration.getConfiguration()) .build(), - /* transitionKey= */ null, + /* transitionKeys= */ ImmutableList.of(), transitiveState, (ConfiguredTargetAndDataProducer.ResultSink) this, i)); @@ -130,17 +131,12 @@ public void acceptConfiguredTargetAndDataError(ConfiguredValueCreationException } @Override - public void acceptConfiguredTargetAndDataError(InvalidVisibilityDependencyException error) { - // After removing the rule transition from dependency resolution, a ConfiguredTargetKey in - // Skyframe with a null BuildConfigurationKey will only be used to request visibility - // dependencies. This will never be the case for ConfigConditions, which are always requested - // with the parent configuration. At the moment, nothing throws - // InvalidVisibilityDependencyException. - // - // TODO(b/261521010): update this comment once rule transitions are removed from dependency - // resolution. + public void acceptConfiguredTargetAndDataError(InconsistentNullConfigException error) { + // A config label was evaluated with a null configuration. This should never happen as + // ConfigConditions are only present if the parent is a Rule, then always evaluated with the + // parent configuration. throw new IllegalArgumentException( - "ConfigCondition dependency should never be marked visibility.", error); + "ConfigCondition dependency should never be evaluated with a null configuration.", error); } private StateMachine constructConfigConditions(Tasks tasks, ExtendedEventHandler listener) { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredTargetAndDataProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredTargetAndDataProducer.java index 2ca4a755ff50b2..89f1ed58defd0c 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredTargetAndDataProducer.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfiguredTargetAndDataProducer.java @@ -16,7 +16,7 @@ import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.ConfiguredTargetValue; -import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; +import com.google.devtools.build.lib.analysis.InconsistentNullConfigException; import com.google.devtools.build.lib.analysis.TransitiveDependencyState; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.events.ExtendedEventHandler; @@ -42,20 +42,19 @@ public final class ConfiguredTargetAndDataProducer implements StateMachine, Consumer, StateMachine.ValueOrException2Sink< - ConfiguredValueCreationException, InvalidVisibilityDependencyException> { + ConfiguredValueCreationException, InconsistentNullConfigException> { /** Interface for accepting values produced by this class. */ public interface ResultSink { void acceptConfiguredTargetAndData(ConfiguredTargetAndData value, int index); void acceptConfiguredTargetAndDataError(ConfiguredValueCreationException error); - void acceptConfiguredTargetAndDataError(InvalidVisibilityDependencyException error); + void acceptConfiguredTargetAndDataError(InconsistentNullConfigException error); } // -------------------- Input -------------------- private final ConfiguredTargetKey key; - @Nullable // Null if no transition key is needed (patch transition or no-op split transition). - private final String transitionKey; + private final ImmutableList transitionKeys; private final TransitiveDependencyState transitiveState; // -------------------- Output -------------------- @@ -70,12 +69,12 @@ public interface ResultSink { public ConfiguredTargetAndDataProducer( ConfiguredTargetKey key, - @Nullable String transitionKey, + ImmutableList transitionKeys, TransitiveDependencyState transitiveState, ResultSink sink, int outputIndex) { this.key = key; - this.transitionKey = transitionKey; + this.transitionKeys = transitionKeys; this.transitiveState = transitiveState; this.sink = sink; this.outputIndex = outputIndex; @@ -86,9 +85,8 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { tasks.lookUp( key.toKey(), ConfiguredValueCreationException.class, - InvalidVisibilityDependencyException.class, - (ValueOrException2Sink< - ConfiguredValueCreationException, InvalidVisibilityDependencyException>) + InconsistentNullConfigException.class, + (ValueOrException2Sink) this); return this::fetchConfigurationAndPackage; } @@ -97,7 +95,7 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { public void acceptValueOrException2( @Nullable SkyValue value, @Nullable ConfiguredValueCreationException error, - @Nullable InvalidVisibilityDependencyException visibilityError) { + @Nullable InconsistentNullConfigException visibilityError) { if (value != null) { var configuredTargetValue = (ConfiguredTargetValue) value; this.configuredTarget = configuredTargetValue.getConfiguredTarget(); @@ -171,11 +169,7 @@ private StateMachine constructResult(Tasks tasks, ExtendedEventHandler listener) throw new IllegalStateException("Target already verified for " + configuredTarget, e); } sink.acceptConfiguredTargetAndData( - new ConfiguredTargetAndData( - configuredTarget, - target, - configurationValue, - transitionKey == null ? ImmutableList.of() : ImmutableList.of(transitionKey)), + new ConfiguredTargetAndData(configuredTarget, target, configurationValue, transitionKeys), outputIndex); return DONE; } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java index 2940409889ba9d..e8610c8f2afabd 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java @@ -28,13 +28,19 @@ import com.google.devtools.build.lib.analysis.DependencyResolver.ExecutionPlatformResult; import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; +import com.google.devtools.build.lib.analysis.config.ConfigurationTransitionEvent; import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException; import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException; +import com.google.devtools.build.lib.causes.LoadingFailedCause; import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.Aspect; import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.AttributeTransitionData; +import com.google.devtools.build.lib.packages.NoSuchTargetException; +import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.skyframe.BuildConfigurationKey; import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException; @@ -183,16 +189,46 @@ private StateMachine processTransitionResult(Tasks tasks, ExtendedEventHandler l return DONE; // There was a previously reported error. } - AttributeConfiguration configuration; - if (transitionedConfigurations.size() == 1 - && transitionedConfigurations.keySet().iterator().next().equals(PATCH_TRANSITION_KEY)) { - // Drops the transition key if it was a patch transition. - configuration = - AttributeConfiguration.ofUnary(transitionedConfigurations.get(PATCH_TRANSITION_KEY)); - } else { - configuration = AttributeConfiguration.ofSplit(transitionedConfigurations); + if (isNonconfigurableTargetInSamePackage(listener)) { + // The target is in the same package as the parent and non-configurable. In the general case + // loading a child target would defeat Package-based sharding. However, when the target is in + // the same Package, that concern no longer applies. This optimization means that delegation, + // and the corresponding creation of additional Skyframe nodes, can be avoided in the very + // common case of source file dependencies in the same Package. + + // Discards transition keys for patch transitions but keeps them otherwise. + ImmutableList transitionKeys = + transitionedConfigurations.size() == 1 + && transitionedConfigurations.containsKey(PATCH_TRANSITION_KEY) + ? ImmutableList.of() + : transitionedConfigurations.keySet().asList(); + return computePrerequisites( + AttributeConfiguration.ofNullTransitionKeys(transitionKeys), + /* executionPlatformLabel= */ null); + } + + String parentChecksum = parameters.configurationKey().getOptionsChecksum(); + for (BuildConfigurationKey configuration : transitionedConfigurations.values()) { + String childChecksum = configuration.getOptionsChecksum(); + if (!parentChecksum.equals(childChecksum)) { + listener.post(ConfigurationTransitionEvent.create(parentChecksum, childChecksum)); + } + } + + if (transitionedConfigurations.size() == 1) { + BuildConfigurationKey patchedConfiguration = + transitionedConfigurations.get(PATCH_TRANSITION_KEY); + if (patchedConfiguration != null) { + // It was a patch transition. Drops the transition key. + return computePrerequisites( + AttributeConfiguration.ofUnary(patchedConfiguration), + /* executionPlatformLabel= */ null); + } } - return computePrerequisites(configuration, /* executionPlatformLabel= */ null); + + return computePrerequisites( + AttributeConfiguration.ofSplit(transitionedConfigurations), + /* executionPlatformLabel= */ null); } private StateMachine computePrerequisites( @@ -226,6 +262,27 @@ public void acceptPrerequisitesAspectError(DependencyEvaluationException error) sink.acceptDependencyError(DependencyError.of(error)); } + private boolean isNonconfigurableTargetInSamePackage(ExtendedEventHandler listener) { + Target parentTarget = parameters.target(); + if (parentTarget.getLabel().getPackageIdentifier().equals(toLabel.getPackageIdentifier())) { + try { + Target toTarget = parentTarget.getPackage().getTarget(toLabel.getName()); + if (!toTarget.isConfigurable()) { + return true; + } + } catch (NoSuchTargetException e) { + parameters + .transitiveState() + .addTransitiveCause(new LoadingFailedCause(toLabel, e.getDetailedExitCode())); + listener.handle( + Event.error( + TargetUtils.getLocationMaybe(parentTarget), + TargetUtils.formatMissingEdge(parentTarget, toLabel, e, kind.getAttribute()))); + } + } + return false; + } + /** * Emits errors from {@link ExecutionPlatformResult#error}. * diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisiteParameters.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisiteParameters.java index 4cdd28db3de305..7ab5fd1300888c 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisiteParameters.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisiteParameters.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.packages.Aspect; import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper; import com.google.devtools.build.lib.packages.Rule; +import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.skyframe.BuildConfigurationKey; import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; import javax.annotation.Nullable; @@ -33,7 +34,7 @@ /** Common parameters for computing prerequisites. */ public final class PrerequisiteParameters { private final ConfiguredTargetKey configuredTargetKey; - @Nullable private final Rule associatedRule; + private final Target target; private final ImmutableList aspects; private final StarlarkTransitionCache transitionCache; @@ -44,14 +45,14 @@ public final class PrerequisiteParameters { public PrerequisiteParameters( ConfiguredTargetKey configuredTargetKey, - @Nullable Rule associatedRule, + Target target, Iterable aspects, StarlarkTransitionCache transitionCache, @Nullable ToolchainCollection toolchainContexts, @Nullable ConfiguredAttributeMapper attributeMap, TransitiveDependencyState transitiveState) { this.configuredTargetKey = configuredTargetKey; - this.associatedRule = associatedRule; + this.target = target; this.aspects = ImmutableList.copyOf(aspects); this.transitionCache = transitionCache; this.toolchainContexts = toolchainContexts; @@ -63,9 +64,13 @@ public Label label() { return configuredTargetKey.getLabel(); } + public Target target() { + return target; + } + @Nullable public Rule associatedRule() { - return associatedRule; + return target.getAssociatedRule(); } @Nullable @@ -91,12 +96,8 @@ public ConfiguredAttributeMapper attributeMap() { return attributeMap; } - @Nullable public Location location() { - if (associatedRule == null) { - return null; - } - return associatedRule.getLocation(); + return target.getLocation(); } public BuildEventId eventId() { diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java index 295eedb29706f3..5f9fbe96689510 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java @@ -15,6 +15,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.devtools.build.lib.analysis.AspectResolutionHelpers.computeAspectCollection; +import static com.google.devtools.build.lib.analysis.producers.AttributeConfiguration.Kind.VISIBILITY; import static com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData.SPLIT_DEP_ORDERING; import static java.util.Arrays.sort; @@ -22,9 +23,11 @@ import com.google.devtools.build.lib.analysis.AspectCollection; import com.google.devtools.build.lib.analysis.DuplicateException; import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException; +import com.google.devtools.build.lib.analysis.InconsistentNullConfigException; import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException; +import com.google.devtools.build.lib.analysis.configuredtargets.PackageGroupConfiguredTarget; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.Aspect; @@ -104,7 +107,16 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { tasks.enqueue( new ConfiguredTargetAndDataProducer( getPrerequisiteKey(/* configurationKey= */ null), - /* transitionKey= */ null, + /* transitionKeys= */ ImmutableList.of(), + parameters.transitiveState(), + (ConfiguredTargetAndDataProducer.ResultSink) this, + /* outputIndex= */ 0)); + break; + case NULL_TRANSITION_KEYS: + tasks.enqueue( + new ConfiguredTargetAndDataProducer( + getPrerequisiteKey(/* configurationKey= */ null), + configuration.nullTransitionKeys(), parameters.transitiveState(), (ConfiguredTargetAndDataProducer.ResultSink) this, /* outputIndex= */ 0)); @@ -113,7 +125,7 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { tasks.enqueue( new ConfiguredTargetAndDataProducer( getPrerequisiteKey(configuration.unary()), - /* transitionKey= */ null, + /* transitionKeys= */ ImmutableList.of(), parameters.transitiveState(), (ConfiguredTargetAndDataProducer.ResultSink) this, /* outputIndex= */ 0)); @@ -124,7 +136,7 @@ public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { tasks.enqueue( new ConfiguredTargetAndDataProducer( getPrerequisiteKey(entry.getValue()), - /* transitionKey= */ entry.getKey(), + ImmutableList.of(entry.getKey()), parameters.transitiveState(), (ConfiguredTargetAndDataProducer.ResultSink) this, index)); @@ -141,9 +153,18 @@ public void acceptConfiguredTargetAndData(ConfiguredTargetAndData value, int ind } @Override - public void acceptConfiguredTargetAndDataError(InvalidVisibilityDependencyException error) { + public void acceptConfiguredTargetAndDataError(InconsistentNullConfigException error) { hasError = true; - sink.acceptPrerequisitesError(error); + if (configuration.kind() == VISIBILITY) { + // The target was configurable, but used as a visibility dependency. This is invalid because + // only `PackageGroup`s are accepted as visibility dependencies and those are not + // configurable. Propagates the exception with more precise information. + sink.acceptPrerequisitesError(new InvalidVisibilityDependencyException(label)); + return; + } + // `configuration.kind()` was `NULL_TRANSITION_KEYS`. This is only used when the target is in + // the same package as the parent and not configurable so this should never happen. + throw new IllegalStateException(error); } @Override @@ -157,6 +178,15 @@ private StateMachine computeConfiguredAspects(Tasks tasks, ExtendedEventHandler return DONE; } + if (configuration.kind() == VISIBILITY) { + // Verifies that the dependency is a `package_group`. The value is always at index 0 because + // the `VISIBILITY` configuration is always unary. + if (!(configuredTargets[0].getConfiguredTarget() instanceof PackageGroupConfiguredTarget)) { + sink.acceptPrerequisitesError(new InvalidVisibilityDependencyException(label)); + return DONE; + } + } + cleanupValues(); AspectCollection aspects; diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java index c8fdc99f0de7c1..474fa84bbf03d0 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java @@ -22,10 +22,10 @@ import com.google.devtools.build.lib.actions.ActionLookupKey; import com.google.devtools.build.lib.analysis.ConfiguredTargetValue; import com.google.devtools.build.lib.analysis.InconsistentNullConfigException; -import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; import com.google.devtools.build.lib.analysis.TransitiveDependencyState; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; +import com.google.devtools.build.lib.analysis.config.ConfigurationTransitionEvent; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.analysis.config.StarlarkTransitionCache; import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition; @@ -35,10 +35,10 @@ import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchTargetException; -import com.google.devtools.build.lib.packages.PackageGroup; import com.google.devtools.build.lib.packages.Rule; import com.google.devtools.build.lib.packages.RuleTransitionData; import com.google.devtools.build.lib.packages.Target; +import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.skyframe.BuildConfigurationKey; import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException; @@ -54,16 +54,14 @@ * Computes the target and configuration for a configured target key. * *

If the key has a configuration and the target is configurable, attempts to apply a rule side - * transition. If the target is not configurable, directly transitions to the null configuration. If - * the resulting configuration already has an owner, delegates to the owner instead of recomputing - * the configured target. - * - *

If the key does not have a configuration, it was requested as a visibility dependency. - * Verifies that the {@link Target} is a {@link PackageGroup}, throwing {@link - * InvalidVisibilityDependencyException} if that's not the case. + * transition. If the configuration changes, delegates to a target with the new configuration. If + * the target is not configurable, directly delegates to the null configuration. */ public final class TargetAndConfigurationProducer - implements StateMachine, Consumer, TargetProducer.ResultSink { + implements StateMachine, + StateMachine.ValueOrExceptionSink, + Consumer, + TargetProducer.ResultSink { /** Accepts results of this producer. */ public interface ResultSink { void acceptTargetAndConfiguration(TargetAndConfiguration value, ConfiguredTargetKey fullKey); @@ -79,7 +77,6 @@ public abstract static class TargetAndConfigurationError { /** Tags the error type. */ public enum Kind { CONFIGURED_VALUE_CREATION, - INVALID_VISIBILITY_DEPENDENCY, INCONSISTENT_NULL_CONFIG } @@ -87,8 +84,6 @@ public enum Kind { public abstract ConfiguredValueCreationException configuredValueCreation(); - public abstract InvalidVisibilityDependencyException invalidVisibilityDependency(); - public abstract InconsistentNullConfigException inconsistentNullConfig(); private static TargetAndConfigurationError of(ConfiguredValueCreationException e) { @@ -96,15 +91,6 @@ private static TargetAndConfigurationError of(ConfiguredValueCreationException e .configuredValueCreation(e); } - // TODO(b/261521010): enable this error once Rule transitions are removed from dependency - // resolution. - // private static TargetAndConfigurationError of(InvalidVisibilityDependencyException e) { - // return AutoOneOf_TargetAndConfigurationProducer_TargetAndConfigurationError - // .invalidVisibilityDependency(e); - // } - - // TODO(b/261521010): delete this error once Rule transitions are removed from dependency - // resolution. private static TargetAndConfigurationError of(InconsistentNullConfigException e) { return AutoOneOf_TargetAndConfigurationProducer_TargetAndConfigurationError .inconsistentNullConfig(e); @@ -173,65 +159,96 @@ private StateMachine determineConfiguration(Tasks tasks, ExtendedEventHandler li if (configurationKey == null) { if (target.isConfigurable()) { // We somehow ended up in a target that requires a non-null configuration but with a key - // that doesn't have a configuration. This is always an error, but we need to analyze the - // dependencies of the latter target to realize that. Short-circuit the evaluation to avoid - // doing useless work and running code with a null configuration that's not prepared for it. + // that doesn't have a configuration. This is always an error, but we need to bubble this + // up to the parent to provide more context. sink.acceptTargetAndConfigurationError( TargetAndConfigurationError.of(new InconsistentNullConfigException())); return DONE; } - // TODO(b/261521010): after removing the rule transition from dependency resolution, the logic - // here changes. - // - // A null configuration key will only be used for visibility dependencies so when that's - // true, a check that the target is a PackageGroup will be performed, throwing - // InvalidVisibilityDependencyException on failure. - // - // The ConfiguredTargetKey cannot fan-in in this case. sink.acceptTargetAndConfiguration( new TargetAndConfiguration(target, /* configuration= */ null), preRuleTransitionKey); return DONE; } - // This may happen for top-level ConfiguredTargets. - // - // TODO(b/261521010): this may also happen for targets that are not top-level after removing - // rule transitions from dependency resolution. Update this comment. if (!target.isConfigurable()) { - var nullConfiguredTargetKey = - ConfiguredTargetKey.builder().setDelegate(preRuleTransitionKey).build(); - ActionLookupKey delegate = nullConfiguredTargetKey.toKey(); - if (!delegate.equals(preRuleTransitionKey)) { - // Delegates to the key that already owns the null configuration. - delegateTo(tasks, delegate); - return DONE; - } - sink.acceptTargetAndConfiguration( - new TargetAndConfiguration(target, /* configuration= */ null), nullConfiguredTargetKey); + // If target is not configurable, but requested with a configuration. Delegates to a key with + // the null configuration. This is expected to be uncommon. The common case of a + // non-configurable target is an input file, but those are usually package local and requested + // correctly with the null configuration. + delegateTo( + tasks, + ConfiguredTargetKey.builder() + .setLabel(preRuleTransitionKey.getLabel()) + .setExecutionPlatformLabel(preRuleTransitionKey.getExecutionPlatformLabel()) + .build() + .toKey()); + return DONE; + } + + if (!preRuleTransitionKey.shouldApplyRuleTransition()) { + lookUpConfigurationValue(tasks); + return DONE; + } + + ConfigurationTransition transition = + computeTransition(target.getAssociatedRule(), trimmingTransitionFactory); + if (transition == null) { + lookUpConfigurationValue(tasks); return DONE; } - return new RuleTransitionApplier(); + return new RuleTransitionApplier(transition); + } + + private void delegateTo(Tasks tasks, ActionLookupKey delegate) { + tasks.lookUp(delegate, (Consumer) this); } - /** Applies any requested rule transition before producing the final configuration. */ - private class RuleTransitionApplier - implements StateMachine, - TransitionApplier.ResultSink, - ValueOrExceptionSink { + @Override + public void accept(SkyValue value) { + sink.acceptTargetAndConfigurationDelegatedValue((ConfiguredTargetValue) value); + } + + private void lookUpConfigurationValue(Tasks tasks) { + tasks.lookUp( + preRuleTransitionKey.getConfigurationKey(), + InvalidConfigurationException.class, + (ValueOrExceptionSink) this); + } + + @Override + public void acceptValueOrException( + @Nullable SkyValue value, @Nullable InvalidConfigurationException error) { + if (value != null) { + sink.acceptTargetAndConfiguration( + new TargetAndConfiguration(target, (BuildConfigurationValue) value), + preRuleTransitionKey); + return; + } + emitError( + error.getMessage(), TargetUtils.getLocationMaybe(target), error.getDetailedExitCode()); + } + + /** + * Applies the requested rule transition. + * + *

When the rule transition results in a new configuration, performs an idempotency check and + * constructs a delegate {@link ConfiguredTargetKey} with the appropriate {@link + * ConfiguredTargetKey#shouldApplyRuleTransition} value. Otherwise, just looks up the + * configuration. + */ + private class RuleTransitionApplier implements StateMachine, TransitionApplier.ResultSink { + // -------------------- Input -------------------- + private final ConfigurationTransition transition; // -------------------- Internal State -------------------- private BuildConfigurationKey configurationKey; - private ConfiguredTargetKey fullKey; + + private RuleTransitionApplier(ConfigurationTransition transition) { + this.transition = transition; + } @Override public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { - ConfigurationTransition transition = - computeTransition(target.getAssociatedRule(), trimmingTransitionFactory); - if (transition == null) { - this.configurationKey = preRuleTransitionKey.getConfigurationKey(); - return processTransitionedKey(tasks, listener); - } - return new TransitionApplier( preRuleTransitionKey.getConfigurationKey(), transition, @@ -266,57 +283,109 @@ private StateMachine processTransitionedKey(Tasks tasks, ExtendedEventHandler li return DONE; // There was an error. } - if (!configurationKey.equals(preRuleTransitionKey.getConfigurationKey())) { - fullKey = - ConfiguredTargetKey.builder() - .setDelegate(preRuleTransitionKey) - .setConfigurationKey(configurationKey) - .build(); - ActionLookupKey delegate = fullKey.toKey(); - if (!delegate.equals(preRuleTransitionKey)) { - // Delegates to the key that already owns this configuration. - delegateTo(tasks, delegate); - return DONE; - } - } else { - fullKey = preRuleTransitionKey; + BuildConfigurationKey parentConfiguration = preRuleTransitionKey.getConfigurationKey(); + if (configurationKey.equals(parentConfiguration)) { + // This key owns the configuration and the computation completes normally. + lookUpConfigurationValue(tasks); + return DONE; } - // This key owns the configuration and the computation completes normally. - tasks.lookUp( - configurationKey, - InvalidConfigurationException.class, - (ValueOrExceptionSink) this); - return DONE; + listener.post( + ConfigurationTransitionEvent.create( + parentConfiguration.getOptionsChecksum(), configurationKey.getOptionsChecksum())); + + return new IdempotencyChecker(); } - @Override - public void acceptValueOrException( - @Nullable SkyValue value, @Nullable InvalidConfigurationException error) { - if (value != null) { - sink.acceptTargetAndConfiguration( - new TargetAndConfiguration(target, (BuildConfigurationValue) value), fullKey); - return; + /** + * Checks the transition for idempotency before applying delegation. + * + *

If the transition is non-idempotent, marks {@link + * ConfiguredTargetKey#shouldApplyRuleTransition} false in the delegate key. + */ + private class IdempotencyChecker implements StateMachine, TransitionApplier.ResultSink { + /* At first glance, it seems like setting `shouldApplyRuleTransition=false` should be benign + * in both cases, but it would be an error in the idempotent case. + * + * Idempotent Case + * + * If we were to mark the idempotent case with `shouldApplyRuleTransition=false`, it would + * lead to action conflicts. Let `//foo[123]` be a key that rule transitions to `//foo[abc]` + * and suppose the outcome is marked `//foo[abc] shouldApplyRuleTransition=false`. + * + * A different parent might directly request `//foo[abc] shouldApplyRuleTransition=true`. + * Since the rule transition is a idempotent, it would result in the same actions as + * `//foo[abc] shouldApplyRuleTransition=false` with a different key, causing action + * conflicts. + * + * Non-idempotent Case + * + * In the example of //foo[abc] shouldApplyRuleTransition=false and //foo[abc] + * shouldApplyRuleTransition=true, there should be no action conflicts because the + * `shouldApplyRuleTransition=false` is the result of a non-idempotent rule transition and + * `shouldApplyRuleTransition=true` will produce a different configuration. */ + + // -------------------- Internal State -------------------- + private BuildConfigurationKey configurationKey2; + + @Override + public StateMachine step(Tasks tasks, ExtendedEventHandler listener) { + return new TransitionApplier( + configurationKey, + transition, + transitionCache, + (TransitionApplier.ResultSink) this, + /* runAfter= */ this::checkIdempotencyAndDelegate); + } + + @Override + public void acceptTransitionedConfigurations( + ImmutableMap transitionResult) { + checkState( + transitionResult.size() == 1, "Expected exactly one result: %s", transitionResult); + this.configurationKey2 = + checkNotNull( + transitionResult.get(ConfigurationTransition.PATCH_TRANSITION_KEY), + "Transition result missing patch transition entry: %s", + transitionResult); + } + + @Override + public void acceptTransitionError(TransitionException e) { + emitTransitionErrorMessage(e.getMessage()); + } + + @Override + public void acceptTransitionError(OptionsParsingException e) { + emitTransitionErrorMessage(e.getMessage()); + } + + private StateMachine checkIdempotencyAndDelegate(Tasks tasks, ExtendedEventHandler listener) { + if (configurationKey2 == null) { + return DONE; // There was an error. + } + + ConfiguredTargetKey.Builder keyBuilder = + ConfiguredTargetKey.builder() + .setLabel(preRuleTransitionKey.getLabel()) + .setExecutionPlatformLabel(preRuleTransitionKey.getExecutionPlatformLabel()) + .setConfigurationKey(configurationKey); + + if (!configurationKey.equals(configurationKey2)) { + // The transition was not idempotent. Explicitly informs the delegate to avoid applying a + // rule transition. + keyBuilder.setShouldApplyRuleTransition(false); + } + delegateTo(tasks, keyBuilder.build().toKey()); + return DONE; } - emitTransitionErrorMessage(error.getMessage()); } private void emitTransitionErrorMessage(String message) { - // The target must be a rule because these errors happen during the Rule transition. - Rule rule = target.getAssociatedRule(); - emitError(message, rule.getLocation(), /* exitCode= */ null); + emitError(message, TargetUtils.getLocationMaybe(target), /* exitCode= */ null); } } - private void delegateTo(Tasks tasks, ActionLookupKey delegate) { - tasks.lookUp(delegate, (Consumer) this); - } - - @Override - public void accept(SkyValue value) { - sink.acceptTargetAndConfigurationDelegatedValue((ConfiguredTargetValue) value); - } - private void emitError( String message, @Nullable Location location, @Nullable DetailedExitCode exitCode) { sink.acceptTargetAndConfigurationError( diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/UnresolvedSymlinkAction.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/UnresolvedSymlinkAction.java index 95910b3413c29d..11a54bfad32735 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/UnresolvedSymlinkAction.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/UnresolvedSymlinkAction.java @@ -103,6 +103,10 @@ protected String getRawProgressMessage() { return progressMessage; } + public PathFragment getTarget() { + return target; + } + private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) { return DetailedExitCode.of( FailureDetail.newBuilder() diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java b/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java index 62998c94d2404e..2c6b46a4279ffd 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/test/CoverageCommon.java @@ -100,10 +100,9 @@ public InstrumentedFilesInfoApi instrumentedFilesInfo( // Should have been verified by Starlark before this function is called throw new IllegalStateException(); } - if (!supportFilesBuilder.isEmpty() || !environmentPairs.isEmpty()) { - BuiltinRestriction.throwIfNotBuiltinUsage(thread); - } - if (!metadataFiles.isEmpty() || !reportedToActualSources.isEmpty()) { + if (!supportFilesBuilder.isEmpty() + || !reportedToActualSources.isEmpty() + || !environmentPairs.isEmpty()) { BuiltinRestriction.throwIfNotBuiltinUsage(thread); } return createInstrumentedFilesInfo( diff --git a/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java b/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java index 5d12a774b4a2e3..5965b8500a4a72 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/Bazel.java @@ -28,6 +28,7 @@ */ public final class Bazel { private static final String BUILD_DATA_PROPERTIES = "/build-data.properties"; + /** * The list of modules to load. Note that the order is important: In case multiple modules provide * strategies for the same things, the last module wins and its strategy becomes the default. 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 index e494a37d720f23..0ce9cb9b903a53 100644 --- 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 @@ -26,6 +26,7 @@ import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.util.ResourceFileLoader; import com.google.devtools.common.options.Converters; +import com.google.devtools.common.options.Converters.BooleanConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionDocumentationCategory; import com.google.devtools.common.options.OptionEffectTag; @@ -43,6 +44,15 @@ public final class BazelRulesModule extends BlazeModule { */ @SuppressWarnings("deprecation") // These fields have no JavaDoc by design public static class BuildGraveyardOptions extends OptionsBase { + @Option( + name = "experimental_skyframe_prepare_analysis", + deprecationWarning = "This flag is a no-op and will be deleted in a future release.", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION}, + help = "Deprecated. No-op.") + public boolean skyframePrepareAnalysis; + @Option( name = "incompatible_use_platforms_repo_for_constraints", defaultValue = "true", @@ -403,6 +413,96 @@ public static class BuildGraveyardOptions extends OptionsBase { effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, help = "Deprecated no-op.") public boolean showArtifacts; + + @Option( + name = "announce", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, + help = "Deprecated. No-op.", + deprecationWarning = "This option is now deprecated and is a no-op") + public boolean announce; + + @Option( + name = "print_workspace_in_output_paths_if_needed", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, + help = "Deprecated no-op.") + public boolean printWorkspaceInOutputPathsIfNeeded; + + @Option( + name = "experimental_multi_cpu", + deprecationWarning = "This flag is a no-op and will be deleted in a future release.", + converter = Converters.CommaSeparatedOptionListConverter.class, + allowMultiple = true, + defaultValue = "null", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, + metadataTags = {OptionMetadataTag.EXPERIMENTAL}, + help = "Deprecated. No-op.") + public List multiCpus; + + @Option( + name = "action_cache_store_output_metadata", + oldName = "experimental_action_cache_store_output_metadata", + defaultValue = "false", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = { + OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION, + OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS + }, + help = "no-op") + public boolean actionCacheStoreOutputMetadata; + + @Option( + name = "discard_actions_after_execution", + defaultValue = "true", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + metadataTags = OptionMetadataTag.INCOMPATIBLE_CHANGE, + effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE}, + help = "This option is deprecated and has no effect.") + public boolean discardActionsAfterExecution; + + @Option( + name = "defer_param_files", + defaultValue = "true", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = { + OptionEffectTag.LOADING_AND_ANALYSIS, + OptionEffectTag.EXECUTION, + OptionEffectTag.ACTION_COMMAND_LINES + }, + help = "This option is deprecated and has no effect and will be removed in the future.") + public boolean deferParamFiles; + + @Option( + name = "experimental_throttle_action_cache_check", + defaultValue = "true", + converter = BooleanConverter.class, + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + metadataTags = OptionMetadataTag.EXPERIMENTAL, + effectTags = {OptionEffectTag.EXECUTION}, + help = "no-op") + public boolean throttleActionCacheCheck; + + @Option( + name = "check_fileset_dependencies_recursively", + defaultValue = "true", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + deprecationWarning = + "This flag is a no-op and fileset dependencies are always checked " + + "to ensure correctness of builds.", + effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}) + public boolean checkFilesetDependenciesRecursively; + + @Option( + name = "experimental_skyframe_native_filesets", + defaultValue = "true", + documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, + effectTags = {OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION}, + deprecationWarning = "This flag is a no-op and skyframe-native-filesets is always true.") + public boolean skyframeNativeFileset; } /** This is where deprecated Bazel-specific options only used by the build command go to die. */ diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibraryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibraryRule.java index a8f3b3518e3327..ea4e63e20126e7 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibraryRule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/cpp/BazelCcLibraryRule.java @@ -63,6 +63,12 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) attr("implementation_deps", LABEL_LIST) .allowedFileTypes(FileTypeSet.NO_FILE) .mandatoryProviders(CcInfo.PROVIDER.id())) + /* + Any additional files you might want to pass to the compiler command line, such as sanitizer + ignorelists, for example. Files specified here can then be used in copts with the + $(location) function. + */ + .add(attr("additional_compiler_inputs", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)) .advertiseStarlarkProvider(CcInfo.PROVIDER.id()) .build(); } 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 deleted file mode 100644 index 849ebe9497cc98..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaBinary.java +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 The Bazel Authors. 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 index 87bd95df34ff60..9a735e785fc519 100644 --- 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 @@ -18,7 +18,8 @@ import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import com.google.devtools.build.lib.analysis.BaseRuleClasses; +import com.google.devtools.build.lib.analysis.BaseRuleClasses.BinaryBaseRule; +import com.google.devtools.build.lib.analysis.BaseRuleClasses.EmptyRuleConfiguredTargetFactory; 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; @@ -32,6 +33,8 @@ /** * Rule definition for the java_binary rule. + * + *

This rule is implemented in Starlark. This class remains only for doc-gen purposes. */ public final class BazelJavaBinaryRule implements RuleDefinition { @Override @@ -107,10 +110,10 @@ public Object getDefault(AttributeMap rule) { @Override public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() + return Metadata.builder() .name("java_binary") - .ancestors(BaseJavaBinaryRule.class, BaseRuleClasses.BinaryBaseRule.class) - .factoryClass(BazelJavaBinary.class) + .ancestors(BaseJavaBinaryRule.class, BinaryBaseRule.class) + .factoryClass(EmptyRuleConfiguredTargetFactory.class) .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 index 5f09384ecfb976..eb8c51e49a79cb 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java @@ -14,9 +14,6 @@ package com.google.devtools.build.lib.bazel.rules.java; -import static com.google.common.base.Strings.isNullOrEmpty; - -import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -24,7 +21,6 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.Runfiles.Builder; 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.LauncherFileWriteAction; @@ -35,16 +31,12 @@ import com.google.devtools.build.lib.analysis.actions.Substitution.ComputedSubstitution; import com.google.devtools.build.lib.analysis.actions.Template; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; -import com.google.devtools.build.lib.analysis.test.TestConfiguration; import com.google.devtools.build.lib.cmdline.Label; 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.BuildType; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; -import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; 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.JavaBuildInfoFactory; @@ -55,9 +47,7 @@ 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.JavaConfiguration.OneVersionEnforcementLevel; -import com.google.devtools.build.lib.rules.java.JavaHelper; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; -import com.google.devtools.build.lib.rules.java.JavaRuntimeInfo; import com.google.devtools.build.lib.rules.java.JavaSemantics; import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider; import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; @@ -68,9 +58,7 @@ import com.google.devtools.build.lib.shell.ShellUtils.TokenizationException; import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; import com.google.devtools.build.lib.util.OS; -import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.util.ShellEscaper; -import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.PathFragment; import java.io.File; import java.util.ArrayList; @@ -117,75 +105,11 @@ public ImmutableList getBuildInfo(RuleContext ruleContext, int stamp) public void checkForProtoLibraryAndJavaProtoLibraryOnSameProto( RuleContext ruleContext, JavaCommon javaCommon) {} - private static final String JUNIT4_RUNNER = "org.junit.runner.JUnitCore"; - @Override public String getTestRunnerMainClass() { return BAZEL_TEST_RUNNER_MAIN_CLASS; } - @Nullable - private String getMainClassInternal(RuleContext ruleContext, ImmutableList sources) { - if (!ruleContext.attributes().get("create_executable", Type.BOOLEAN)) { - return null; - } - String mainClass = getMainClassFromRule(ruleContext); - - if (mainClass.isEmpty()) { - mainClass = JavaCommon.determinePrimaryClass(ruleContext, sources); - } - return mainClass; - } - - private String getMainClassFromRule(RuleContext ruleContext) { - String mainClass = ruleContext.attributes().get("main_class", Type.STRING); - if (!mainClass.isEmpty()) { - return mainClass; - } - - if (JavaSemantics.useLegacyJavaTest(ruleContext)) { - // Legacy behavior for java_test rules: main_class defaulted to JUnit4 runner. - // TODO(dmarting): remove once we drop the legacy bazel java_test behavior. - if ("java_test".equals(ruleContext.getRule().getRuleClass())) { - return JUNIT4_RUNNER; - } - } else { - if (ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) { - return BAZEL_TEST_RUNNER_MAIN_CLASS; - } - } - return mainClass; - } - - private void checkMainClass(RuleContext ruleContext, ImmutableList sources) { - boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - String mainClass = getMainClassInternal(ruleContext, sources); - - if (!createExecutable && !isNullOrEmpty(mainClass)) { - ruleContext.ruleError("main class must not be specified when executable is not created"); - } - - if (createExecutable && isNullOrEmpty(mainClass)) { - if (sources.isEmpty()) { - ruleContext.ruleError("need at least one of 'main_class' or Java source files"); - } - mainClass = JavaCommon.determinePrimaryClass(ruleContext, sources); - if (mainClass == null) { - ruleContext.ruleError( - String.format( - "main_class was not provided and cannot be inferred: source path doesn't include" - + " a known root (%s)", - Joiner.on(", ").join(JavaUtil.KNOWN_SOURCE_ROOTS))); - } - } - } - - @Override - public String getMainClass(RuleContext ruleContext, ImmutableList sources) { - checkMainClass(ruleContext, sources); - return getMainClassInternal(ruleContext, sources); - } - @Override public ImmutableList collectResources(RuleContext ruleContext) { if (!ruleContext.getRule().isAttrDefined("resources", BuildType.LABEL_LIST)) { @@ -416,19 +340,6 @@ private static NestedSet getRuntimeJarsForTargets(TransitiveInfoCollec .getRuntimeJars(); } - @Override - public void addRunfilesForBinary( - RuleContext ruleContext, Artifact launcher, Runfiles.Builder runfilesBuilder) - throws RuleErrorException { - TransitiveInfoCollection testSupport = JavaSemantics.getTestSupport(ruleContext); - if (testSupport != null) { - // We assume that the runtime jars will not have conflicting artifacts - // with the same root relative path - runfilesBuilder.addTransitiveArtifactsWrappedInStableOrder( - getRuntimeJarsForTargets(testSupport)); - } - } - @Override public void addRunfilesForLibrary(RuleContext ruleContext, Runfiles.Builder runfilesBuilder) { } @@ -461,88 +372,6 @@ public ImmutableList getCompatibleJavacOptions( return ImmutableList.of(); } - // TODO(dmarting): simplify that logic when we remove the legacy Bazel java_test behavior. - @Nullable - private String getPrimaryClassLegacy(RuleContext ruleContext, ImmutableList sources) { - boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - if (!createExecutable) { - return null; - } - return getMainClassInternal(ruleContext, sources); - } - - @Nullable - private String getPrimaryClassNew(RuleContext ruleContext, ImmutableList sources) { - boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - - if (!createExecutable) { - return null; - } - - boolean useTestrunner = ruleContext.attributes().get("use_testrunner", Type.BOOLEAN); - - String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING) - ? ruleContext.attributes().get("test_class", Type.STRING) : ""; - - if (useTestrunner) { - if (testClass.isEmpty()) { - testClass = JavaCommon.determinePrimaryClass(ruleContext, sources); - if (testClass == null) { - ruleContext.ruleError("cannot determine junit.framework.Test class " - + "(Found no source file '" + ruleContext.getTarget().getName() - + ".java' and package name doesn't include 'java' or 'javatests'. " - + "You might want to rename the rule or add a 'test_class' " - + "attribute.)"); - } - } - return testClass; - } else { - if (!testClass.isEmpty()) { - ruleContext.attributeError("test_class", "this attribute is only meaningful to " - + "BazelTestRunner, but you are not using it (use_testrunner = 0)"); - } - return getMainClassInternal(ruleContext, sources); - } - } - - @Override - public String getPrimaryClass(RuleContext ruleContext, ImmutableList sources) { - return JavaSemantics.useLegacyJavaTest(ruleContext) - ? getPrimaryClassLegacy(ruleContext, sources) - : getPrimaryClassNew(ruleContext, sources); - } - - @Override - public Iterable getJvmFlags( - RuleContext ruleContext, ImmutableList sources, List userJvmFlags) { - ImmutableList.Builder jvmFlags = ImmutableList.builder(); - jvmFlags.addAll(userJvmFlags); - - if (!JavaSemantics.useLegacyJavaTest(ruleContext)) { - if (ruleContext.attributes().get("use_testrunner", Type.BOOLEAN)) { - String testClass = ruleContext.getRule().isAttrDefined("test_class", Type.STRING) - ? ruleContext.attributes().get("test_class", Type.STRING) : ""; - if (testClass.isEmpty()) { - testClass = JavaCommon.determinePrimaryClass(ruleContext, sources); - } - - if (testClass == null) { - ruleContext.ruleError("cannot determine test class"); - } else { - if (JavaRuntimeInfo.from(ruleContext).version() >= 17) { - jvmFlags.add("-Djava.security.manager=allow"); - } - // Always run junit tests with -ea (enable assertion) - jvmFlags.add("-ea"); - // "suite" is a misnomer. - jvmFlags.add("-Dbazel.test_suite=" + ShellEscaper.escapeString(testClass)); - } - } - } - - return jvmFlags.build(); - } - @Override public String addCoverageSupport(JavaCompilationHelper helper, Artifact executable) { // This method can be called only for *_binary/*_test targets. @@ -597,27 +426,6 @@ public CustomCommandLine buildSingleJarCommandLine( .build(); } - @Override - public ImmutableList translate(RuleContext ruleContext, List messages) { - return ImmutableList.of(); - } - - @Override - public Pair getLauncher( - RuleContext ruleContext, - JavaCommon common, - DeployArchiveBuilder deployArchiveBuilder, - DeployArchiveBuilder unstrippedDeployArchiveBuilder, - Builder runfilesBuilder, - List jvmFlags, - JavaTargetAttributes.Builder attributesBuilder, - boolean shouldStrip, - CcToolchainProvider ccToolchain, - FeatureConfiguration featureConfiguration) { - Artifact launcher = JavaHelper.launcherArtifactForTarget(this, ruleContext); - return new Pair<>(launcher, launcher); - } - @Override public void addArtifactToJavaTargetAttribute(JavaTargetAttributes.Builder builder, Artifact srcArtifact) { @@ -636,28 +444,6 @@ public PathFragment getDefaultJavaResourcePath(PathFragment path) { return javaPath == null ? path : javaPath; } - @Override - public List getExtraArguments(RuleContext ruleContext, ImmutableList sources) { - if (ruleContext.getRule().getRuleClass().equals("java_test")) { - if (JavaSemantics.useLegacyJavaTest(ruleContext)) { - TestConfiguration testConfiguration = - ruleContext.getConfiguration().getFragment(TestConfiguration.class); - if ((testConfiguration == null || testConfiguration.getTestArguments().isEmpty()) - && !ruleContext.attributes().isAttributeValueExplicitlySpecified("args")) { - ImmutableList.Builder builder = ImmutableList.builder(); - for (Artifact artifact : sources) { - PathFragment path = artifact.getRepositoryRelativePath(); - String className = JavaUtil.getJavaFullClassname(FileSystemUtils.removeExtension(path)); - if (className != null) { - builder.add(className); - } - } - return builder.build(); - } - } - } - return ImmutableList.of(); - } @Override public Artifact getProtoMapping(RuleContext ruleContext) throws InterruptedException { return null; 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 deleted file mode 100644 index fb33cef811b0a0..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTest.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 The Bazel Authors. 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.analysis.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 index 35eb7943f27fec..2230e63b33cbb4 100644 --- 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 @@ -21,6 +21,8 @@ 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.BaseRuleClasses.EmptyRuleConfiguredTargetFactory; +import com.google.devtools.build.lib.analysis.BaseRuleClasses.TestBaseRule; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; @@ -34,6 +36,8 @@ /** * Rule definition for the java_test rule. + * + *

This rule is implemented in Starlark. This class remains only for doc-gen purposes. */ public final class BazelJavaTestRule implements RuleDefinition { @@ -106,11 +110,11 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) @Override public Metadata getMetadata() { - return RuleDefinition.Metadata.builder() + return Metadata.builder() .name("java_test") .type(RuleClassType.TEST) - .ancestors(BaseJavaBinaryRule.class, BaseRuleClasses.TestBaseRule.class) - .factoryClass(BazelJavaTest.class) + .ancestors(BaseJavaBinaryRule.class, TestBaseRule.class) + .factoryClass(EmptyRuleConfiguredTargetFactory.class) .build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java index 6d7e8b6150aeaf..94f5283331197b 100644 --- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java +++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventStreamOptions.java @@ -59,9 +59,12 @@ public class BuildEventStreamOptions extends OptionsBase { name = "build_event_json_file", oldName = "experimental_build_event_json_file", defaultValue = "", + implicitRequirements = {"--bes_upload_mode=wait_for_upload_complete"}, documentationCategory = OptionDocumentationCategory.LOGGING, effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, - help = "If non-empty, write a JSON serialisation of the build event protocol to that file.") + help = + "If non-empty, write a JSON serialisation of the build event protocol to that file." + + " This option implies --bes_upload_mode=wait_for_upload_complete.") public String buildEventJsonFile; @Option( diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisAndExecutionPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisAndExecutionPhaseRunner.java index 21f81af7bbb886..9210adb9e7c842 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisAndExecutionPhaseRunner.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisAndExecutionPhaseRunner.java @@ -161,10 +161,7 @@ static AnalysisAndExecutionResult execute( env.getReporter().post(new NoAnalyzeEvent()); logger.atInfo().log("No analysis requested, so finished"); FailureDetail failureDetail = - BuildView.createAnalysisFailureDetail( - loadingResult, - /* skyframeAnalysisResult= */ null, - /* hasTopLevelTargetsWithConfigurationError= */ false); + BuildView.createAnalysisFailureDetail(loadingResult, /* skyframeAnalysisResult= */ null); if (failureDetail != null) { throw new BuildFailedException( failureDetail.getMessage(), DetailedExitCode.of(failureDetail)); diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java index a96bb2f6621329..6e8fcda45e19cf 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java @@ -161,10 +161,7 @@ public static AnalysisResult execute( env.getReporter().post(new NoAnalyzeEvent()); logger.atInfo().log("No analysis requested, so finished"); FailureDetail failureDetail = - BuildView.createAnalysisFailureDetail( - loadingResult, - /* skyframeAnalysisResult= */ null, - /* hasTopLevelTargetsWithConfigurationError= */ false); + BuildView.createAnalysisFailureDetail(loadingResult, /* skyframeAnalysisResult= */ null); if (failureDetail != null) { throw new BuildFailedException( failureDetail.getMessage(), DetailedExitCode.of(failureDetail)); diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java index f804dd30db86ca..ca06040c1ae787 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/AqueryProcessor.java @@ -87,7 +87,6 @@ public BlazeCommandResult dumpActionGraphFromSkyframe(CommandEnvironment env) { aqueryOptions.includeArtifacts, actionFilters, aqueryOptions.includeParamFiles, - aqueryOptions.deduplicateDepsets, aqueryOptions.includeFileWriteContents, aqueryOutputHandler, env.getReporter()); diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java index c189f3fc66efb7..2a8b2930241ecf 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java @@ -460,11 +460,7 @@ public boolean useValidationAspect() { private OutputGroupInfo.ValidationMode validationMode() { BuildRequestOptions buildOptions = getBuildOptions(); - // "and" these together so that --noexperimental_run_validation and --norun_validations work - // as expected. - boolean runValidationActions = - buildOptions.runValidationActions && buildOptions.experimentalRunValidationActions; - if (!runValidationActions) { + if (!buildOptions.runValidationActions) { return OutputGroupInfo.ValidationMode.OFF; } return buildOptions.useValidationAspect diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java index 6485cb0a2c3615..48842f71178282 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java @@ -160,16 +160,9 @@ public class BuildRequestOptions extends OptionsBase { + " bar are built.") public List outputGroups; - @Option( - name = "experimental_run_validations", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION, - effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.AFFECTS_OUTPUTS}, - help = "Use --run_validations instead.") - public boolean experimentalRunValidationActions; - @Option( name = "run_validations", + oldName = "experimental_run_validations", defaultValue = "true", documentationCategory = OptionDocumentationCategory.OUTPUT_SELECTION, effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.AFFECTS_OUTPUTS}, @@ -203,15 +196,6 @@ public class BuildRequestOptions extends OptionsBase { + " under the threshold.") public int maxResultTargets; - @Option( - name = "announce", - defaultValue = "false", - documentationCategory = OptionDocumentationCategory.LOGGING, - effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, - help = "Deprecated. No-op.", - deprecationWarning = "This option is now deprecated and is a no-op") - public boolean announce; - @Option( name = "symlink_prefix", defaultValue = "null", @@ -260,18 +244,6 @@ public class BuildRequestOptions extends OptionsBase { + "the convenienceSymlinksIdentified entry in the BuildEventProtocol will be empty.") public boolean experimentalConvenienceSymlinksBepEvent; - @Option( - name = "experimental_multi_cpu", - deprecationWarning = "This flag is a no-op and will be deleted in a future release.", - converter = Converters.CommaSeparatedOptionListConverter.class, - allowMultiple = true, - defaultValue = "null", - documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS, - effectTags = {OptionEffectTag.AFFECTS_OUTPUTS}, - metadataTags = {OptionMetadataTag.EXPERIMENTAL}, - help = "Deprecated. No-op.") - public List multiCpus; - @Option( name = "output_tree_tracking", oldName = "experimental_output_tree_tracking", @@ -383,19 +355,6 @@ public boolean useTopLevelTargetsForSymlinks() { + " This flag is not planned to be enabled by default, and should not be relied on.") public boolean experimentalCreatePySymlinks; - @Option( - name = "print_workspace_in_output_paths_if_needed", - defaultValue = "false", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, - help = - "If enabled, when the current working directory is deeper than the workspace (for" - + " example, when running from /foo instead of ), printed" - + " output paths include the absolute path to the workspace (for example," - + " /-bin/foo/binary instead of " - + "-bin/foo/binary).") - public boolean printWorkspaceInOutputPathsIfNeeded; - @Option( name = "use_action_cache", defaultValue = "true", @@ -407,18 +366,6 @@ public boolean useTopLevelTargetsForSymlinks() { help = "Whether to use the action cache") public boolean useActionCache; - @Option( - name = "action_cache_store_output_metadata", - oldName = "experimental_action_cache_store_output_metadata", - defaultValue = "false", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - effectTags = { - OptionEffectTag.BAZEL_INTERNAL_CONFIGURATION, - OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS - }, - help = "no-op") - public boolean actionCacheStoreOutputMetadata; - @Option( name = "rewind_lost_inputs", defaultValue = "false", @@ -429,15 +376,6 @@ public boolean useTopLevelTargetsForSymlinks() { + " prerequisites for rewinding are met (no incrementality, no action cache).") public boolean rewindLostInputs; - @Option( - name = "discard_actions_after_execution", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, - metadataTags = OptionMetadataTag.INCOMPATIBLE_CHANGE, - effectTags = {OptionEffectTag.LOSES_INCREMENTAL_STATE}, - help = "This option is deprecated and has no effect.") - public boolean discardActionsAfterExecution; - @Option( name = "incompatible_skip_genfiles_symlink", defaultValue = "true", diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java index 03f03d4b3757d5..779cdd3f6b7ffc 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildResultPrinter.java @@ -95,10 +95,7 @@ private boolean outputTargets( runtime.getRuleClassProvider().getSymlinkDefinitions(), request.getBuildOptions().getSymlinkPrefix(productName), productName, - env.getWorkspace(), - request.getBuildOptions().printWorkspaceInOutputPathsIfNeeded - ? env.getWorkingDirectory() - : env.getWorkspace()); + env.getWorkspace()); OutErr outErr = request.getOutErr(); // Splits aspects based on whether they are validation aspects. diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java index bd41e5278432a5..b976d1f41cc875 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java @@ -434,7 +434,6 @@ private void dumpSkyframeStateAfterBuild( /* includeArtifacts= */ true, /* actionFilters= */ null, /* includeParamFiles= */ false, - /* deduplicateDepsets= */ true, /* includeFileWriteContents */ false, aqueryOutputHandler, getReporter()); diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java index ac93bf2059f9a8..47ba5a408ff0f3 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/OutputDirectoryLinksUtils.java @@ -179,14 +179,9 @@ public static PathPrettyPrinter getPathPrettyPrinter( Iterable symlinkDefinitions, String symlinkPrefix, String productName, - Path workspaceDirectory, - Path workingDirectory) { + Path workspaceDirectory) { return new PathPrettyPrinter( - getAllLinkDefinitions(symlinkDefinitions), - symlinkPrefix, - productName, - workspaceDirectory, - workingDirectory); + getAllLinkDefinitions(symlinkDefinitions), symlinkPrefix, productName, workspaceDirectory); } private static void removeAllSymlinks( diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/PathPrettyPrinter.java b/src/main/java/com/google/devtools/build/lib/buildtool/PathPrettyPrinter.java index 064df933227741..c1d4e7d71cbadb 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/PathPrettyPrinter.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/PathPrettyPrinter.java @@ -29,7 +29,6 @@ public final class PathPrettyPrinter { private final String symlinkPrefix; private final String productName; private final Path workspaceDirectory; - private final Path workingDirectory; /** * Creates a path pretty printer, immediately resolving the symlink definitions by reading the @@ -39,12 +38,10 @@ public final class PathPrettyPrinter { ImmutableList symlinkDefinitions, String symlinkPrefix, String productName, - Path workspaceDirectory, - Path workingDirectory) { + Path workspaceDirectory) { this.symlinkPrefix = symlinkPrefix; this.productName = productName; this.workspaceDirectory = workspaceDirectory; - this.workingDirectory = workingDirectory; this.resolvedSymlinks = resolve(symlinkDefinitions); } @@ -87,11 +84,7 @@ public PathFragment getPrettyPath(PathFragment file) { PathFragment linkFragment = e.getKey(); PathFragment linkTarget = e.getValue(); if (file.startsWith(linkTarget)) { - PathFragment outputLink = - workingDirectory.equals(workspaceDirectory) - ? linkFragment - : workspaceDirectory.getRelative(linkFragment).asFragment(); - return outputLink.getRelative(file.relativeTo(linkTarget)); + return linkFragment.getRelative(file.relativeTo(linkTarget)); } } diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java index 25e432e4b9346d..9aeb87277ace2e 100644 --- a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java +++ b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java @@ -19,7 +19,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ComparisonChain; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Interner; import com.google.common.util.concurrent.Striped; import com.google.devtools.build.docgen.annot.DocCategory; import com.google.devtools.build.lib.actions.CommandLineItem; @@ -34,7 +33,6 @@ import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; -import com.google.devtools.build.skyframe.UsePooledLabelInterningFlag; import java.util.Arrays; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -86,16 +84,10 @@ public final class Label implements Comparable

The {@link ConfiguredTargetKey} graph contains delegation entries where instead of + * computing its own value, it delegates to a child with the same labels but a different + * configuration. This causes problems in reverse dependency traversal because traversal stops at + * duplicate values. The delegating parent has the same value as the delegate child. + * + *

This method replaces any delegating ancestor in the set of reverse dependencies with the + * reverse dependencies of the ancestor. + */ + private ImmutableListMultimap skipDelegatingAncestors( + Map> reverseDeps) throws InterruptedException { + var result = ImmutableListMultimap.builder(); + for (Map.Entry> entry : reverseDeps.entrySet()) { + SkyKey child = entry.getKey(); + Iterable rdeps = entry.getValue(); + Set unwoundRdeps = unwindReverseDependencyDelegationLayersIfFound(child, rdeps); + result.putAll(child, unwoundRdeps == null ? rdeps : unwoundRdeps); + } + return result.build(); + } + + @Nullable + private Set unwindReverseDependencyDelegationLayersIfFound( + SkyKey child, Iterable rdeps) throws InterruptedException { + // Most rdeps will not be delegating. Performs an optimistic pass that avoids copying. + boolean foundDelegatingRdep = false; + for (SkyKey rdep : rdeps) { + if (!rdep.functionName().equals(SkyFunctions.CONFIGURED_TARGET)) { + continue; + } + ConfiguredTargetKey actualParentKey = getConfiguredTargetKey(getValueFromKey(rdep)); + if (actualParentKey.equals(child)) { + // The parent has the same value as the child because it is delegating. + foundDelegatingRdep = true; + break; + } + } + if (!foundDelegatingRdep) { + return null; + } + var logicalParents = new HashSet(); + unwindReverseDependencyDelegationLayers(child, rdeps, logicalParents); + return logicalParents; + } + + private void unwindReverseDependencyDelegationLayers( + SkyKey child, Iterable rdeps, Set output) throws InterruptedException { + // Checks the value of each rdep to see if it is delegating to `child`. If so, fetches its rdeps + // and processes those, applying the same expansion as needed. + for (SkyKey rdep : rdeps) { + if (!rdep.functionName().equals(SkyFunctions.CONFIGURED_TARGET)) { + output.add(rdep); + continue; + } + ConfiguredTargetKey actualParentKey = getConfiguredTargetKey(getValueFromKey(rdep)); + if (!actualParentKey.equals(child)) { + output.add(rdep); + continue; + } + // Otherwise `rdep` is delegating to child and needs to be unwound. + Iterable rdepParents = graph.getReverseDeps(ImmutableList.of(rdep)).get(rdep); + // Applies this recursively in case there are multiple layers of delegation. + unwindReverseDependencyDelegationLayers(child, rdepParents, output); + } + } + /** * @param target source target * @param deps next level of deps to filter @@ -416,7 +489,6 @@ private ImmutableList> targetifyValues( continue; } if (key.functionName().equals(SkyFunctions.CONFIGURED_TARGET)) { - ConfiguredTargetKey ctkey = (ConfiguredTargetKey) key.argument(); T dependency = getValueFromKey(key); Preconditions.checkState( dependency != null, @@ -426,7 +498,8 @@ private ImmutableList> targetifyValues( + " configurability team.", key); - boolean implicit = implicitDeps == null || implicitDeps.contains(ctkey); + boolean implicit = + implicitDeps == null || implicitDeps.contains(getConfiguredTargetKey(dependency)); values.add(new ClassifiedDependency<>(dependency, implicit)); knownCtDeps.add(key); } else if (settings.contains(Setting.INCLUDE_ASPECTS) @@ -486,6 +559,14 @@ private ClassifiedDependency(T dependency, boolean implicit) { this.implicit = implicit; this.dependency = dependency; } + + @Override + public String toString() { + return toStringHelper(this) + .add("implicit", implicit) + .add("dependency", dependency) + .toString(); + } } private static ImmutableList getDependencies( diff --git a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java index 4d7c103fdbb753..fe93375460ca1a 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/query2/SkyQueryEnvironment.java @@ -260,7 +260,8 @@ protected EvaluationContext newEvaluationContext() { .build(); } - protected void beforeEvaluateQuery(QueryExpression expr) + protected void beforeEvaluateQuery( + QueryExpression expr, ThreadSafeOutputFormatterCallback callback) throws QueryException, InterruptedException { UniverseSkyKey universeKey = universeScope.getUniverseKey(expr, parserPrefix); ImmutableList universeScopeListToUse = universeKey.getPatterns(); @@ -295,10 +296,11 @@ protected void beforeEvaluateQuery(QueryExpression expr) /* workQueue= */ new BlockingStack<>(), new ThreadFactoryBuilder().setNameFormat("QueryEnvironment %d").build())); } - resolver = makeNewTargetPatternResolver(); + resolver = makeNewTargetPatternResolver(expr, callback); } - protected TargetPatternResolver makeNewTargetPatternResolver() { + protected TargetPatternResolver makeNewTargetPatternResolver( + QueryExpression expr, ThreadSafeOutputFormatterCallback callback) { return new RecursivePackageProviderBackedTargetPatternResolver( graphBackedRecursivePackageProvider, eventHandler, @@ -458,7 +460,7 @@ protected void handleInterruptedShutdown() {} public QueryEvalResult evaluateQuery( QueryExpression expr, ThreadSafeOutputFormatterCallback callback) throws QueryException, InterruptedException, IOException { - beforeEvaluateQuery(expr); + beforeEvaluateQuery(expr, callback); // SkyQueryEnvironment batches callback invocations using a BatchStreamedCallback, created here // so that there's one per top-level evaluateQuery call. The batch size is large enough that diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java index 5cbaf4846d321f..0de141643d5d4a 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java +++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphProtoOutputFormatterCallback.java @@ -74,7 +74,6 @@ public class ActionGraphProtoOutputFormatterCallback extends AqueryThreadsafeCal options.includeArtifacts, this.actionFilters, options.includeParamFiles, - options.deduplicateDepsets, options.includeFileWriteContents, aqueryOutputHandler, eventHandler); diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java index cb7763a5a3cb4f..e87ad3fec7f35a 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java +++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/ActionGraphTextOutputFormatterCallback.java @@ -35,6 +35,7 @@ import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; import com.google.devtools.build.lib.analysis.actions.Substitution; import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; +import com.google.devtools.build.lib.analysis.starlark.UnresolvedSymlinkAction; import com.google.devtools.build.lib.buildeventstream.BuildEvent; import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos; import com.google.devtools.build.lib.cmdline.RepositoryMapping; @@ -345,6 +346,13 @@ private void writeAction(ActionAnalysisMetadata action, PrintStream printStream) .append("]\n"); } + if (action instanceof UnresolvedSymlinkAction) { + stringBuilder + .append(" UnresolvedSymlinkTarget: ") + .append(((UnresolvedSymlinkAction) action).getTarget()) + .append("\n"); + } + stringBuilder.append('\n'); printStream.write(stringBuilder.toString().getBytes(UTF_8)); diff --git a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java index 81071863f75873..6deee8958f623e 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java +++ b/src/main/java/com/google/devtools/build/lib/query2/aquery/AqueryOptions.java @@ -78,15 +78,4 @@ public class AqueryOptions extends CommonQueryOptions { + "Note: Specifying a target with --skyframe_state is currently not supported. " + "This flag is only available with --output=proto or --output=textproto.") public boolean queryCurrentSkyframeState; - - @Option( - name = "deduplicate_depsets", - defaultValue = "true", - documentationCategory = OptionDocumentationCategory.QUERY, - effectTags = {OptionEffectTag.TERMINAL_OUTPUT}, - help = - "De-duplicate non-leaf children of a dep_set_of_files in the final proto/textproto/json" - + " output. This does not deduplicate depsets that don't share an immediate parent." - + " This does not affect the final effective list of input artifacts of the actions.") - public boolean deduplicateDepsets; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/AndroidLintActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/AndroidLintActionBuilder.java deleted file mode 100644 index abc19aed79a220..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/java/AndroidLintActionBuilder.java +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2020 The Bazel Authors. 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.rules.java; - -import static com.google.common.collect.ImmutableList.toImmutableList; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ExecutionRequirements; -import com.google.devtools.build.lib.actions.ParamFileInfo; -import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; -import com.google.devtools.build.lib.analysis.RuleContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.collect.nestedset.NestedSet; -import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; -import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.util.StringCanonicalizer; -import javax.annotation.Nullable; - -/** Helper to create Android Lint actions. */ -class AndroidLintActionBuilder { - private AndroidLintActionBuilder() {} - - private static final String MNEMONIC = "AndroidLint"; - private static final ParamFileInfo PARAM_FILE_INFO = - ParamFileInfo.builder(ParameterFileType.UNQUOTED) - .setCharset(UTF_8) - .setUseAlways(true) // needed to support workers - .build(); - - /** Creates and registers Android Lint action if needed and returns action's output if created. */ - @Nullable - static Artifact create( - RuleContext ruleContext, - JavaConfiguration config, - JavaTargetAttributes attributes, - BootClassPathInfo bootClassPathInfo, - JavaCommon common, - JavaSemantics semantics, - JavaCompileOutputs outputs) { - if (!config.runAndroidLint() - || !attributes.hasSources() - || JavaCommon.isNeverLink(ruleContext)) { - // Note Javac doesn't run when depending on neverlink library, so we also skip Android Lint. - return null; - } - if (config.limitAndroidLintToAndroidCompatible() - && !JavaCommon.getConstraints(ruleContext).contains("android")) { - return null; - } - JavaToolchainProvider toolchain = JavaToolchainProvider.from(ruleContext); - AndroidLintTool androidLint = toolchain.getAndroidLint(); - if (androidLint == null) { - ruleContext.ruleError( - "android_lint_wrapper not set in java_toolchain: " + toolchain.getToolchainLabel()); - return null; - } - - ImmutableList allSrcJars = attributes.getSourceJars(); - if (outputs.genSource() != null) { - allSrcJars = - ImmutableList.builder().addAll(allSrcJars).add(outputs.genSource()).build(); - } - NestedSet classpath = attributes.getCompileTimeClassPath(); - if (!bootClassPathInfo.auxiliary().isEmpty()) { - classpath = - NestedSetBuilder.naiveLinkOrder() - .addTransitive(bootClassPathInfo.auxiliary()) - .addTransitive(classpath) - .build(); - } - - CustomCommandLine.Builder cmd = CustomCommandLine.builder(); - cmd.addExecPaths("--sources", attributes.getSourceFiles()) - .addExecPaths("--source_jars", allSrcJars) - .addExecPaths("--bootclasspath", bootClassPathInfo.bootclasspath()) - .addExecPaths("--classpath", classpath) - .addExecPaths("--plugins", attributes.plugins().plugins().processorClasspath()) - .addLabel("--target_label", ruleContext.getLabel()); - ImmutableList javacopts = - common.getJavacOpts().stream().map(StringCanonicalizer::intern).collect(toImmutableList()); - if (!javacopts.isEmpty()) { - cmd.addAll("--javacopts", javacopts); - // terminate --javacopts with `--` to support javac flags that start with `--` - cmd.add("--"); - } - cmd.add("--lintopts"); - cmd.addAll(androidLint.options()); - - SpawnAction.Builder spawnAction = new SpawnAction.Builder(); - for (JavaPackageConfigurationProvider provider : androidLint.packageConfiguration()) { - if (provider.matches(ruleContext.getLabel())) { - cmd.addAll(provider.javacopts()); - spawnAction.addTransitiveInputs(provider.data()); - } - } - - Artifact result = - ruleContext.getPackageRelativeArtifact( - ruleContext.getLabel().getName() + "_android_lint_output.xml", - ruleContext.getBinOrGenfilesDirectory()); - cmd.addExecPath("--xml", result); - - NestedSetBuilder toolInputs = NestedSetBuilder.stableOrder(); - androidLint.tool().addInputs(toolchain, toolInputs); - - semantics.setLintProgressMessage(spawnAction); - ruleContext.registerAction( - spawnAction - .addCommandLine( - androidLint.tool().getCommandLine(toolchain, /* stripOutputPath= */ null)) - .addCommandLine(cmd.build(), PARAM_FILE_INFO) - .addInputs(attributes.getSourceFiles()) - .addInputs(allSrcJars) - .addTransitiveInputs(bootClassPathInfo.bootclasspath()) - .addTransitiveInputs(classpath) - .addTransitiveInputs(attributes.plugins().plugins().processorClasspath()) - .addTransitiveInputs(attributes.plugins().plugins().data()) - .addTransitiveTools(toolInputs.build()) - .addOutput(result) - .setMnemonic(MNEMONIC) - .setExecutionInfo(getExecutionInfo(ruleContext)) - .build(ruleContext)); - return result; - } - - /** Advertises worker support added in b/191156225. */ - private static ImmutableMap getExecutionInfo(RuleContext ruleContext) { - ImmutableMap executionInfo = - ImmutableMap.of(ExecutionRequirements.SUPPORTS_WORKERS, "1"); - - return ImmutableMap.builder() - .putAll(ruleContext.getConfiguration().modifiedExecutionInfo(executionInfo, MNEMONIC)) - .putAll( - TargetUtils.getExecutionInfo( - ruleContext.getRule(), ruleContext.isAllowTagsPropagation())) - .buildOrThrow(); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BUILD b/src/main/java/com/google/devtools/build/lib/rules/java/BUILD index f30234ff10d3de..3e4a4771613c54 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/BUILD +++ b/src/main/java/com/google/devtools/build/lib/rules/java/BUILD @@ -15,7 +15,6 @@ java_library( name = "java-rules", srcs = [ "GenericBuildInfoPropertiesTranslator.java", - "JavaBinary.java", "JavaImportBaseRule.java", "JavaInfo.java", "JavaPackageConfiguration.java", @@ -36,11 +35,9 @@ java_library( ":java-compilation", "//src/main/java/com/google/devtools/build/lib/actions", "//src/main/java/com/google/devtools/build/lib/actions:artifacts", - "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements", "//src/main/java/com/google/devtools/build/lib/analysis:actions/custom_command_line", "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster", "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration", - "//src/main/java/com/google/devtools/build/lib/analysis:config/compilation_mode", "//src/main/java/com/google/devtools/build/lib/analysis:config/execution_transition_factory", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/no_transition", "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", @@ -48,7 +45,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:package_specification_provider", "//src/main/java/com/google/devtools/build/lib/analysis:rule_definition_environment", "//src/main/java/com/google/devtools/build/lib/analysis:template_variable_info", - "//src/main/java/com/google/devtools/build/lib/analysis:test/execution_info", "//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_collection", "//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_provider", "//src/main/java/com/google/devtools/build/lib/analysis/platform", @@ -58,7 +54,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/packages", "//src/main/java/com/google/devtools/build/lib/packages:exec_group", "//src/main/java/com/google/devtools/build/lib/packages/semantics", - "//src/main/java/com/google/devtools/build/lib/rules/apple", "//src/main/java/com/google/devtools/build/lib/rules/cpp", "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi", "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/core", @@ -66,9 +61,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java", "//src/main/java/com/google/devtools/build/lib/util", "//src/main/java/com/google/devtools/build/lib/util:filetype", - "//src/main/java/com/google/devtools/build/lib/util:os", - "//src/main/java/com/google/devtools/build/lib/util:string", - "//src/main/java/com/google/devtools/build/lib/vfs", "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", "//src/main/java/net/starlark/java/eval", "//src/main/java/net/starlark/java/syntax", @@ -81,7 +73,6 @@ java_library( java_library( name = "java-compilation", srcs = [ - "AndroidLintActionBuilder.java", "AndroidLintTool.java", "BootClassPathInfo.java", "BuildInfoPropertiesTranslator.java", @@ -183,7 +174,6 @@ java_library( "//src/main/java/com/google/devtools/build/lib/util", "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code", "//src/main/java/com/google/devtools/build/lib/util:filetype", - "//src/main/java/com/google/devtools/build/lib/util:string", "//src/main/java/com/google/devtools/build/lib/vfs", "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", "//src/main/java/com/google/devtools/common/options", diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java index ad5f49b1a63e1b..4c0bc096ace14d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/BootClassPathInfo.java @@ -23,6 +23,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.packages.BuiltinProvider; import com.google.devtools.build.lib.packages.NativeInfo; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.starlarkbuildapi.FileApi; import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; import com.google.devtools.build.lib.vfs.PathFragment; @@ -46,6 +47,26 @@ public final class BootClassPathInfo extends NativeInfo implements StarlarkValue /** Provider singleton constant. */ public static final Provider PROVIDER = new Provider(); + /** + * Transforms a {@link BootClassPathInfo} instance received from Starlark to native. + * + *

For now, only native instances exist, so we handle the null/None case and cast otherwise. + * + * @param obj the instance to translate + * @return a {@link BootClassPathInfo} provider instance + * @throws RuleErrorException if the provided instance is of an incompatible type + */ + // TODO(hvd): In the future, when this provider is moved to Starlark, this method must be + // updated to translate the StarlarkInfo. + static BootClassPathInfo fromStarlark(Object obj) throws RuleErrorException { + if (obj == null || obj == Starlark.NONE) { + return empty(); + } else if (obj instanceof BootClassPathInfo) { + return (BootClassPathInfo) obj; + } + throw new RuleErrorException("expected BootClassPathInfo, got: " + Starlark.type(obj)); + } + /** Provider class for {@link BootClassPathInfo} objects. */ @StarlarkBuiltin(name = "Provider", documented = false, doc = "") public static class Provider extends BuiltinProvider implements ProviderApi { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java deleted file mode 100644 index de564a1fa3df3c..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java +++ /dev/null @@ -1,797 +0,0 @@ -// Copyright 2014 The Bazel Authors. 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.rules.java; - -import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER; -import static com.google.devtools.build.lib.packages.ExecGroup.DEFAULT_EXEC_GROUP_NAME; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; -import static com.google.devtools.build.lib.rules.cpp.CppRuleClasses.JAVA_LAUNCHER_LINK; -import static com.google.devtools.build.lib.rules.cpp.CppRuleClasses.STATIC_LINKING_MODE; -import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.COMPRESSED; -import static java.util.Objects.requireNonNull; - -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.ExecutionRequirements; -import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; -import com.google.devtools.build.lib.analysis.Allowlist; -import com.google.devtools.build.lib.analysis.ConfiguredTarget; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; -import com.google.devtools.build.lib.analysis.OutputGroupInfo; -import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; -import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; -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.SourceManifestAction; -import com.google.devtools.build.lib.analysis.SourceManifestAction.ManifestType; -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.FileWriteAction; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.analysis.config.CompilationMode; -import com.google.devtools.build.lib.analysis.test.ExecutionInfo; -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.BuildType; -import com.google.devtools.build.lib.packages.TargetUtils; -import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.apple.ApplePlatform; -import com.google.devtools.build.lib.rules.cpp.CcCommon; -import com.google.devtools.build.lib.rules.cpp.CcCommon.Language; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; -import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; -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.java.JavaCompilationArgsProvider.ClasspathType; -import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; -import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider; -import com.google.devtools.build.lib.util.OS; -import com.google.devtools.build.lib.util.Pair; -import com.google.devtools.build.lib.util.StringCanonicalizer; -import com.google.devtools.build.lib.vfs.FileSystemUtils; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; -import net.starlark.java.eval.EvalException; - -/** An implementation of java_binary. */ -public class JavaBinary implements RuleConfiguredTargetFactory { - private static final PathFragment CPP_RUNTIMES = PathFragment.create("_cpp_runtimes"); - - private final JavaSemantics semantics; - - protected JavaBinary(JavaSemantics semantics) { - this.semantics = semantics; - } - - @Override - @Nullable - public ConfiguredTarget create(RuleContext ruleContext) - throws InterruptedException, RuleErrorException, ActionConflictException { - final JavaCommon common = new JavaCommon(ruleContext, semantics); - DeployArchiveBuilder deployArchiveBuilder = new DeployArchiveBuilder(semantics, ruleContext); - Runfiles.Builder runfilesBuilder = - new Runfiles.Builder( - ruleContext.getWorkspaceName(), - ruleContext.getConfiguration().legacyExternalRunfiles()); - List jvmFlags = new ArrayList<>(); - - JavaTargetAttributes.Builder attributesBuilder = common.initCommon(); - attributesBuilder.addClassPathResources( - ruleContext.getPrerequisiteArtifacts("classpath_resources").list()); - - // Add Java8 timezone resource data - addTimezoneResourceForJavaBinaries(ruleContext, attributesBuilder); - - List userJvmFlags = JavaCommon.getJvmFlags(ruleContext); - - ruleContext.checkSrcsSamePackage(true); - boolean createExecutable = ruleContext.attributes().get("create_executable", Type.BOOLEAN); - - if (!createExecutable - && ruleContext.attributes().isAttributeValueExplicitlySpecified("launcher")) { - ruleContext.ruleError("launcher specified but create_executable is false"); - } - - if (!ruleContext.attributes().get("use_launcher", Type.BOOLEAN) - && ruleContext.attributes().isAttributeValueExplicitlySpecified("launcher")) { - ruleContext.ruleError("launcher specified but use_launcher is false"); - } - - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("add_exports") - && Allowlist.hasAllowlist(ruleContext, "java_add_exports_allowlist") - && !Allowlist.isAvailable(ruleContext, "java_add_exports_allowlist")) { - ruleContext.ruleError("setting add_exports is not permitted"); - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("add_opens") - && Allowlist.hasAllowlist(ruleContext, "java_add_opens_allowlist") - && !Allowlist.isAvailable(ruleContext, "java_add_opens_allowlist")) { - ruleContext.ruleError("setting add_opens is not permitted"); - } - - semantics.checkRule(ruleContext, common); - semantics.checkForProtoLibraryAndJavaProtoLibraryOnSameProto(ruleContext, common); - String mainClass = semantics.getMainClass(ruleContext, common.getSrcsArtifacts()); - String originalMainClass = mainClass; - if (ruleContext.hasErrors()) { - return null; - } - - // Collect the transitive dependencies. - JavaCompilationHelper helper = - new JavaCompilationHelper(ruleContext, semantics, common.getJavacOpts(), attributesBuilder); - List deps = - Lists.newArrayList(common.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)); - helper.addLibrariesToAttributes(deps); - attributesBuilder.addNativeLibraries( - JavaCommon.collectNativeLibraries(common.targetsTreatedAsDeps(ClasspathType.BOTH))); - - // deploy_env is valid for java_binary, but not for java_test. - if (ruleContext.getRule().isAttrDefined("deploy_env", BuildType.LABEL_LIST)) { - for (JavaRuntimeClasspathProvider envTarget : - ruleContext.getPrerequisites("deploy_env", JavaRuntimeClasspathProvider.class)) { - attributesBuilder.addExcludedArtifacts(envTarget.getRuntimeClasspathNestedSet()); - } - } - - Artifact srcJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_SOURCE_JAR); - JavaSourceJarsProvider.Builder javaSourceJarsProviderBuilder = - JavaSourceJarsProvider.builder() - .addSourceJar(srcJar) - .addAllTransitiveSourceJars(common.collectTransitiveSourceJars(srcJar)); - Artifact classJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_CLASS_JAR); - - CppConfiguration cppConfiguration = - ruleContext.getConfiguration().getFragment(CppConfiguration.class); - CcToolchainProvider ccToolchain = - CppHelper.getToolchainUsingDefaultCcToolchainAttribute(ruleContext); - FeatureConfiguration featureConfiguration = null; - try { - featureConfiguration = - CcCommon.configureFeaturesOrThrowEvalException( - /* requestedFeatures= */ ImmutableSet.builder() - .addAll(ruleContext.getFeatures()) - .add(STATIC_LINKING_MODE) - .add(JAVA_LAUNCHER_LINK) - .build(), - /* unsupportedFeatures= */ ruleContext.getDisabledFeatures(), - Language.CPP, - ccToolchain, - cppConfiguration); - } catch (EvalException e) { - ruleContext.ruleError(e.getMessage()); - } - boolean stripAsDefault = - ccToolchain.shouldCreatePerObjectDebugInfo(featureConfiguration, cppConfiguration) - && cppConfiguration.getCompilationMode() == CompilationMode.OPT; - DeployArchiveBuilder unstrippedDeployArchiveBuilder = null; - if (stripAsDefault) { - unstrippedDeployArchiveBuilder = new DeployArchiveBuilder(semantics, ruleContext); - } - Pair launcherAndUnstrippedLauncher = - semantics.getLauncher( - ruleContext, - common, - deployArchiveBuilder, - unstrippedDeployArchiveBuilder, - runfilesBuilder, - jvmFlags, - attributesBuilder, - stripAsDefault, - ccToolchain, - featureConfiguration); - Artifact launcher = launcherAndUnstrippedLauncher.first; - Artifact unstrippedLauncher = launcherAndUnstrippedLauncher.second; - - JavaCompilationArtifacts.Builder javaArtifactsBuilder = new JavaCompilationArtifacts.Builder(); - - NestedSetBuilder filesBuilder = NestedSetBuilder.stableOrder(); - Artifact executableForRunfiles = null; - if (createExecutable) { - // This artifact is named as the rule itself, e.g. //foo:bar_bin -> bazel-bin/foo/bar_bin - // On Windows, it's going to be bazel-bin/foo/bar_bin.exe - if (OS.getCurrent() == OS.WINDOWS) { - executableForRunfiles = - ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".exe"); - } else { - executableForRunfiles = ruleContext.createOutputArtifact(); - } - filesBuilder.add(classJar).add(executableForRunfiles); - - if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { - mainClass = semantics.addCoverageSupport(helper, executableForRunfiles); - } - } else { - filesBuilder.add(classJar); - } - - JavaCompileOutputs outputs = helper.createOutputs(classJar); - JavaRuleOutputJarsProvider.Builder ruleOutputJarsProviderBuilder = - JavaRuleOutputJarsProvider.builder() - .addJavaOutput( - JavaOutput.builder().fromJavaCompileOutputs(outputs).addSourceJar(srcJar).build()); - - JavaTargetAttributes attributes = attributesBuilder.build(); - List nativeLibraries = attributes.getNativeLibraries(); - if (!nativeLibraries.isEmpty()) { - jvmFlags.add( - "-Djava.library.path=" - + JavaCommon.javaLibraryPath( - nativeLibraries, ruleContext.getRule().getPackage().getWorkspaceName())); - } - - JavaConfiguration javaConfig = ruleContext.getFragment(JavaConfiguration.class); - if (attributes.hasMessages()) { - helper.setTranslations(semantics.translate(ruleContext, attributes.getMessages())); - } - - if (attributes.hasSources() || attributes.hasResources()) { - // We only want to add a jar to the classpath of a dependent rule if it has content. - javaArtifactsBuilder.addRuntimeJar(classJar); - } - - GeneratedExtensionRegistryProvider generatedExtensionRegistryProvider = - semantics.createGeneratedExtensionRegistry( - ruleContext, - common, - filesBuilder, - javaArtifactsBuilder, - ruleOutputJarsProviderBuilder, - javaSourceJarsProviderBuilder); - javaArtifactsBuilder.setCompileTimeDependencies(outputs.depsProto()); - - JavaCompilationArtifacts javaArtifacts = javaArtifactsBuilder.build(); - common.setJavaCompilationArtifacts(javaArtifacts); - - helper.createCompileAction(outputs); - helper.createSourceJarAction(srcJar, outputs.genSource()); - - common.setClassPathFragment( - new ClasspathConfiguredFragment( - javaArtifacts, attributes, false, helper.getBootclasspathOrDefault())); - - Iterables.addAll( - jvmFlags, semantics.getJvmFlags(ruleContext, common.getSrcsArtifacts(), userJvmFlags)); - - JavaModuleFlagsProvider javaModuleFlagsProvider = - JavaModuleFlagsProvider.create( - ruleContext, - JavaInfo.moduleFlagsProviders(common.targetsTreatedAsDeps(ClasspathType.BOTH)) - .stream()); - - javaModuleFlagsProvider.toFlags().stream() - // Share strings in the heap with the equivalent javacopt flags, which are also interned - .map(StringCanonicalizer::intern) - .forEach(jvmFlags::add); - - if (ruleContext.hasErrors()) { - return null; - } - - Artifact executableToRun = executableForRunfiles; - if (createExecutable) { - String javaExecutable; - if (semantics.isJavaExecutableSubstitution()) { - javaExecutable = JavaCommon.getJavaBinSubstitution(ruleContext, launcher); - } else { - javaExecutable = JavaCommon.getJavaExecutableForStub(ruleContext, launcher); - } - // Create a shell stub for a Java application - executableToRun = - semantics.createStubAction( - ruleContext, - common, - jvmFlags, - executableForRunfiles, - mainClass, - originalMainClass, - filesBuilder, - javaExecutable, - /* createCoverageMetadataJar= */ false); - if (!executableToRun.equals(executableForRunfiles)) { - filesBuilder.add(executableToRun); - runfilesBuilder.addArtifact(executableToRun); - } - } - - JavaSourceJarsProvider sourceJarsProvider = javaSourceJarsProviderBuilder.build(); - NestedSet transitiveSourceJars = sourceJarsProvider.getTransitiveSourceJars(); - - // TODO(bazel-team): if (getOptions().sourceJars) then make this a dummy prerequisite for the - // DeployArchiveAction ? Needs a few changes there as we can't pass inputs - SingleJarActionBuilder.createSourceJarAction( - ruleContext, - semantics, - NestedSetBuilder.emptySet(Order.STABLE_ORDER), - transitiveSourceJars, - ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_SOURCE_JAR), - ruleContext.useAutoExecGroups() - ? semantics.getJavaToolchainType() - : DEFAULT_EXEC_GROUP_NAME); - - RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext); - builder.add( - JavaPrimaryClassProvider.class, - new JavaPrimaryClassProvider( - semantics.getPrimaryClass(ruleContext, common.getSrcsArtifacts()))); - if (generatedExtensionRegistryProvider != null) { - builder.addNativeDeclaredProvider(generatedExtensionRegistryProvider); - } - - Artifact deployJar = - ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_JAR); - - if (javaConfig.oneVersionEnforcementLevel() != OneVersionEnforcementLevel.OFF) { - // This JavaBinary class is also the implementation for java_test targets (via the - // {Google,Bazel}JavaTest subclass). java_test targets can have their one version enforcement - // disabled with a second flag (to avoid the incremental build performance cost at the expense - // of safety.) - if (javaConfig.enforceOneVersionOnJavaTests() || !isJavaTestRule(ruleContext)) { - Artifact oneVersionOutputArtifact = - OneVersionCheckActionBuilder.newBuilder() - .withEnforcementLevel(javaConfig.oneVersionEnforcementLevel()) - .useToolchain(JavaToolchainProvider.from(ruleContext)) - .checkJars( - NestedSetBuilder.fromNestedSet(attributes.getRuntimeClassPath()) - .add(classJar) - .build()) - .build(ruleContext); - if (oneVersionOutputArtifact != null) { - builder.addOutputGroup(OutputGroupInfo.VALIDATION, oneVersionOutputArtifact); - } - } - } - NestedSet filesToBuild = filesBuilder.build(); - - NestedSet dynamicRuntimeActionInputs; - try { - dynamicRuntimeActionInputs = ccToolchain.getDynamicRuntimeLinkInputs(featureConfiguration); - } catch (EvalException e) { - throw ruleContext.throwWithRuleError(e); - } - - collectDefaultRunfiles( - runfilesBuilder, - ruleContext, - common, - javaArtifacts, - filesToBuild, - launcher, - dynamicRuntimeActionInputs); - Runfiles defaultRunfiles = runfilesBuilder.build(); - - RunfilesSupport runfilesSupport = null; - NestedSetBuilder extraFilesToRunBuilder = NestedSetBuilder.stableOrder(); - if (createExecutable) { - List extraArgs = - new ArrayList<>(semantics.getExtraArguments(ruleContext, common.getSrcsArtifacts())); - // The executable we pass here will be used when creating the runfiles directory. E.g. for the - // stub script called bazel-bin/foo/bar_bin, the runfiles directory will be created under - // bazel-bin/foo/bar_bin.runfiles . On platforms where there's an extra stub script (Windows) - // which dispatches to this one, we still create the runfiles directory for the shell script, - // but use the dispatcher script (a batch file) as the RunfilesProvider's executable. - runfilesSupport = - RunfilesSupport.withExecutable( - ruleContext, defaultRunfiles, executableForRunfiles, extraArgs); - extraFilesToRunBuilder.add(runfilesSupport.getRunfilesMiddleman()); - } - - RunfilesProvider runfilesProvider = - RunfilesProvider.withData( - defaultRunfiles, - new Runfiles.Builder( - ruleContext.getWorkspaceName(), - ruleContext.getConfiguration().legacyExternalRunfiles()) - .merge(runfilesSupport) - .build()); - - ImmutableList deployManifestLines = - getDeployManifestLines(ruleContext, originalMainClass); - - // Create the java_binary target specific CDS archive. - Artifact jsa = createSharedArchive(ruleContext, javaArtifacts, attributes); - - if (ruleContext.isAttrDefined("hermetic", BOOLEAN) - && ruleContext.attributes().get("hermetic", BOOLEAN)) { - if (!createExecutable) { - ruleContext.ruleError("hermetic specified but create_executable is false"); - } - - JavaRuntimeInfo javaRuntime = JavaRuntimeInfo.from(ruleContext); - if (!javaRuntime.hermeticInputs().isEmpty() - && javaRuntime.libModules() != null - && !javaRuntime.hermeticStaticLibs().isEmpty()) { - deployArchiveBuilder - .setJavaHome(javaRuntime.javaHomePathFragment()) - .setLibModules(javaRuntime.libModules()) - .setHermeticInputs(javaRuntime.hermeticInputs()); - } - - if (jsa == null) { - // Use the JDK default CDS specified by the JavaRuntime if the - // java_binary target specific CDS archive is null, when building - // a hermetic deploy JAR. - jsa = javaRuntime.defaultCDS(); - } - } - - deployArchiveBuilder - .setOutputJar(deployJar) - .setJavaStartClass(mainClass) - .setDeployManifestLines(deployManifestLines) - .setAttributes(attributes) - .addRuntimeJars(javaArtifacts.getRuntimeJars()) - .setIncludeBuildData(true) - .setRunfilesMiddleman( - runfilesSupport == null ? null : runfilesSupport.getRunfilesMiddleman()) - .setCompression(COMPRESSED) - .setLauncher(launcher) - .setOneVersionEnforcementLevel( - javaConfig.oneVersionEnforcementLevel(), - JavaToolchainProvider.from(ruleContext).getOneVersionAllowlist()) - .setMultiReleaseDeployJars(javaConfig.multiReleaseDeployJars()) - .setSharedArchive(jsa) - .setAddExports(javaModuleFlagsProvider.addExports()) - .setAddOpens(javaModuleFlagsProvider.addOpens()) - .build(); - - Artifact unstrippedDeployJar = - ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR); - if (stripAsDefault) { - requireNonNull(unstrippedDeployArchiveBuilder); // guarded by stripAsDefault - unstrippedDeployArchiveBuilder - .setOutputJar(unstrippedDeployJar) - .setJavaStartClass(mainClass) - .setDeployManifestLines(deployManifestLines) - .setAttributes(attributes) - .addRuntimeJars(javaArtifacts.getRuntimeJars()) - .setIncludeBuildData(true) - .setRunfilesMiddleman( - runfilesSupport == null ? null : runfilesSupport.getRunfilesMiddleman()) - .setCompression(COMPRESSED) - .setLauncher(unstrippedLauncher); - - unstrippedDeployArchiveBuilder.build(); - } else { - // Write an empty file as the name_deploy.jar.unstripped when the default output jar is not - // stripped. - ruleContext.registerAction( - FileWriteAction.create(ruleContext, unstrippedDeployJar, "", false)); - } - - JavaRuleOutputJarsProvider ruleOutputJarsProvider = ruleOutputJarsProviderBuilder.build(); - - JavaInfo.Builder javaInfoBuilder = JavaInfo.Builder.create(); - - NestedSetBuilder> coverageEnvironment = NestedSetBuilder.stableOrder(); - NestedSetBuilder coverageSupportFiles = NestedSetBuilder.stableOrder(); - if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { - - // Create an artifact that contains the runfiles relative paths of the jars on the runtime - // classpath. Using SourceManifestAction is the only reliable way to match the runfiles - // creation code. - Artifact runtimeClasspathArtifact = - ruleContext.getUniqueDirectoryArtifact( - "runtime_classpath_for_coverage", - "runtime_classpath.txt", - ruleContext.getBinOrGenfilesDirectory()); - ruleContext.registerAction( - new SourceManifestAction( - ManifestType.SOURCES_ONLY, - ruleContext.getActionOwner(), - runtimeClasspathArtifact, - new Runfiles.Builder( - ruleContext.getWorkspaceName(), - ruleContext.getConfiguration().legacyExternalRunfiles()) - // This matches the code below in collectDefaultRunfiles. - .addTransitiveArtifactsWrappedInStableOrder(common.getRuntimeClasspath()) - .build(), - null, - true)); - filesBuilder.add(runtimeClasspathArtifact); - - // Pass the artifact through an environment variable in the coverage environment so it - // can be read by the coverage collection script. - coverageEnvironment.add( - new Pair<>( - "JAVA_RUNTIME_CLASSPATH_FOR_COVERAGE", runtimeClasspathArtifact.getExecPathString())); - // Add the file to coverageSupportFiles so it ends up as an input for the test action - // when coverage is enabled. - coverageSupportFiles.add(runtimeClasspathArtifact); - - // Make single jar reachable from the coverage environment because it needs to be executed - // by the coverage collection script. - FilesToRunProvider singleJar = JavaToolchainProvider.from(ruleContext).getSingleJar(); - coverageEnvironment.add( - new Pair<>("SINGLE_JAR_TOOL", singleJar.getExecutable().getExecPathString())); - coverageSupportFiles.addTransitive(singleJar.getFilesToRun()); - } - - common.addTransitiveInfoProviders( - builder, - javaInfoBuilder, - filesToBuild, - classJar, - coverageEnvironment.build(), - coverageSupportFiles.build()); - common.addGenJarsProvider(builder, javaInfoBuilder, outputs.genClass(), outputs.genSource()); - - // This rule specifically _won't_ build deploy_env, so we selectively propagate validations to - // filter out deploy_env's if there are any (and otherwise rely on automatic validation - // propagation). Note that any validations not propagated here will still be built if and when - // deploy_env is built. - if (ruleContext.getRule().isAttrDefined("deploy_env", BuildType.LABEL_LIST)) { - NestedSetBuilder excluded = NestedSetBuilder.stableOrder(); - for (OutputGroupInfo outputGroup : - ruleContext.getPrerequisites("deploy_env", OutputGroupInfo.STARLARK_CONSTRUCTOR)) { - NestedSet toExclude = outputGroup.getOutputGroup(OutputGroupInfo.VALIDATION); - if (!toExclude.isEmpty()) { - excluded.addTransitive(toExclude); - } - } - if (!excluded.isEmpty()) { - NestedSetBuilder validations = NestedSetBuilder.stableOrder(); - RuleConfiguredTargetBuilder.collectTransitiveValidationOutputGroups( - ruleContext, - attributeName -> !"deploy_env".equals(attributeName), - validations::addTransitive); - - // Likely, deploy_env will overlap with deps/runtime_deps. Unless we're building an - // executable (which is rare and somewhat questionable when deploy_env is specified), we can - // exclude validations from deploy_env entirely from this rule, since this rule specifically - // never builds the referenced code. - if (createExecutable) { - // Executable classpath isn't affected by deploy_env, so build all collected validations. - builder.addOutputGroup(OutputGroupInfo.VALIDATION_TRANSITIVE, validations.build()); - } else { - // Filter validations similar to JavaTargetAttributes.getRuntimeClassPathForArchive(). - builder.addOutputGroup( - OutputGroupInfo.VALIDATION_TRANSITIVE, - NestedSetBuilder.wrap( - Order.STABLE_ORDER, - Iterables.filter( - validations.build().toList(), - Predicates.not(Predicates.in(excluded.build().toSet()))))); - } - } - } - - Artifact validation = - AndroidLintActionBuilder.create( - ruleContext, - javaConfig, - attributes, - helper.getBootclasspathOrDefault(), - common, - semantics, - outputs); - if (validation != null) { - builder.addOutputGroup( - OutputGroupInfo.VALIDATION, NestedSetBuilder.create(STABLE_ORDER, validation)); - } - - // Support test execution on darwin. - if (ApplePlatform.isApplePlatform(ruleContext.getConfiguration().getCpu()) - && TargetUtils.isTestRule(ruleContext.getRule())) { - builder.addNativeDeclaredProvider( - new ExecutionInfo(ImmutableMap.of(ExecutionRequirements.REQUIRES_DARWIN, ""))); - } - - JavaInfo javaInfo = - javaInfoBuilder - .javaSourceJars(sourceJarsProvider) - .javaRuleOutputs(ruleOutputJarsProvider) - .build(); - - return builder - .setFilesToBuild(filesToBuild) - .addStarlarkDeclaredProvider(javaInfo) - .add(RunfilesProvider.class, runfilesProvider) - // The executable to run (below) may be different from the executable for runfiles (the one - // we create the runfiles support object with). On Linux they are the same (it's the same - // shell script), on Windows they are different (the executable to run is a batch file, the - // executable for runfiles is the shell script). - .setRunfilesSupport(runfilesSupport, executableToRun) - // Add the native libraries as test action tools. Useful for the persistent test runner - // to include them in the worker's key and re-build a worker if the native dependencies - // have changed. - .addTestActionTools(nativeLibraries) - .addFilesToRun(extraFilesToRunBuilder.build()) - .add( - JavaRuntimeClasspathProvider.class, - new JavaRuntimeClasspathProvider(common.getRuntimeClasspath())) - .addOutputGroup(JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, transitiveSourceJars) - .addOutputGroup( - JavaSemantics.DIRECT_SOURCE_JARS_OUTPUT_GROUP, - NestedSetBuilder.wrap(Order.STABLE_ORDER, sourceJarsProvider.getSourceJars())) - .build(); - } - - @Nullable - private static Artifact createSharedArchive( - RuleContext ruleContext, - JavaCompilationArtifacts javaArtifacts, - JavaTargetAttributes attributes) - throws InterruptedException { - if (!ruleContext.getRule().isAttrDefined("classlist", BuildType.LABEL)) { - return null; - } - Artifact classlist = ruleContext.getPrerequisiteArtifact("classlist"); - if (classlist == null) { - return null; - } - NestedSet classpath = - NestedSetBuilder.stableOrder() - .addAll(javaArtifacts.getRuntimeJars()) - .addTransitive(attributes.getRuntimeClassPathForArchive()) - .build(); - Artifact jsa = ruleContext.getImplicitOutputArtifact(JavaSemantics.SHARED_ARCHIVE_ARTIFACT); - Artifact merged = - ruleContext.getDerivedArtifact( - jsa.getOutputDirRelativePath(ruleContext.getConfiguration().isSiblingRepositoryLayout()) - .replaceName( - FileSystemUtils.removeExtension(jsa.getRootRelativePath().getBaseName()) - + "-merged.jar"), - jsa.getRoot()); - SingleJarActionBuilder.createSingleJarAction(ruleContext, classpath, merged); - JavaRuntimeInfo javaRuntime = JavaRuntimeInfo.from(ruleContext); - Artifact configFile = ruleContext.getPrerequisiteArtifact("cds_config_file"); - - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .add("-Xshare:dump") - .addFormatted("-XX:SharedArchiveFile=%s", jsa.getExecPath()) - .addFormatted("-XX:SharedClassListFile=%s", classlist.getExecPath()); - if (configFile != null) { - commandLine.addFormatted("-XX:SharedArchiveConfigFile=%s", configFile.getExecPath()); - } - commandLine.add("-cp").addExecPath(merged); - SpawnAction.Builder spawnAction = new SpawnAction.Builder(); - if (ruleContext.getRule().isAttrDefined("jvm_flags_for_cds_image_creation", Type.STRING_LIST)) { - commandLine.addAll( - ruleContext - .getExpander() - .withDataExecLocations() - .list("jvm_flags_for_cds_image_creation")); - spawnAction.addTransitiveInputs(PrerequisiteArtifacts.nestedSet(ruleContext, "data")); - } - spawnAction - .setExecutable(javaRuntime.javaBinaryExecPathFragment()) - .addCommandLine(commandLine.build()) - .setMnemonic("JavaJSA") - .setProgressMessage("Dumping Java Shared Archive %s", jsa.prettyPrint()) - .addOutput(jsa) - .addInput(classlist) - .addInput(merged) - .addTransitiveInputs(javaRuntime.javaBaseInputs()); - if (configFile != null) { - spawnAction.addInput(configFile); - } - ruleContext.registerAction(spawnAction.build(ruleContext)); - return jsa; - } - - // Create the deploy jar and make it dependent on the runfiles middleman if an executable is - // created. Do not add the deploy jar to files to build, so we will only build it when it gets - // requested. - private static ImmutableList getDeployManifestLines( - RuleContext ruleContext, String originalMainClass) { - ImmutableList.Builder builder = - ImmutableList.builder() - .addAll(ruleContext.attributes().get("deploy_manifest_lines", Type.STRING_LIST)); - if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { - builder.add("Coverage-Main-Class: " + originalMainClass); - } - return builder.build(); - } - - /** Add Java8 timezone resource jar to java binary, if specified in tool chain. */ - private static void addTimezoneResourceForJavaBinaries( - RuleContext ruleContext, JavaTargetAttributes.Builder attributesBuilder) { - JavaToolchainProvider toolchainProvider = JavaToolchainProvider.from(ruleContext); - if (toolchainProvider.getTimezoneData() != null) { - attributesBuilder.addResourceJars( - NestedSetBuilder.create(Order.STABLE_ORDER, toolchainProvider.getTimezoneData())); - } - } - - private void collectDefaultRunfiles( - Runfiles.Builder builder, - RuleContext ruleContext, - JavaCommon common, - JavaCompilationArtifacts javaArtifacts, - NestedSet filesToBuild, - Artifact launcher, - NestedSet dynamicRuntimeActionInputs) - throws RuleErrorException { - builder.addTransitiveArtifactsWrappedInStableOrder(filesToBuild); - builder.addArtifacts(javaArtifacts.getRuntimeJars()); - if (launcher != null) { - final TransitiveInfoCollection defaultLauncher = - JavaHelper.launcherForTarget(semantics, ruleContext); - final Artifact defaultLauncherArtifact = - JavaHelper.launcherArtifactForTarget(semantics, ruleContext); - if (!defaultLauncherArtifact.equals(launcher)) { - builder.addArtifact(launcher); - - // N.B. The "default launcher" referred to here is the launcher target specified through - // an attribute or flag. We wish to retain the runfiles of the default launcher, *except* - // for the original cc_binary artifact, because we've swapped it out with our custom - // launcher. Hence, instead of calling builder.addTarget(), or adding an odd method - // to Runfiles.Builder, we "unravel" the call and manually add things to the builder. - // Because the NestedSet representing each target's launcher runfiles is re-built here, - // we may see increased memory consumption for representing the target's runfiles. - Runfiles runfiles = - defaultLauncher.getProvider(RunfilesProvider.class).getDefaultRunfiles(); - NestedSetBuilder unconditionalArtifacts = NestedSetBuilder.compileOrder(); - for (Artifact a : runfiles.getArtifacts().toList()) { - if (!a.equals(defaultLauncherArtifact)) { - unconditionalArtifacts.add(a); - } - } - builder.addTransitiveArtifacts(unconditionalArtifacts.build()); - builder.addSymlinks(runfiles.getSymlinks()); - builder.addRootSymlinks(runfiles.getRootSymlinks()); - } else { - builder.addTarget( - defaultLauncher, - RunfilesProvider.DEFAULT_RUNFILES, - ruleContext.getConfiguration().alwaysIncludeFilesToBuildInData()); - } - } - - semantics.addRunfilesForBinary(ruleContext, launcher, builder); - builder.addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES); - - List runtimeDeps = - ruleContext.getPrerequisites("runtime_deps"); - builder.addTargets( - runtimeDeps, - RunfilesProvider.DEFAULT_RUNFILES, - ruleContext.getConfiguration().alwaysIncludeFilesToBuildInData()); - - builder.addTransitiveArtifactsWrappedInStableOrder(common.getRuntimeClasspath()); - - // Add the JDK files if it comes from the source repository (see java_stub_template.txt). - JavaRuntimeInfo javaRuntime = JavaRuntimeInfo.from(ruleContext); - if (javaRuntime != null) { - builder.addTransitiveArtifacts(javaRuntime.javaBaseInputs()); - - if (!javaRuntime.javaHomePathFragment().isAbsolute()) { - // Add symlinks to the C++ runtime libraries under a path that can be built - // into the Java binary without having to embed the crosstool, gcc, and grte - // version information contained within the libraries' package paths. - for (Artifact lib : dynamicRuntimeActionInputs.toList()) { - PathFragment path = CPP_RUNTIMES.getRelative(lib.getExecPath().getBaseName()); - builder.addSymlink(path, lib); - } - } - } - } - - private static boolean isJavaTestRule(RuleContext ruleContext) { - return ruleContext.getRule().getRuleClass().endsWith("_test"); - } -} diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java index 2147c6030ec46f..29ea5698421245 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCommon.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.devtools.build.lib.packages.Type.BOOLEAN; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -52,9 +51,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.stream.Stream; import javax.annotation.Nullable; @@ -82,27 +79,6 @@ public class JavaCommon { private final JavaToolchainProvider javaToolchain; private JavaCompilationHelper javaCompilationHelper; - public JavaCommon(RuleContext ruleContext, JavaSemantics semantics) { - this( - ruleContext, - semantics, - ruleContext.getPrerequisiteArtifacts("srcs").list(), - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.COMPILE_ONLY), - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.RUNTIME_ONLY), - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.BOTH)); - } - - public JavaCommon( - RuleContext ruleContext, JavaSemantics semantics, ImmutableList sources) { - this( - ruleContext, - semantics, - sources, - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.COMPILE_ONLY), - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.RUNTIME_ONLY), - collectTargetsTreatedAsDeps(ruleContext, semantics, ClasspathType.BOTH)); - } - public JavaCommon( RuleContext ruleContext, JavaSemantics semantics, @@ -179,33 +155,6 @@ public JavaCompilationArtifacts getJavaCompilationArtifacts() { return javaArtifacts; } - /** - * Creates the java.library.path from a list of the native libraries. Concatenates the parent - * directories of the shared libraries into a Java search path. Each relative path entry is - * prepended with "${JAVA_RUNFILES}/" so it can be resolved at runtime. - * - * @param sharedLibraries a collection of native libraries to create the java library path from - * @return a String containing the ":" separated java library path - */ - public static String javaLibraryPath(Collection sharedLibraries, String runfilePrefix) { - StringBuilder buffer = new StringBuilder(); - Set entries = new HashSet<>(); - for (Artifact sharedLibrary : sharedLibraries) { - PathFragment entry = sharedLibrary.getRootRelativePath().getParentDirectory(); - if (entries.add(entry)) { - if (buffer.length() > 0) { - buffer.append(':'); - } - buffer - .append("${JAVA_RUNFILES}/") - .append(runfilePrefix) - .append("/") - .append(entry.getPathString()); - } - } - return buffer.toString(); - } - /** * Collects Java compilation arguments for this target. * @@ -499,10 +448,6 @@ private static List getRuntimeDeps(RuleContext ruleCon } } - public JavaTargetAttributes.Builder initCommon() throws RuleErrorException, InterruptedException { - return initCommon(ImmutableList.of(), getCompatibleJavacOptions()); - } - /** * Initialize the common actions and build various collections of artifacts for the * initializationHook() methods of the subclasses. @@ -556,10 +501,6 @@ public JavaTargetAttributes.Builder initCommon( return javaTargetAttributes; } - private ImmutableList getCompatibleJavacOptions() { - return semantics.getCompatibleJavacOptions(ruleContext, javaToolchain); - } - private boolean disallowDepsWithoutSrcs(String ruleClass) { return ruleClass.equals("java_library") || ruleClass.equals("java_binary") @@ -571,14 +512,6 @@ public ImmutableList targetsTreatedAsDeps( return targetsTreatedAsDeps.get(type); } - public ImmutableList hermeticStaticLibs() { - if (ruleContext.isAttrDefined("hermetic", BOOLEAN) - && ruleContext.attributes().get("hermetic", BOOLEAN)) { - return JavaRuntimeInfo.from(ruleContext).hermeticStaticLibs(); - } - return ImmutableList.of(); - } - /** Returns the default dependencies for the given classpath context. */ public static ImmutableList defaultDeps( RuleContext ruleContext, JavaSemantics semantics, ClasspathType type) { @@ -741,7 +674,7 @@ public void addGenJarsProvider( } /** Processes the sources of this target, adding them as messages or proper sources. */ - private void processSrcs(JavaTargetAttributes.Builder attributes) { + private void processSrcs(JavaTargetAttributes.Builder attributes) throws RuleErrorException { List srcs = ruleContext.getPrerequisites("srcs"); for (TransitiveInfoCollection src : srcs) { ImmutableList messages = MessageBundleInfo.getMessages(src); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java index cc94e47b92b79a..c3a357d4f43aad 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java @@ -74,8 +74,6 @@ public final class JavaCompilationHelper { private final JavaTargetAttributes.Builder attributes; private JavaTargetAttributes builtAttributes; private final ImmutableList customJavacOpts; - private final List translations = new ArrayList<>(); - private boolean translationsFrozen; private final JavaSemantics semantics; private final ImmutableList additionalInputsForDatabinding; private final StrictDepsMode strictJavaDeps; @@ -410,8 +408,7 @@ private boolean separateResourceJar( return !resourceJars.isEmpty() || !attributes.getResources().isEmpty() || !attributes.getResourceJars().isEmpty() - || !attributes.getClassPathResources().isEmpty() - || !getTranslations().isEmpty(); + || !attributes.getClassPathResources().isEmpty(); } private ImmutableMap getExecutionInfo() { @@ -658,7 +655,6 @@ private void createResourceJarAction(Artifact resourceJar, ImmutableList getJavacOpts() { return customJavacOpts; } - public void setTranslations(Collection translations) { - Preconditions.checkArgument(!translationsFrozen); - this.translations.addAll(translations); - } - - private ImmutableList getTranslations() { - translationsFrozen = true; - return ImmutableList.copyOf(translations); - } - /** * Creates the Action that creates ijars from Jar files. * diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationInfoProvider.java index 91154791aa1290..da766f8160fec7 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationInfoProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationInfoProvider.java @@ -20,10 +20,15 @@ import com.google.devtools.build.lib.collect.nestedset.Depset; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.packages.StructImpl; import com.google.devtools.build.lib.rules.java.JavaInfo.JavaInfoInternalProvider; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaCompilationInfoProviderApi; import com.google.errorprone.annotations.CanIgnoreReturnValue; import javax.annotation.Nullable; +import net.starlark.java.eval.EvalException; +import net.starlark.java.eval.Sequence; +import net.starlark.java.eval.Starlark; /** * A class that provides compilation information in Java rules, for perusal of aspects and tools. @@ -36,6 +41,46 @@ public final class JavaCompilationInfoProvider @Nullable private final NestedSet compilationClasspath; private final BootClassPathInfo bootClasspath; + /** + * Transforms the {@code compilation_info} field from a {@link JavaInfo} into a native instance. + * + * @param javaInfo A {@link JavaInfo} instance. + * @return a {@link JavaCompilationInfoProvider} instance or {@code null} if the {@code + * compilation_info} field is not present in the supplied {@code javaInfo} + * @throws RuleErrorException if the {@code compilation_info} is of an incompatible type + * @throws EvalException if there are any errors accessing Starlark values + */ + @Nullable + static JavaCompilationInfoProvider fromStarlarkJavaInfo(StructImpl javaInfo) + throws RuleErrorException, EvalException { + Object value = javaInfo.getValue("compilation_info"); + if (value == null || value == Starlark.NONE) { + return null; + } else if (value instanceof JavaCompilationInfoProvider) { + return (JavaCompilationInfoProvider) value; + } else if (value instanceof StructImpl) { + StructImpl info = (StructImpl) value; + Builder builder = + new Builder() + .setJavacOpts( + Sequence.cast(info.getValue("javac_options"), String.class, "javac_options") + .getImmutableList()) + .setBootClasspath(BootClassPathInfo.fromStarlark(info.getValue("boot_classpath"))); + Object runtimeClasspath = info.getValue("runtime_classpath"); + if (runtimeClasspath != null) { + builder.setRuntimeClasspath( + Depset.noneableCast(runtimeClasspath, Artifact.class, "runtime_classpath")); + } + Object compilationClasspath = info.getValue("compilation_classpath"); + if (compilationClasspath != null) { + builder.setCompilationClasspath( + Depset.noneableCast(compilationClasspath, Artifact.class, "compilation_classpath")); + } + return builder.build(); + } + throw new RuleErrorException("expected java_compilation_info, got: " + Starlark.type(value)); + } + @Override public boolean isImmutable() { return true; // immutable and Starlark-hashable diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java index a2d9939bc80748..fd612854c6902d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfo.java @@ -36,7 +36,6 @@ import com.google.devtools.build.lib.rules.cpp.LibraryToLink; import com.google.devtools.build.lib.rules.java.JavaPluginInfo.JavaPluginData; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; -import com.google.devtools.build.lib.starlarkbuildapi.FileApi; import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcInfoApi; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaInfoApi; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaModuleFlagsProviderApi; @@ -52,7 +51,6 @@ import net.starlark.java.eval.Sequence; import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkList; -import net.starlark.java.eval.StarlarkThread; import net.starlark.java.eval.StarlarkValue; import net.starlark.java.syntax.Location; @@ -241,7 +239,7 @@ static T nullIfNone(Object object, Class type) { /** Java constraints (e.g. "android") that are present on the target. */ private final ImmutableList javaConstraints; - // Whether or not this library should be used only for compilation and not at runtime. + // Whether this library should be used only for compilation and not at runtime. private final boolean neverlink; @Nullable @@ -398,7 +396,7 @@ private JavaInfo(StructImpl javaInfo) throws EvalException, TypeException, RuleE this( JavaCcInfoProvider.fromStarlarkJavaInfo(javaInfo), JavaCompilationArgsProvider.fromStarlarkJavaInfo(javaInfo), - /* javaCompilationInfoProvider= */ null, + JavaCompilationInfoProvider.fromStarlarkJavaInfo(javaInfo), JavaGenJarsProvider.from(javaInfo.getValue("annotation_processing")), JavaModuleFlagsProvider.fromStarlarkJavaInfo(javaInfo), JavaPluginInfo.fromStarlarkJavaInfo(javaInfo), @@ -406,7 +404,7 @@ private JavaInfo(StructImpl javaInfo) throws EvalException, TypeException, RuleE JavaSourceJarsProvider.fromStarlarkJavaInfo(javaInfo), extractDirectRuntimeJars(javaInfo), extractNeverLink(javaInfo), - ImmutableList.of(), + extractConstraints(javaInfo), javaInfo.getCreationLocation()); } @@ -422,12 +420,22 @@ private static boolean extractNeverLink(StructImpl javaInfo) throws EvalExceptio return neverlink != null && neverlink; } + private static ImmutableList extractConstraints(StructImpl javaInfo) + throws EvalException { + Object constraints = javaInfo.getValue("_constraints"); + if (constraints == null || constraints == Starlark.NONE) { + return ImmutableList.of(); + } + return Sequence.cast(constraints, String.class, "_constraints").getImmutableList(); + } + @Override public JavaInfoProvider getProvider() { return PROVIDER; } - public Boolean isNeverlink() { + @Override + public boolean isNeverlink() { return neverlink; } @@ -583,6 +591,11 @@ public ImmutableList getJavaConstraints() { return javaConstraints; } + @Override + public Sequence getJavaConstraintsStarlark() { + return StarlarkList.immutableCopyOf(javaConstraints); + } + /** * Gets Provider, check it for not null and call function to get NestedSet<S> from it. * @@ -647,56 +660,6 @@ private JavaInfoProvider() { super(Label.parseCanonicalUnchecked("@_builtins//:common/java/java_info.bzl"), STARLARK_NAME); } - @Override - public JavaInfo javaInfo( - FileApi outputJarApi, - Object compileJarApi, - Object sourceJarApi, - Object compileJdepsApi, - Object generatedClassJarApi, - Object generatedSourceJarApi, - Object nativeHeadersJarApi, - Object manifestProtoApi, - Boolean neverlink, - Sequence deps, - Sequence runtimeDeps, - Sequence exports, - Sequence exportedPlugins, - Object jdepsApi, - Sequence nativeLibraries, - StarlarkThread thread) - throws EvalException, RuleErrorException { - Artifact outputJar = (Artifact) outputJarApi; - @Nullable Artifact compileJar = nullIfNone(compileJarApi, Artifact.class); - @Nullable Artifact sourceJar = nullIfNone(sourceJarApi, Artifact.class); - @Nullable Artifact compileJdeps = nullIfNone(compileJdepsApi, Artifact.class); - @Nullable Artifact generatedClassJar = nullIfNone(generatedClassJarApi, Artifact.class); - @Nullable Artifact generatedSourceJar = nullIfNone(generatedSourceJarApi, Artifact.class); - @Nullable Artifact nativeHeadersJar = nullIfNone(nativeHeadersJarApi, Artifact.class); - @Nullable Artifact manifestProto = nullIfNone(manifestProtoApi, Artifact.class); - @Nullable Artifact jdeps = nullIfNone(jdepsApi, Artifact.class); - return JavaInfoBuildHelper.getInstance() - .createJavaInfo( - JavaOutput.builder() - .setClassJar(outputJar) - .setCompileJar(compileJar) - .setCompileJdeps(compileJdeps) - .setGeneratedClassJar(generatedClassJar) - .setGeneratedSourceJar(generatedSourceJar) - .setNativeHeadersJar(nativeHeadersJar) - .setManifestProto(manifestProto) - .setJdeps(jdeps) - .addSourceJar(sourceJar) - .build(), - neverlink, - Sequence.cast(deps, JavaInfo.class, "deps"), - Sequence.cast(runtimeDeps, JavaInfo.class, "runtime_deps"), - Sequence.cast(exports, JavaInfo.class, "exports"), - JavaPluginInfo.wrapSequence(exportedPlugins, "exported_plugins"), - Sequence.cast(nativeLibraries, CcInfo.class, "native_libraries"), - thread.getCallerLocation()); - } - @Override public JavaInfo wrap(Info info) throws RuleErrorException { if (info instanceof JavaInfo) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java index 87777b79fdbeda..a5bdde6a54261b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaInfoBuildHelper.java @@ -16,44 +16,29 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Streams.stream; -import static com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType.BOTH; -import static com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType.COMPILE_ONLY; -import static com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType.RUNTIME_ONLY; import static com.google.devtools.build.lib.rules.java.JavaInfo.streamProviders; import static java.util.stream.Stream.concat; import com.google.common.base.Ascii; import com.google.common.collect.ImmutableList; import com.google.common.collect.Streams; -import com.google.devtools.build.lib.actions.ActionRegistry; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; -import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.CoreOptionConverters.StrictDepsMode; -import com.google.devtools.build.lib.analysis.starlark.StarlarkActionFactory; import com.google.devtools.build.lib.analysis.starlark.StarlarkRuleContext; -import com.google.devtools.build.lib.cmdline.Label; 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.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.rules.cpp.CcInfo; -import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; import com.google.devtools.build.lib.shell.ShellUtils; -import com.google.devtools.build.lib.vfs.FileSystemUtils; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Stream; -import javax.annotation.Nullable; import net.starlark.java.eval.EvalException; -import net.starlark.java.eval.Sequence; import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkThread; -import net.starlark.java.syntax.Location; /** Implements logic for creating JavaInfo from different set of input parameters. */ final class JavaInfoBuildHelper { @@ -65,101 +50,6 @@ public static JavaInfoBuildHelper getInstance() { return INSTANCE; } - /** - * Creates JavaInfo instance from outputJar. - * - * @param javaOutput the artifacts that were created as a result of a compilation (e.g. javac, - * scalac, etc) - * @param neverlink if true only use this library for compilation and not at runtime - * @param compileTimeDeps compile time dependencies that were used to create the output jar - * @param runtimeDeps runtime dependencies that are needed for this library - * @param exports libraries to make available for users of this library. java_library.exports - * @param exportedPlugins A list of exported plugins. - * @param nativeLibraries CC library dependencies that are needed for this library - * @return new created JavaInfo instance - */ - JavaInfo createJavaInfo( - JavaOutput javaOutput, - Boolean neverlink, - Sequence compileTimeDeps, - Sequence runtimeDeps, - Sequence exports, - Iterable exportedPlugins, - Sequence nativeLibraries, - Location location) - throws RuleErrorException, EvalException { - JavaInfo.Builder javaInfoBuilder = JavaInfo.Builder.create(); - javaInfoBuilder.setLocation(location); - javaInfoBuilder.setNeverlink(neverlink); - - JavaCompilationArgsProvider.Builder javaCompilationArgsBuilder = - JavaCompilationArgsProvider.builder(); - - if (!neverlink) { - javaCompilationArgsBuilder.addRuntimeJar(javaOutput.getClassJar()); - } - if (javaOutput.getCompileJar() != null) { - javaCompilationArgsBuilder.addDirectCompileTimeJar( - /* interfaceJar= */ javaOutput.getCompileJar(), /* fullJar= */ javaOutput.getClassJar()); - } - - JavaRuleOutputJarsProvider javaRuleOutputJarsProvider = - JavaRuleOutputJarsProvider.builder().addJavaOutput(javaOutput).build(); - javaInfoBuilder.javaRuleOutputs(javaRuleOutputJarsProvider); - - ClasspathType type = neverlink ? COMPILE_ONLY : BOTH; - - streamProviders(exports, JavaCompilationArgsProvider.class) - .forEach(args -> javaCompilationArgsBuilder.addExports(args, type)); - streamProviders(compileTimeDeps, JavaCompilationArgsProvider.class) - .forEach(args -> javaCompilationArgsBuilder.addDeps(args, type)); - - streamProviders(runtimeDeps, JavaCompilationArgsProvider.class) - .forEach(args -> javaCompilationArgsBuilder.addDeps(args, RUNTIME_ONLY)); - - if (javaOutput.getCompileJdeps() != null) { - javaCompilationArgsBuilder.addCompileTimeJavaDependencyArtifacts( - NestedSetBuilder.create(Order.STABLE_ORDER, javaOutput.getCompileJdeps())); - } - - javaInfoBuilder.javaCompilationArgs(javaCompilationArgsBuilder.build()); - - javaInfoBuilder.javaPluginInfo(mergeExportedJavaPluginInfo(exportedPlugins, exports)); - - javaInfoBuilder.javaSourceJars( - createJavaSourceJarsProvider( - javaOutput.getSourceJars(), concat(compileTimeDeps, runtimeDeps, exports))); - - javaInfoBuilder.javaGenJars( - JavaGenJarsProvider.create( - false, - javaOutput.getGeneratedClassJar(), - javaOutput.getGeneratedSourceJar(), - JavaPluginInfo.empty(), - collectJavaGenJarsProviders(concat(compileTimeDeps, exports)))); - - javaInfoBuilder.setRuntimeJars(ImmutableList.of(javaOutput.getClassJar())); - - ImmutableList transitiveNativeLibraries = - Streams.concat( - streamProviders(runtimeDeps, JavaCcInfoProvider.class), - streamProviders(exports, JavaCcInfoProvider.class), - streamProviders(compileTimeDeps, JavaCcInfoProvider.class), - Stream.of(new JavaCcInfoProvider(CcInfo.merge(nativeLibraries)))) - .collect(toImmutableList()); - javaInfoBuilder.javaCcInfo(JavaCcInfoProvider.merge(transitiveNativeLibraries)); - - javaInfoBuilder.javaModuleFlags( - JavaModuleFlagsProvider.merge( - JavaInfo.streamProviders( - concat(compileTimeDeps, exports), JavaModuleFlagsProvider.class) - .collect(toImmutableList()))); - - return javaInfoBuilder.build(); - } - private static ImmutableList collectJavaGenJarsProviders( Iterable javaInfos) throws RuleErrorException, EvalException { ImmutableList.Builder builder = ImmutableList.builder(); @@ -172,49 +62,6 @@ private static ImmutableList collectJavaGenJarsProviders( return builder.build(); } - /** - * Creates action which creates archive with all source files inside. Takes all filer from - * sourceFiles collection and all files from every sourceJars. Name of Artifact generated based on - * outputJar. - * - * @param outputJar name of output Jar artifact. - * @param outputSourceJar name of output source Jar artifact, or {@code null}. If unset, defaults - * to base name of the output jar with the suffix {@code -src.jar}. - * @return generated artifact (can also be empty) - */ - Artifact packSourceFiles( - StarlarkActionFactory actions, - Artifact outputJar, - Artifact outputSourceJar, - List sourceFiles, - List sourceJars, - JavaToolchainProvider javaToolchain, - String execGroup) - throws EvalException { - if (outputJar == null && outputSourceJar == null) { - throw Starlark.errorf( - "pack_sources requires at least one of the parameters output_jar or output_source_jar"); - } - // If we only have one source jar, return it directly to avoid action creation - if (sourceFiles.isEmpty() && sourceJars.size() == 1 && outputSourceJar == null) { - return sourceJars.get(0); - } - ActionRegistry actionRegistry = actions.asActionRegistry(actions); - if (outputSourceJar == null) { - outputSourceJar = getDerivedSourceJar(actions.getActionConstructionContext(), outputJar); - } - SingleJarActionBuilder.createSourceJarAction( - actionRegistry, - actions.getActionConstructionContext(), - javaToolchain.getJavaSemantics(), - NestedSetBuilder.wrap(Order.STABLE_ORDER, sourceFiles), - NestedSetBuilder.wrap(Order.STABLE_ORDER, sourceJars), - outputSourceJar, - javaToolchain, - execGroup); - return outputSourceJar; - } - private JavaSourceJarsProvider createJavaSourceJarsProvider( Iterable sourceJars, Iterable transitiveDeps) { NestedSetBuilder transitiveSourceJars = NestedSetBuilder.stableOrder(); @@ -418,72 +265,6 @@ private static List tokenize(List input) throws EvalException { return output; } - public Artifact buildIjar( - StarlarkActionFactory actions, - Artifact inputJar, - @Nullable Artifact outputJar, - @Nullable Label targetLabel, - JavaToolchainProvider javaToolchain, - String execGroup) - throws EvalException { - Artifact interfaceJar; - if (outputJar != null) { - interfaceJar = outputJar; - } else { - String ijarBasename = FileSystemUtils.removeExtension(inputJar.getFilename()) + "-ijar.jar"; - interfaceJar = actions.declareFile(ijarBasename, inputJar); - } - FilesToRunProvider ijarTarget = javaToolchain.getIjar(); - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder().addExecPath(inputJar).addExecPath(interfaceJar); - if (targetLabel != null) { - commandLine.addLabel("--target_label", targetLabel); - } - SpawnAction.Builder actionBuilder = - new SpawnAction.Builder() - .addInput(inputJar) - .addOutput(interfaceJar) - .setExecutable(ijarTarget) - .setProgressMessage("Extracting interface for jar %s", inputJar.getFilename()) - .addCommandLine(commandLine.build()) - .useDefaultShellEnvironment() - .setMnemonic("JavaIjar") - .setExecGroup(execGroup); - actions.registerAction(actionBuilder.build(actions.getActionConstructionContext())); - return interfaceJar; - } - - public Artifact stampJar( - StarlarkActionFactory actions, - Artifact inputJar, - Label targetLabel, - JavaToolchainProvider javaToolchain, - String execGroup) - throws EvalException { - String basename = FileSystemUtils.removeExtension(inputJar.getFilename()) + "-stamped.jar"; - Artifact outputJar = actions.declareFile(basename, inputJar); - // ijar doubles as a stamping tool - FilesToRunProvider ijarTarget = javaToolchain.getIjar(); - CustomCommandLine.Builder commandLine = - CustomCommandLine.builder() - .addExecPath(inputJar) - .addExecPath(outputJar) - .add("--nostrip_jar") - .addLabel("--target_label", targetLabel); - SpawnAction.Builder actionBuilder = - new SpawnAction.Builder() - .addInput(inputJar) - .addOutput(outputJar) - .setExecutable(ijarTarget) - .setProgressMessage("Stamping target label into jar %s", inputJar.getFilename()) - .addCommandLine(commandLine.build()) - .useDefaultShellEnvironment() - .setMnemonic("JavaIjar") - .setExecGroup(execGroup); - actions.registerAction(actionBuilder.build(actions.getActionConstructionContext())); - return outputJar; - } - private static StrictDepsMode getStrictDepsMode(String strictDepsMode) { switch (strictDepsMode) { case "OFF": diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaModuleFlagsProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaModuleFlagsProvider.java index 66dbf52d910248..3867c64e30286f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaModuleFlagsProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaModuleFlagsProvider.java @@ -26,13 +26,16 @@ 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.AttributeMap; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.StructImpl; import com.google.devtools.build.lib.rules.java.JavaInfo.JavaInfoInternalProvider; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaModuleFlagsProviderApi; import java.util.Collection; import java.util.List; import java.util.stream.Stream; +import javax.annotation.Nullable; import net.starlark.java.eval.EvalException; +import net.starlark.java.eval.Starlark; /** * Provides information about {@code --add-exports=} and {@code --add-opens=} flags for Java @@ -113,12 +116,31 @@ public ImmutableList toFlags() { return toFlags(addExports().toList(), addOpens().toList()); } + /** + * Translates the {@code module_flags_info} from a {@link JavaInfo} to the native class. + * + * @param javaInfo a {@link JavaInfo} provider instance + * @return a {@link JavaModuleFlagsProvider} instance or {@code null} if {@code module_flags_info} + * is absent or {@code None} + * @throws EvalException if there are any errors accessing Starlark values + * @throws TypeException if any depset values are of an incompatible type + * @throws RuleErrorException if the {@code module_flags_info} is of an incompatible type + */ + @Nullable static JavaModuleFlagsProvider fromStarlarkJavaInfo(StructImpl javaInfo) - throws EvalException, TypeException { - StructImpl moduleFlagsInfo = javaInfo.getValue("module_flags_info", StructImpl.class); - return JavaModuleFlagsProvider.create( - moduleFlagsInfo.getValue("add_exports", Depset.class).toList(String.class), - moduleFlagsInfo.getValue("add_opens", Depset.class).toList(String.class), - Stream.empty()); + throws EvalException, TypeException, RuleErrorException { + Object value = javaInfo.getValue("module_flags_info"); + if (value == null || value == Starlark.NONE) { + return null; + } else if (value instanceof JavaModuleFlagsProvider) { + return (JavaModuleFlagsProvider) value; + } else if (value instanceof StructImpl) { + StructImpl moduleFlagsInfo = (StructImpl) value; + return JavaModuleFlagsProvider.create( + moduleFlagsInfo.getValue("add_exports", Depset.class).toList(String.class), + moduleFlagsInfo.getValue("add_opens", Depset.class).toList(String.class), + Stream.empty()); + } + throw new RuleErrorException("expected JavaModuleFlagsInfo, got: " + Starlark.type(value)); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfo.java index ba058ef2965356..02f0f3af6245bb 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPluginInfo.java @@ -34,7 +34,6 @@ import com.google.devtools.build.lib.starlarkbuildapi.java.JavaPluginInfoApi; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Sequence; import net.starlark.java.eval.Starlark; @@ -318,10 +317,23 @@ public JavaPluginInfo disableAnnotationProcessing() { plugins().disableAnnotationProcessing(), /* generatesApi= */ false, getJavaOutputs()); } - @Nullable + /** + * Translates the plugin information from a {@link JavaInfo} instance. + * + * @param javaInfo the {@link JavaInfo} instance + * @return a {@link JavaPluginInfo} instance + * @throws EvalException if there are any errors accessing Starlark values + * @throws RuleErrorException if the {@code plugins} or {@code api_generating_plugins} fields are + * of an incompatible type + */ static JavaPluginInfo fromStarlarkJavaInfo(StructImpl javaInfo) throws EvalException, RuleErrorException { - Info info = javaInfo.getValue("_plugin_info", Info.class); - return info == null ? null : JavaPluginInfo.PROVIDER.wrap(info); + JavaPluginData plugins = JavaPluginData.wrap(javaInfo.getValue("plugins")); + JavaPluginData apiGeneratingPlugins = + JavaPluginData.wrap(javaInfo.getValue("api_generating_plugins")); + if (plugins.isEmpty() && apiGeneratingPlugins.isEmpty()) { + return JavaPluginInfo.empty(); + } + return new AutoValue_JavaPluginInfo(ImmutableList.of(), plugins, apiGeneratingPlugins); } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java index 6a3e58cf6a9812..6c17609d844ca1 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuleOutputJarsProvider.java @@ -23,6 +23,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.StructImpl; import com.google.devtools.build.lib.rules.java.JavaInfo.JavaInfoInternalProvider; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; @@ -36,6 +37,7 @@ import javax.annotation.Nullable; import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Sequence; +import net.starlark.java.eval.Starlark; import net.starlark.java.eval.StarlarkList; /** Provides information about jar files produced by a Java rule. */ @@ -305,11 +307,27 @@ public JavaRuleOutputJarsProvider build() { } } - static JavaRuleOutputJarsProvider fromStarlarkJavaInfo(StructImpl javaInfo) throws EvalException { - Sequence outputs = javaInfo.getValue("java_outputs", StarlarkList.class); + /** + * Translates the {@code outputs} field of a {@link JavaInfo} instance into a native {@link + * JavaRuleOutputJarsProvider} instance. + * + * @param javaInfo the {@link JavaInfo} instance + * @return a {@link JavaRuleOutputJarsProvider} instance + * @throws EvalException if there are any errors accessing Starlark values + * @throws RuleErrorException if any of the {@code output} instances are of incompatible type + */ + static JavaRuleOutputJarsProvider fromStarlarkJavaInfo(StructImpl javaInfo) + throws EvalException, RuleErrorException { JavaRuleOutputJarsProvider.Builder builder = JavaRuleOutputJarsProvider.builder(); - for (StructImpl output : Sequence.cast(outputs, StructImpl.class, "outputs")) { - builder.addJavaOutput(JavaOutput.fromStarlarkJavaOutput(output)); + for (Object output : + Sequence.cast(javaInfo.getValue("java_outputs"), Object.class, "outputs")) { + if (output instanceof JavaOutput) { + builder.addJavaOutput((JavaOutput) output); + } else if (output instanceof StructImpl) { + builder.addJavaOutput(JavaOutput.fromStarlarkJavaOutput((StructImpl) output)); + } else { + throw new RuleErrorException("expected JavaOutput, got: " + Starlark.type(output)); + } } return builder.build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java index d9ecabeaefe2b2..60f4210433e318 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java @@ -25,7 +25,6 @@ import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.analysis.Runfiles; -import com.google.devtools.build.lib.analysis.Runfiles.Builder; 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.SpawnAction; @@ -37,15 +36,12 @@ import com.google.devtools.build.lib.packages.ImplicitOutputsFunction.SafeImplicitOutputsFunction; import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.Type; -import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration; -import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider; import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression; import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider.ClasspathType; import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel; import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider; import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant; import com.google.devtools.build.lib.util.FileType; -import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.List; import javax.annotation.Nullable; @@ -59,7 +55,6 @@ public interface JavaSemantics { SafeImplicitOutputsFunction JAVA_BINARY_SOURCE_JAR = fromTemplates("%{name}-src.jar"); SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_JAR = fromTemplates("%{name}_deploy.jar"); - SafeImplicitOutputsFunction JAVA_BINARY_MERGED_JAR = fromTemplates("%{name}_merged.jar"); SafeImplicitOutputsFunction JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR = fromTemplates("%{name}_deploy.jar.unstripped"); SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_MAP = fromTemplates("%{name}_proguard.map"); @@ -70,16 +65,10 @@ public interface JavaSemantics { SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_CONFIG = fromTemplates("%{name}_proguard.config"); SafeImplicitOutputsFunction JAVA_ONE_VERSION_ARTIFACT = fromTemplates("%{name}-one-version.txt"); - SafeImplicitOutputsFunction SHARED_ARCHIVE_ARTIFACT = fromTemplates("%{name}.jsa"); - - SafeImplicitOutputsFunction JAVA_COVERAGE_RUNTIME_CLASS_PATH_TXT = - fromTemplates("%{name}-runtime-classpath.txt"); SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_SOURCE_JAR = fromTemplates("%{name}_deploy-src.jar"); - SafeImplicitOutputsFunction JAVA_TEST_CLASSPATHS_FILE = fromTemplates("%{name}_classpaths_file"); - FileType JAVA_SOURCE = FileType.of(".java"); FileType JAR = FileType.of(".jar"); FileType PROPERTIES = FileType.of(".properties"); @@ -199,15 +188,6 @@ static LabelLateBoundDefault javaLauncherAttribute(Label defa void checkForProtoLibraryAndJavaProtoLibraryOnSameProto( RuleContext ruleContext, JavaCommon javaCommon); - /** Returns the main class of a Java binary. */ - String getMainClass(RuleContext ruleContext, ImmutableList srcsArtifacts); - - /** - * Returns the primary class for a Java binary - either the main class, or, in case of a test, the - * test class (not the test runner main class). - */ - String getPrimaryClass(RuleContext ruleContext, ImmutableList srcsArtifacts); - /** * Returns the resources contributed by a Java rule (usually the contents of the {@code resources} * attribute) @@ -317,11 +297,6 @@ static boolean isJavaBinaryOrJavaTest(RuleContext ruleContext) { || ruleContext.getRule().getRuleClass().equals("java_test"); } - /** Adds extra runfiles for a {@code java_binary} rule. */ - void addRunfilesForBinary( - RuleContext ruleContext, Artifact launcher, Runfiles.Builder runfilesBuilder) - throws RuleErrorException; - /** Adds extra runfiles for a {@code java_library} rule. */ void addRunfilesForLibrary(RuleContext ruleContext, Runfiles.Builder runfilesBuilder); @@ -349,44 +324,6 @@ void collectTargetsTreatedAsDeps( String addCoverageSupport(JavaCompilationHelper helper, Artifact executable) throws InterruptedException, RuleErrorException; - /** Return the JVM flags to be used in a Java binary. */ - Iterable getJvmFlags( - RuleContext ruleContext, ImmutableList srcsArtifacts, List userJvmFlags); - - /** Translates XMB messages to translations artifact suitable for Java targets. */ - ImmutableList translate(RuleContext ruleContext, List messages); - - /** - * Get the launcher artifact for a java binary, creating the necessary actions for it. - * - * @param ruleContext The rule context - * @param common The common helper class. - * @param deployArchiveBuilder the builder to construct the deploy archive action (mutable). - * @param unstrippedDeployArchiveBuilder the builder to construct the unstripped deploy archive - * action (mutable). - * @param runfilesBuilder the builder to construct the list of runfiles (mutable). - * @param jvmFlags the list of flags to pass to the JVM when running the Java binary (mutable). - * @param attributesBuilder the builder to construct the list of attributes of this target - * (mutable). - * @param ccToolchain to be used to build the launcher - * @param featureConfiguration to be used to configure the cc toolchain - * @return the launcher and unstripped launcher as an artifact pair. If shouldStrip is false, then - * they will be the same. - * @throws InterruptedException - */ - Pair getLauncher( - final RuleContext ruleContext, - final JavaCommon common, - DeployArchiveBuilder deployArchiveBuilder, - DeployArchiveBuilder unstrippedDeployArchiveBuilder, - Builder runfilesBuilder, - List jvmFlags, - JavaTargetAttributes.Builder attributesBuilder, - boolean shouldStrip, - CcToolchainProvider ccToolchain, - FeatureConfiguration featureConfiguration) - throws InterruptedException, RuleErrorException; - /** * Add a source artifact to a {@link JavaTargetAttributes.Builder}. It is called when a source * artifact is processed but is not matched by default patterns in the {@link @@ -407,9 +344,6 @@ Pair getLauncher( */ PathFragment getDefaultJavaResourcePath(PathFragment path); - /** @return a list of extra arguments to appends to the runfiles support. */ - List getExtraArguments(RuleContext ruleContext, ImmutableList sources); - /** * @return An artifact representing the protobuf-format version of the proguard mapping, or null * if the proguard version doesn't support this. diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java index 720d9e9eab7808..b83c34f294af16 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaStarlarkCommon.java @@ -14,7 +14,6 @@ package com.google.devtools.build.lib.rules.java; import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.devtools.build.lib.packages.ExecGroup.DEFAULT_EXEC_GROUP_NAME; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; @@ -44,7 +43,6 @@ import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; import com.google.devtools.build.lib.rules.cpp.CcInfo; import com.google.devtools.build.lib.rules.cpp.CppFileTypes; -import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.JavaOutput; import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.core.TransitiveInfoCollectionApi; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaCommonApi; @@ -52,7 +50,6 @@ import java.util.LinkedHashSet; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Module; import net.starlark.java.eval.Sequence; @@ -80,11 +77,6 @@ public JavaStarlarkCommon(JavaSemantics javaSemantics) { this.javaSemantics = javaSemantics; } - @Override - public Provider getJavaProvider() { - return JavaInfo.PROVIDER; - } - @Override public JavaInfo createJavaCompileAction( StarlarkRuleContext starlarkRuleContext, @@ -210,73 +202,6 @@ public JavaInfo createJavaCompileAction( thread); } - private String getExecGroup(boolean useAutoExecGroups) { - if (useAutoExecGroups) { - return javaSemantics.getJavaToolchainType(); - } else { - return DEFAULT_EXEC_GROUP_NAME; - } - } - - @Override - public Artifact runIjar( - StarlarkActionFactory actions, - Artifact jar, - Object output, - Object targetLabel, - JavaToolchainProvider javaToolchain, - StarlarkThread thread) - throws EvalException { - if (output != Starlark.NONE) { - checkPrivateAccess(thread); - } - return JavaInfoBuildHelper.getInstance() - .buildIjar( - actions, - jar, - output != Starlark.NONE ? (Artifact) output : null, - targetLabel != Starlark.NONE ? (Label) targetLabel : null, - javaToolchain, - getExecGroup(actions.getRuleContext().useAutoExecGroups())); - } - - @Override - public Artifact stampJar( - StarlarkActionFactory actions, - Artifact jar, - Label targetLabel, - JavaToolchainProvider javaToolchain) - throws EvalException { - return JavaInfoBuildHelper.getInstance() - .stampJar( - actions, - jar, - targetLabel, - javaToolchain, - getExecGroup(actions.getRuleContext().useAutoExecGroups())); - } - - @Override - public Artifact packSources( - StarlarkActionFactory actions, - Object outputJar, - Object outputSourceJar, - Sequence sourceFiles, // expected. - Sequence sourceJars, // expected. - JavaToolchainProvider javaToolchain, - Object hostJavabase) - throws EvalException { - return JavaInfoBuildHelper.getInstance() - .packSourceFiles( - actions, - outputJar instanceof Artifact ? (Artifact) outputJar : null, - outputSourceJar instanceof Artifact ? (Artifact) outputSourceJar : null, - Sequence.cast(sourceFiles, Artifact.class, "sources"), - Sequence.cast(sourceJars, Artifact.class, "source_jars"), - javaToolchain, - getExecGroup(actions.getRuleContext().useAutoExecGroups())); - } - @Override // TODO(b/78512644): migrate callers to passing explicit javacopts or using custom toolchains, and // delete @@ -311,11 +236,6 @@ public JavaInfo makeNonStrict(JavaInfo javaInfo) { .build(); } - @Override - public ProviderApi getJavaPluginProvider() { - return JavaPluginInfo.PROVIDER; - } - @Override public Provider getJavaToolchainProvider() { return JavaToolchainProvider.PROVIDER; @@ -326,28 +246,6 @@ public Provider getJavaRuntimeProvider() { return JavaRuntimeInfo.PROVIDER; } - @Override - public ProviderApi getMessageBundleInfo() { - // No implementation in Bazel. This method not callable in Starlark except through - // (discouraged) use of --experimental_google_legacy_api. - return null; - } - - @Override - public Info addConstraints(Info info, Sequence constraints) - throws EvalException, RuleErrorException { - // No implementation in Bazel. This method is not callable in Starlark except through - // (discouraged) use of --experimental_google_legacy_api. - return info; - } - - @Override - public Sequence getConstraints(Info info) throws RuleErrorException { - // No implementation in Bazel. This method not callable in Starlark except through - // (discouraged) use of --experimental_google_legacy_api. - return StarlarkList.empty(); - } - @Override public JavaInfo setAnnotationProcessing( Info info, @@ -401,49 +299,6 @@ protected static void checkPrivateAccess(StarlarkThread thread) throws EvalExcep } } - @Override - public JavaInfo toJavaBinaryInfo(JavaInfo javaInfo, StarlarkThread thread) throws EvalException { - checkPrivateAccess(thread); - JavaRuleOutputJarsProvider ruleOutputs = - JavaRuleOutputJarsProvider.builder() - .addJavaOutput( - javaInfo.getJavaOutputs().stream() - .map( - output -> - JavaOutput.create( - output.getClassJar(), - null, - null, - output.getGeneratedClassJar(), - output.getGeneratedSourceJar(), - output.getNativeHeadersJar(), - output.getManifestProto(), - output.getJdeps(), - output.getSourceJars())) - .collect(Collectors.toList())) - .build(); - JavaInfo.Builder builder = JavaInfo.Builder.create(); - if (javaInfo.getProvider(JavaCompilationInfoProvider.class) != null) { - builder.javaCompilationInfo(javaInfo.getCompilationInfoProvider()); - } else if (javaInfo.getProvider(JavaCompilationArgsProvider.class) != null) { - JavaCompilationArgsProvider compilationArgsProvider = - javaInfo.getProvider(JavaCompilationArgsProvider.class); - builder.javaCompilationInfo( - new JavaCompilationInfoProvider.Builder() - .setCompilationClasspath(compilationArgsProvider.getTransitiveCompileTimeJars()) - .setRuntimeClasspath(compilationArgsProvider.getRuntimeJars()) - .build()); - } - if (javaInfo.getProvider(JavaGenJarsProvider.class) != null) { - builder.javaGenJars(javaInfo.getGenJarsProvider()); - } - return builder - .javaCcInfo(javaInfo.getProvider(JavaCcInfoProvider.class)) - .javaSourceJars(javaInfo.getProvider(JavaSourceJarsProvider.class)) - .javaRuleOutputs(ruleOutputs) - .build(); - } - @Override public Sequence getBuildInfo( StarlarkRuleContext starlarkRuleContext, boolean isStampingEnabled, StarlarkThread thread) diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java index fedee3356aa4ef..bbf838f698b2a6 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaTargetAttributes.java @@ -284,15 +284,6 @@ public Builder addNativeLibrary(Artifact nativeLibrary) { return this; } - @CanIgnoreReturnValue - public Builder addNativeLibraries(Iterable nativeLibraries) { - Preconditions.checkArgument(!built); - for (Artifact nativeLibrary : nativeLibraries) { - addNativeLibrary(nativeLibrary); - } - return this; - } - @CanIgnoreReturnValue public Builder addMessages(Collection messages) { Preconditions.checkArgument(!built); diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java index c154139546b80f..870fc1c2340546 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java @@ -376,6 +376,7 @@ public Artifact getTimezoneData() { } /** Returns the ijar executable */ + @Override public FilesToRunProvider getIjar() { return ijar; } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/MessageBundleInfo.java b/src/main/java/com/google/devtools/build/lib/rules/java/MessageBundleInfo.java index 61c2e1ca083027..a98c86edc5ca6e 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/MessageBundleInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/MessageBundleInfo.java @@ -14,83 +14,61 @@ package com.google.devtools.build.lib.rules.java; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; -import com.google.devtools.build.lib.packages.BuiltinProvider; -import com.google.devtools.build.lib.packages.NativeInfo; -import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; -import com.google.devtools.build.lib.starlarkbuildapi.java.MessageBundleInfoApi; -import java.util.List; +import com.google.devtools.build.lib.packages.Info; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.packages.StarlarkInfo; +import com.google.devtools.build.lib.packages.StarlarkProviderWrapper; import javax.annotation.Nullable; -import net.starlark.java.annot.Param; -import net.starlark.java.annot.StarlarkBuiltin; -import net.starlark.java.annot.StarlarkMethod; import net.starlark.java.eval.EvalException; import net.starlark.java.eval.Sequence; -import net.starlark.java.eval.StarlarkList; -import net.starlark.java.eval.StarlarkThread; -import net.starlark.java.syntax.Location; /** Marks configured targets that are able to supply message bundles to their dependents. */ @Immutable -public final class MessageBundleInfo extends NativeInfo implements MessageBundleInfoApi { +public final class MessageBundleInfo { - public static final String STARLARK_NAME = "MessageBundleInfo"; + private static final String STARLARK_NAME = "MessageBundleInfo"; /** Provider singleton constant. */ - public static final BuiltinProvider PROVIDER = new Provider(); + private static final StarlarkProviderWrapper PROVIDER = new Provider(); /** Provider class for {@link MessageBundleInfo} objects. */ - @StarlarkBuiltin(name = "Provider", documented = false, doc = "") - public static class Provider extends BuiltinProvider implements ProviderApi { + private static class Provider extends StarlarkProviderWrapper { private Provider() { - super(STARLARK_NAME, MessageBundleInfo.class); + super( + Label.parseCanonicalUnchecked("@_builtins//:common/java/message_bundle_info.bzl"), + STARLARK_NAME); } - @StarlarkMethod( - name = "MessageBundleInfo", - doc = "The MessageBundleInfo constructor.", - documented = false, - parameters = { - @Param(name = "messages", positional = false, named = true), - }, - selfCall = true, - useStarlarkThread = true) - public MessageBundleInfo messageBundleInfo(Sequence messages, StarlarkThread thread) - throws EvalException { - List messagesList = Sequence.cast(messages, Artifact.class, "messages"); - return new MessageBundleInfo(ImmutableList.copyOf(messagesList), thread.getCallerLocation()); + @Override + public MessageBundleInfo wrap(Info value) throws RuleErrorException { + try { + return new MessageBundleInfo((StarlarkInfo) value); + } catch (EvalException e) { + throw new RuleErrorException(e); + } } } private final ImmutableList messages; - private MessageBundleInfo(ImmutableList messages, Location creationLocation) { - super(creationLocation); - this.messages = Preconditions.checkNotNull(messages); + private MessageBundleInfo(StarlarkInfo value) throws EvalException { + this.messages = + Sequence.cast(value.getValue("messages"), Artifact.class, "messages").getImmutableList(); } - @Override - public BuiltinProvider getProvider() { - return PROVIDER; - } - - @Override - public Sequence getMessageBundles() { - return StarlarkList.immutableCopyOf(getMessages()); - } - - public ImmutableList getMessages() { + private ImmutableList getMessages() { return messages; } @Nullable - public static ImmutableList getMessages(TransitiveInfoCollection info) { - MessageBundleInfo messageBundleInfo = - (MessageBundleInfo) info.get(MessageBundleInfo.PROVIDER.getKey()); + public static ImmutableList getMessages(TransitiveInfoCollection info) + throws RuleErrorException { + MessageBundleInfo messageBundleInfo = info.get(MessageBundleInfo.PROVIDER); if (messageBundleInfo != null) { return messageBundleInfo.getMessages(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/ResourceJarActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/ResourceJarActionBuilder.java index 61a7f4b274bc11..d13b52da2009a0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/ResourceJarActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/ResourceJarActionBuilder.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ParamFileInfo; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; @@ -29,7 +30,6 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.util.List; import java.util.Map; /** Builds the action to package the resources for a Java rule into a jar. */ @@ -43,7 +43,7 @@ public class ResourceJarActionBuilder { private Map resources = ImmutableMap.of(); private NestedSet resourceJars = NestedSetBuilder.emptySet(Order.STABLE_ORDER); private ImmutableList classpathResources = ImmutableList.of(); - private List messages = ImmutableList.of(); + private ImmutableList messages = ImmutableList.of(); private JavaToolchainProvider javaToolchain; private NestedSet additionalInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER); @@ -105,16 +105,7 @@ public void build(JavaSemantics semantics, RuleContext ruleContext, String execG if (!resourceJars.isEmpty()) { command.addExecPaths("--sources", resourceJars); } - if (!resources.isEmpty() || !messages.isEmpty()) { - command.add("--resources"); - for (Map.Entry resource : resources.entrySet()) { - addAsResourcePrefixedExecPath(resource.getKey(), resource.getValue(), command); - } - for (Artifact message : messages) { - addAsResourcePrefixedExecPath( - semantics.getDefaultJavaResourcePath(message.getRootRelativePath()), message, command); - } - } + addResources(command, semantics); if (!classpathResources.isEmpty()) { command.addExecPaths("--classpath_resources", classpathResources); } @@ -136,13 +127,46 @@ public void build(JavaSemantics semantics, RuleContext ruleContext, String execG .build(ruleContext)); } - private static void addAsResourcePrefixedExecPath( - PathFragment resourcePath, Artifact artifact, CustomCommandLine.Builder builder) { - PathFragment execPath = artifact.getExecPath(); - if (execPath.equals(resourcePath)) { - builder.addFormatted("%s", resourcePath); + private void addResources(CustomCommandLine.Builder command, JavaSemantics semantics) { + if (resources.isEmpty() && messages.isEmpty()) { + return; + } + + command.add("--resources"); + ImmutableList resourcesWithDefaultPath; + + // When all resources use the default path (common case), save memory by throwing away those + // path fragments. The artifacts can be lazily converted to default-prefixed strings. + if (resources.entrySet().stream() + .allMatch(e -> e.getKey().equals(defaultResourcePath(e.getValue(), semantics)))) { + resourcesWithDefaultPath = + ImmutableList.builderWithExpectedSize(resources.size() + messages.size()) + .addAll(resources.values()) + .addAll(messages) + .build(); } else { - builder.addFormatted("%s:%s", execPath, resourcePath); + command.addObject( + Lists.transform( + ImmutableList.copyOf(resources.entrySet()), + e -> resourcePrefixedExecPath(e.getKey(), e.getValue()))); + resourcesWithDefaultPath = messages; + } + + if (!resourcesWithDefaultPath.isEmpty()) { + command.addObject( + Lists.transform( + resourcesWithDefaultPath, + artifact -> + resourcePrefixedExecPath(defaultResourcePath(artifact, semantics), artifact))); } } + + private static PathFragment defaultResourcePath(Artifact artifact, JavaSemantics semantics) { + return semantics.getDefaultJavaResourcePath(artifact.getRootRelativePath()); + } + + private static String resourcePrefixedExecPath(PathFragment resourcePath, Artifact artifact) { + PathFragment execPath = artifact.getExecPath(); + return execPath.equals(resourcePath) ? execPath.getPathString() : execPath + ":" + resourcePath; + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/SingleJarActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/SingleJarActionBuilder.java index 04b4f104330d12..1b335cf4f5198d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/SingleJarActionBuilder.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/SingleJarActionBuilder.java @@ -29,8 +29,6 @@ import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorArg; import com.google.devtools.build.lib.analysis.actions.SpawnAction; 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.concurrent.ThreadSafety.Immutable; import java.util.function.Consumer; @@ -111,34 +109,6 @@ public static void createSourceJarAction( actionRegistry.registerAction(builder.build(actionConstructionContext)); } - /** - * Creates an Action that merges jars into a single archive. - * - * @param jars the jars to merge. - * @param output the output jar to create - */ - public static void createSingleJarAction( - RuleContext ruleContext, NestedSet jars, Artifact output) { - requireNonNull(ruleContext); - requireNonNull(jars); - requireNonNull(output); - SpawnAction.Builder builder = - new SpawnAction.Builder() - .setExecutable(JavaToolchainProvider.from(ruleContext).getSingleJar()) - .addOutput(output) - .addTransitiveInputs(jars) - .addCommandLine( - sourceJarCommandLine( - output, - /* semantics= */ null, - /* resources= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER), - jars), - ParamFileInfo.builder(ParameterFileType.SHELL_QUOTED).setUseAlways(true).build()) - .setProgressMessage("Building singlejar jar %{output}") - .setMnemonic("JavaSingleJar"); - ruleContext.registerAction(builder.build(ruleContext)); - } - private static CommandLine sourceJarCommandLine( Artifact outputJar, JavaSemantics semantics, diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java index fa0363bf4208e0..6576e2eca47d4a 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java @@ -622,10 +622,7 @@ private static void constructCommandLine( runtime.getRuleClassProvider().getSymlinkDefinitions(), requestOptions.getSymlinkPrefix(productName), productName, - env.getWorkspace(), - requestOptions.printWorkspaceInOutputPathsIfNeeded - ? env.getWorkingDirectory() - : env.getWorkspace()); + env.getWorkspace()); PathFragment prettyExecutablePath = prettyPrinter.getPrettyPath(executable.getPath().asFragment()); diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java index 43f006d9196458..cf772847db75fe 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java @@ -255,7 +255,6 @@ private static TestLogPathFormatter makeTestLogPathFormatter( runtime.getRuleClassProvider().getSymlinkDefinitions(), requestOptions.getSymlinkPrefix(productName), productName, - env.getWorkspace(), env.getWorkspace()); return path -> pathPrettyPrinter.getPrettyPath(path.asFragment()).getPathString(); } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionLookupValuesTraversal.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionLookupValuesTraversal.java index 7d61c7ccba37f5..046347399bd499 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionLookupValuesTraversal.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionLookupValuesTraversal.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos; import com.google.devtools.build.lib.concurrent.Sharder; import com.google.devtools.build.skyframe.SkyValue; +import java.util.Objects; /** Represents the traversal of the ActionLookupValues in a build. */ public class ActionLookupValuesTraversal { @@ -43,7 +44,7 @@ public class ActionLookupValuesTraversal { public ActionLookupValuesTraversal() {} - void accumulate(ActionLookupKeyOrProxy keyForDebugging, SkyValue value) { + void accumulate(ActionLookupKeyOrProxy key, SkyValue value) { boolean isConfiguredTarget = value instanceof ConfiguredTargetValue; boolean isActionLookupValue = value instanceof ActionLookupValue; if (!isConfiguredTarget && !isActionLookupValue) { @@ -52,7 +53,16 @@ void accumulate(ActionLookupKeyOrProxy keyForDebugging, SkyValue value) { String.format( "Should only be called with ConfiguredTargetValue or ActionLookupValue: %s %s" + " %s", - value.getClass(), keyForDebugging, value))); + value.getClass(), key, value))); + return; + } + if (isConfiguredTarget + && !Objects.equals( + key.getConfigurationKey(), + ((ConfiguredTargetValue) value).getConfiguredTarget().getConfigurationKey())) { + // The configuration of the key doesn't match the configuration of the value. This means that + // the ConfiguredTargetValue is delegated from a different key. This ConfiguredTargetValue + // will show up again under its own key. Avoids double counting by skipping accumulation. return; } configuredObjectCount++; @@ -72,8 +82,7 @@ void accumulate(ActionLookupKeyOrProxy keyForDebugging, SkyValue value) { if (!(value instanceof NonRuleConfiguredTargetValue)) { BugReport.sendBugReport( new IllegalStateException( - String.format( - "Unexpected value type: %s %s %s", value.getClass(), keyForDebugging, value))); + String.format("Unexpected value type: %s %s %s", value.getClass(), key, value))); return; } ConfiguredTarget configuredTarget = diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD index 0838022f2d0d18..c76d8274a798c9 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD @@ -236,6 +236,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration", "//src/main/java/com/google/devtools/build/lib/analysis:config/build_options", "//src/main/java/com/google/devtools/build/lib/analysis:config/config_conditions", + "//src/main/java/com/google/devtools/build/lib/analysis:config/configuration_value_event", "//src/main/java/com/google/devtools/build/lib/analysis:config/core_options", "//src/main/java/com/google/devtools/build/lib/analysis:config/execution_transition_factory", "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_factory", @@ -247,10 +248,8 @@ java_library( "//src/main/java/com/google/devtools/build/lib/analysis:config/toolchain_type_requirement", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/baseline_options_value", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/configuration_transition", - "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/null_transition", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/patch_transition", "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_collector", - "//src/main/java/com/google/devtools/build/lib/analysis:configurations_collector", "//src/main/java/com/google/devtools/build/lib/analysis:configured_object_value", "//src/main/java/com/google/devtools/build/lib/analysis:configured_target", "//src/main/java/com/google/devtools/build/lib/analysis:configured_target_value", diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java index d90d21a95fc3d2..55a3f0fe134d94 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationFunction.java @@ -25,6 +25,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.config.BuildOptions; +import com.google.devtools.build.lib.analysis.config.ConfigurationValueEvent; import com.google.devtools.build.lib.analysis.config.CoreOptions; import com.google.devtools.build.lib.analysis.config.FragmentFactory; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; @@ -105,15 +106,19 @@ public SkyValue compute(SkyKey skyKey, Environment env) } try { - return BuildConfigurationValue.create( - targetOptions, - RepositoryName.createUnvalidated(workspaceNameValue.getName()), - starlarkSemantics.getBool(BuildLanguageOptions.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT), - transitionDirectoryNameFragment, - // Arguments below this are server-global. - directories, - ruleClassProvider, - fragmentFactory); + var configurationValue = + BuildConfigurationValue.create( + targetOptions, + RepositoryName.createUnvalidated(workspaceNameValue.getName()), + starlarkSemantics.getBool( + BuildLanguageOptions.EXPERIMENTAL_SIBLING_REPOSITORY_LAYOUT), + transitionDirectoryNameFragment, + // Arguments below this are server-global. + directories, + ruleClassProvider, + fragmentFactory); + env.getListener().post(ConfigurationValueEvent.create(configurationValue)); + return configurationValue; } catch (InvalidConfigurationException e) { throw new BuildConfigurationFunctionException(e); } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java index 8fa7842a22039d..3cf6d615c8c17f 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java @@ -228,7 +228,6 @@ public SkyValue compute(SkyKey key, Environment env) throws ReportedException, UnreportedException, DependencyException, InterruptedException { State state = env.getState(() -> new State(storeTransitivePackages)); ConfiguredTargetKey configuredTargetKey = (ConfiguredTargetKey) key.argument(); - Preconditions.checkArgument(!configuredTargetKey.isProxy(), configuredTargetKey); SkyframeBuildView view = buildViewProvider.getSkyframeBuildView(); if (shouldUnblockCpuWorkWhenFetchingDeps) { @@ -249,6 +248,9 @@ public SkyValue compute(SkyKey key, Environment env) } catch (InconsistentNullConfigException e) { // TODO(b/267529852): see if we can remove this. It's not clear the conditions that trigger // InconsistentNullConfigException are even possible. + // + // TODO(b/261521010): propagate this exception once the parent side rule transition is + // deleted. The caller should handle it correctly. return new NonRuleConfiguredTargetValue( new EmptyConfiguredTarget(configuredTargetKey), computeDependenciesState.transitivePackages()); @@ -282,11 +284,14 @@ public SkyValue compute(SkyKey key, Environment env) // If this CT applied an incoming rule transition, log it. BuildConfigurationValue config = prereqs.getTargetAndConfiguration().getConfiguration(); - if (config != null && !config.getKey().equals(configuredTargetKey.getConfigurationKey())) { + // `toKey` here retrieves the original key if there's a proxy key due to a transition. + if (config != null + && !config.getKey().equals(configuredTargetKey.toKey().getConfigurationKey())) { env.getListener() .post( new ConfigRequestedEvent( - config, configuredTargetKey.getConfigurationKey().getOptionsChecksum())); + config, + configuredTargetKey.toKey().getConfigurationKey().getOptionsChecksum())); } // If one of our dependencies is platform-incompatible with this build, so are we. @@ -507,10 +512,6 @@ private void computeTargetAndConfiguration( storedEvents.handle(Event.error(e.getLocation(), e.getMessage())); } throw new ReportedException(e); - case INVALID_VISIBILITY_DEPENDENCY: - // Bubbles the error up to the parent ConfiguredTargetFunction where it will be reported - // with additional context. - throw new DependencyException(error.invalidVisibilityDependency()); case INCONSISTENT_NULL_CONFIG: throw error.inconsistentNullConfig(); } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java index e2282048cbbc6e..e9e28e3a7ad68e 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetKey.java @@ -14,13 +14,11 @@ package com.google.devtools.build.lib.skyframe; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.devtools.build.lib.util.HashCodes.hashObjects; import com.google.common.base.MoreObjects; import com.google.devtools.build.lib.actions.ActionLookupKey; -import com.google.devtools.build.lib.actions.ActionLookupKeyOrProxy; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.cmdline.Label; @@ -43,17 +41,9 @@ * dependency resolution and the rule analysis. * *

In practice, a ({@link Label} and post-transition {@link BuildConfigurationKey}) pair plus a - * possible execution platform override {@link Label} with special constraints. To elaborate, in - * order of highest to lowest potential for concern: + * possible execution platform override {@link Label} with special constraints described as follows. * - *

1. The {@link BuildConfigurationKey} must be post-transition and thus ready for immediate use - * in dependency resolution and analysis. In practice, this means that if the rule has an - * incoming-edge transition (cfg in {@link RuleClass}) or there are global trimming transitions, - * THOSE TRANSITIONS MUST ALREADY BE DONE before creating the key. Failure to do so will lead to - * build graphs with ConfiguredTarget that have seemingly impossible {@link BuildConfigurationValue} - * (due to the skipped transitions). - * - *

2. A build should not request keys with equal ({@link Label}, {@link BuildConfigurationValue}) + *

A build should not request keys with equal ({@link Label}, {@link BuildConfigurationValue}) * pairs but different execution platform override {@link Label} if the invoked rule will register * actions. (This is potentially OK if all outputs of all registered actions incorporate the * execution platform in their name unless the build also requests keys without an override that @@ -63,32 +53,40 @@ * *

Note that this key may be used to look up the generating action of an artifact. * - *

The {@link ConfiguredTargetKey} is not a {@link SkyKey} and must be cast to one using {@link - * ActionLookupKeyOrProxy#toKey}. - * *

TODO(blaze-configurability-team): Consider just using BuildOptions over a * BuildConfigurationKey. */ -public abstract class ConfiguredTargetKey implements ActionLookupKeyOrProxy { +public class ConfiguredTargetKey implements ActionLookupKey { /** * Cache so that the number of ConfiguredTargetKey instances is {@code O(configured targets)} and * not {@code O(edges between configured targets)}. */ - private static final SkyKey.SkyKeyInterner interner = SkyKey.newInterner(); + private static final SkyKey.SkyKeyInterner interner = SkyKey.newInterner(); + private final Label label; @Nullable private final BuildConfigurationKey configurationKey; private final transient int hashCode; - private ConfiguredTargetKey(@Nullable BuildConfigurationKey configurationKey, int hashCode) { + private ConfiguredTargetKey( + Label label, @Nullable BuildConfigurationKey configurationKey, int hashCode) { + this.label = label; this.configurationKey = configurationKey; this.hashCode = hashCode; } - public Builder toBuilder() { - return builder() - .setConfigurationKey(configurationKey) - .setLabel(getLabel()) - .setExecutionPlatformLabel(getExecutionPlatformLabel()); + @Override + public final SkyFunctionName functionName() { + return SkyFunctions.CONFIGURED_TARGET; + } + + @Override + public SkyKeyInterner getSkyKeyInterner() { + return interner; + } + + @Override + public Label getLabel() { + return label; } @Nullable @@ -97,22 +95,36 @@ public final BuildConfigurationKey getConfigurationKey() { return configurationKey; } - public abstract Label getExecutionPlatformLabel(); - @Override - public final int hashCode() { - return hashCode; + public final ConfiguredTargetKey toKey() { + return this; } - public boolean isProxy() { - return false; + @Nullable + public Label getExecutionPlatformLabel() { + return null; } - private static int computeHashCode( - Label label, - @Nullable BuildConfigurationKey configurationKey, - @Nullable Label executionPlatformLabel) { - return hashObjects(label, configurationKey, executionPlatformLabel); + /** + * True if the target's rule transition should be applied. + * + *

True by default but set false when a non-idempotent rule transition is detected. It prevents + * over-application of such transitions. + */ + public boolean shouldApplyRuleTransition() { + return true; + } + + public final String prettyPrint() { + if (getLabel() == null) { + return "null"; + } + return String.format("%s (%s)", getLabel(), formatConfigurationKey(configurationKey)); + } + + @Override + public final int hashCode() { + return hashCode; } @Override @@ -127,22 +139,12 @@ public final boolean equals(Object obj) { return hashCode == other.hashCode && getLabel().equals(other.getLabel()) && Objects.equals(configurationKey, other.configurationKey) - && Objects.equals(getExecutionPlatformLabel(), other.getExecutionPlatformLabel()); - } - - public String prettyPrint() { - if (getLabel() == null) { - return "null"; - } - return String.format("%s (%s)", getLabel(), formatConfigurationKey(configurationKey)); - } - - private static ConfiguredTargetKey intern(ConfiguredTargetKey key) { - return (ConfiguredTargetKey) interner.intern((SkyKey) key); + && Objects.equals(getExecutionPlatformLabel(), other.getExecutionPlatformLabel()) + && shouldApplyRuleTransition() == other.shouldApplyRuleTransition(); } @Override - public String toString() { + public final String toString() { // TODO(b/162809183): consider reverting to less verbose toString when bug is resolved. MoreObjects.ToStringHelper helper = MoreObjects.toStringHelper(this).add("label", getLabel()).add("config", configurationKey); @@ -152,47 +154,43 @@ public String toString() { return helper.toString(); } - private static final class RealConfiguredTargetKey extends ConfiguredTargetKey - implements ActionLookupKey { - private final Label label; - - private RealConfiguredTargetKey( - Label label, @Nullable BuildConfigurationKey configurationKey, int hashCode) { - super(configurationKey, hashCode); - this.label = label; - } - - static ConfiguredTargetKey create( - Label label, @Nullable BuildConfigurationKey configurationKey) { - int hashCode = computeHashCode(label, configurationKey, /* executionPlatformLabel= */ null); - return intern(new RealConfiguredTargetKey(label, configurationKey, hashCode)); - } - - @Override - public final SkyFunctionName functionName() { - return SkyFunctions.CONFIGURED_TARGET; - } - - @Override - public SkyKeyInterner getSkyKeyInterner() { - return interner; - } + /** + * Key indicating that no rule transition should be applied to the configuration. + * + *

NOTE: although it's true that no rule transition is applied when there is a null + * configuration, this key type is used to handle a special edge case described below. It should + * only be used with a non-null configuration. + * + *

When a non-noop rule transition occurs, it creates a new delegation {@link + * ConfiguredTargetKey} with the resulting configuration. This is so if different starting + * configurations result in the same configuration after transition, they converge on the same + * key-value entry in Skyframe. + * + *

This can be problematic when transitions are not idempotent because evaluation of the + * delegate repeats the transition, resulting in a another delegate. In cases of + * non-convergent transitions, this may lead to infinite expansion. + * + *

To ensure that transitions are effectively only applied once, prior to delegation, the + * {@link ConfiguredTargetFunction} applies the transition a second time to check it for + * idempotency. It sets {@link ConfiguredTargetKey#shouldApplyRuleTransition} false when it is not + * idempotent. + */ + private static final class ConfiguredTargetKeyWithFinalConfiguration extends ConfiguredTargetKey { + // This is implemented using subtypes instead of adding a boolean field to `ConfiguredTargetKey` + // to reduce memory cost. - @Override - public Label getLabel() { - return label; + private ConfiguredTargetKeyWithFinalConfiguration( + Label label, BuildConfigurationKey configurationKey, int hashCode) { + super(label, checkNotNull(configurationKey), hashCode); } - @Nullable @Override - public Label getExecutionPlatformLabel() { - return null; + public boolean shouldApplyRuleTransition() { + return false; } } - private static final class ToolchainDependencyConfiguredTargetKey extends ConfiguredTargetKey - implements ActionLookupKey { - private final Label label; + private static class ToolchainDependencyConfiguredTargetKey extends ConfiguredTargetKey { private final Label executionPlatformLabel; private ToolchainDependencyConfiguredTargetKey( @@ -200,119 +198,38 @@ private ToolchainDependencyConfiguredTargetKey( @Nullable BuildConfigurationKey configurationKey, int hashCode, Label executionPlatformLabel) { - super(configurationKey, hashCode); - this.label = label; + super(label, configurationKey, hashCode); this.executionPlatformLabel = checkNotNull(executionPlatformLabel); } - private static ConfiguredTargetKey create( - Label label, - @Nullable BuildConfigurationKey configurationKey, - Label executionPlatformLabel) { - int hashCode = computeHashCode(label, configurationKey, executionPlatformLabel); - return intern( - new ToolchainDependencyConfiguredTargetKey( - label, configurationKey, hashCode, executionPlatformLabel)); - } - - @Override - public SkyFunctionName functionName() { - return SkyFunctions.CONFIGURED_TARGET; - } - - @Override - public Label getLabel() { - return label; - } - @Override public Label getExecutionPlatformLabel() { return executionPlatformLabel; } - - @Override - public SkyKeyInterner getSkyKeyInterner() { - return interner; - } } - // This class implements SkyKey only so that it can share the interner. It should never be used as - // a SkyKey. - private static final class ProxyConfiguredTargetKey extends ConfiguredTargetKey - implements SkyKey { - private final ConfiguredTargetKey delegate; - - private static ConfiguredTargetKey create( - ConfiguredTargetKey delegate, @Nullable BuildConfigurationKey configurationKey) { - int hashCode = - computeHashCode( - delegate.getLabel(), configurationKey, delegate.getExecutionPlatformLabel()); - return intern(new ProxyConfiguredTargetKey(delegate, configurationKey, hashCode)); - } - - private ProxyConfiguredTargetKey( - ConfiguredTargetKey delegate, - @Nullable BuildConfigurationKey configurationKey, - int hashCode) { - super(configurationKey, hashCode); - checkArgument( - !delegate.isProxy(), "Proxy keys must not be nested: %s %s", delegate, configurationKey); - this.delegate = delegate; - } - - @Override - public SkyFunctionName functionName() { - // ProxyConfiguredTargetKey is never used directly by Skyframe. It must always be cast using - // toKey. - throw new UnsupportedOperationException(); - } - - @Override - public Label getLabel() { - return delegate.getLabel(); - } - - @Override - @Nullable - public Label getExecutionPlatformLabel() { - return delegate.getExecutionPlatformLabel(); - } - - @Override - public ActionLookupKey toKey() { - return (ActionLookupKey) delegate; - } - - @Override - public boolean isProxy() { - return true; - } - - @Override - public Builder toBuilder() { - return new Builder().setDelegate(delegate).setConfigurationKey(getConfigurationKey()); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("delegate", delegate) - .add("config", getConfigurationKey()) - .toString(); + private static final class ToolchainDependencyConfiguredTargetKeyWithFinalConfiguration + extends ToolchainDependencyConfiguredTargetKey { + private ToolchainDependencyConfiguredTargetKeyWithFinalConfiguration( + Label label, + BuildConfigurationKey configurationKey, + int hashCode, + Label executionPlatformLabel) { + super(label, checkNotNull(configurationKey), hashCode, executionPlatformLabel); } @Override - public String prettyPrint() { - return super.prettyPrint() - + " virtual(" - + formatConfigurationKey(getConfigurationKey()) - + ")"; + public boolean shouldApplyRuleTransition() { + return false; } + } - @Override - public SkyKeyInterner getSkyKeyInterner() { - return interner; - } + public Builder toBuilder() { + return builder() + .setConfigurationKey(configurationKey) + .setLabel(getLabel()) + .setExecutionPlatformLabel(getExecutionPlatformLabel()) + .setShouldApplyRuleTransition(shouldApplyRuleTransition()); } /** Returns a new {@link Builder} to create instances of {@link ConfiguredTargetKey}. */ @@ -335,7 +252,7 @@ public static final class Builder { private Label label = null; private BuildConfigurationKey configurationKey = null; private Label executionPlatformLabel = null; - private ConfiguredTargetKey delegate; + private boolean shouldApplyRuleTransition = true; private Builder() {} @@ -369,31 +286,45 @@ public Builder setExecutionPlatformLabel(@Nullable Label executionPlatformLabel) return this; } - /** - * If set, creates a {@link ProxyConfiguredTargetKey}. - * - *

It's invalid to set a label or execution platform label if this is set. Those will be - * defined by the corresponding values of {@code delegate}. - */ @CanIgnoreReturnValue - public Builder setDelegate(ConfiguredTargetKey delegate) { - this.delegate = delegate; + public Builder setShouldApplyRuleTransition(boolean shouldApplyRuleTransition) { + this.shouldApplyRuleTransition = shouldApplyRuleTransition; return this; } /** Builds a new {@link ConfiguredTargetKey} based on the supplied data. */ public ConfiguredTargetKey build() { - if (this.delegate != null) { - checkArgument(label == null); - checkArgument(executionPlatformLabel == null); - return ProxyConfiguredTargetKey.create(delegate, configurationKey); - } - if (this.executionPlatformLabel != null) { - return ToolchainDependencyConfiguredTargetKey.create( - label, configurationKey, executionPlatformLabel); + int hashCode = + computeHashCode( + label, configurationKey, executionPlatformLabel, shouldApplyRuleTransition); + ConfiguredTargetKey newKey; + if (executionPlatformLabel == null) { + newKey = + shouldApplyRuleTransition + ? new ConfiguredTargetKey(label, configurationKey, hashCode) + : new ConfiguredTargetKeyWithFinalConfiguration(label, configurationKey, hashCode); + } else { + newKey = + shouldApplyRuleTransition + ? new ToolchainDependencyConfiguredTargetKey( + label, configurationKey, hashCode, executionPlatformLabel) + : new ToolchainDependencyConfiguredTargetKeyWithFinalConfiguration( + label, configurationKey, hashCode, executionPlatformLabel); } - return RealConfiguredTargetKey.create(label, configurationKey); + return interner.intern(newKey); + } + } + + private static int computeHashCode( + Label label, + @Nullable BuildConfigurationKey configurationKey, + @Nullable Label executionPlatformLabel, + boolean shouldApplyRuleTransition) { + int hashCode = hashObjects(label, configurationKey, executionPlatformLabel); + if (!shouldApplyRuleTransition) { + hashCode = ~hashCode; } + return hashCode; } private static String formatConfigurationKey(@Nullable BuildConfigurationKey key) { @@ -403,13 +334,7 @@ private static String formatConfigurationKey(@Nullable BuildConfigurationKey key return key.getOptions().checksum(); } - /** - * Codec for all {@link ConfiguredTargetKey} subtypes. - * - *

By design, {@link ProxyConfiguredTargetKey} serializes as a key without delegation. Upon - * deserialization, if the key is locally delegated, it becomes delegating again due to interning. - * If not, it deserializes to the appropriate non-delegating key. - */ + /** Codec for all {@link ConfiguredTargetKey} subtypes. */ @Keep private static class ConfiguredTargetKeyCodec implements ObjectCodec { @Override @@ -424,6 +349,7 @@ public void serialize( context.serialize(key.getLabel(), codedOut); context.serialize(key.getConfigurationKey(), codedOut); context.serialize(key.getExecutionPlatformLabel(), codedOut); + context.serialize(key.shouldApplyRuleTransition(), codedOut); } @Override @@ -433,6 +359,7 @@ public ConfiguredTargetKey deserialize(DeserializationContext context, CodedInpu .setLabel(context.deserialize(codedIn)) .setConfigurationKey(context.deserialize(codedIn)) .setExecutionPlatformLabel(context.deserialize(codedIn)) + .setShouldApplyRuleTransition(context.deserialize(codedIn)) .build(); } } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/FileSystemValueCheckerInferringAncestors.java b/src/main/java/com/google/devtools/build/lib/skyframe/FileSystemValueCheckerInferringAncestors.java index 14f3571ff33788..eba5c66214fd5e 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/FileSystemValueCheckerInferringAncestors.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/FileSystemValueCheckerInferringAncestors.java @@ -279,8 +279,11 @@ && listingHasEntriesOutsideOf(path, maybeDeletedChildren))) { if (oldFsv.getType().isDirectory()) { return false; } - // TODO(b/287632270) - handle this scenario - valuesToInject.put(key, Delta.justNew(FileStateValue.DIRECTORY_FILE_STATE_NODE)); + Version directoryFileStateNodeMtsv = + skyValueDirtinessChecker.getMaxTransitiveSourceVersionForNewValue( + key, FileStateValue.DIRECTORY_FILE_STATE_NODE); + valuesToInject.put( + key, Delta.justNew(FileStateValue.DIRECTORY_FILE_STATE_NODE, directoryFileStateNodeMtsv)); parentListingKey(path).ifPresent(valuesToInvalidate::add); return true; } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageErrorMessageValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageErrorMessageValue.java index fa545974dd1299..54c68a635525b2 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageErrorMessageValue.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageErrorMessageValue.java @@ -56,7 +56,7 @@ public enum Result { * If {@code getResult().equals(NO_SUCH_PACKAGE_EXCEPTION)}, returns the error message from the * {@link com.google.devtools.build.lib.packages.NoSuchPackageException} encountered. */ - abstract String getNoSuchPackageExceptionMessage(); + public abstract String getNoSuchPackageExceptionMessage(); static PackageErrorMessageValue ofPackageWithNoErrors() { return NO_ERROR_VALUE; @@ -109,7 +109,7 @@ public Result getResult() { } @Override - String getNoSuchPackageExceptionMessage() { + public String getNoSuchPackageExceptionMessage() { throw new IllegalStateException(); } }; @@ -123,7 +123,7 @@ public Result getResult() { } @Override - String getNoSuchPackageExceptionMessage() { + public String getNoSuchPackageExceptionMessage() { throw new IllegalStateException(); } }; @@ -141,7 +141,7 @@ public Result getResult() { } @Override - String getNoSuchPackageExceptionMessage() { + public String getNoSuchPackageExceptionMessage() { return errorMessage; } diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java index bdf21b7fa4ba42..a78cd7a9db7160 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java @@ -511,7 +511,11 @@ public void dumpSkyframeStateInParallel( if (skyValue instanceof RuleConfiguredTargetValue) { tasks.add( () -> { - actionGraphDump.dumpConfiguredTarget((RuleConfiguredTargetValue) skyValue); + var configuredTarget = (RuleConfiguredTargetValue) skyValue; + // Only dumps the value for non-delegating keys. + if (configuredTarget.getConfiguredTarget().getKeyOrProxy().equals(key)) { + actionGraphDump.dumpConfiguredTarget(configuredTarget); + } return null; }); } else if (key.functionName().equals(SkyFunctions.ASPECT)) { @@ -570,7 +574,11 @@ public void dumpSkyframeState(ActionGraphDump actionGraphDump) } try { if (skyValue instanceof RuleConfiguredTargetValue) { - actionGraphDump.dumpConfiguredTarget((RuleConfiguredTargetValue) skyValue); + var configuredTarget = (RuleConfiguredTargetValue) skyValue; + // Only dumps the value for non-delegating keys. + if (configuredTarget.getConfiguredTarget().getKeyOrProxy().equals(key)) { + actionGraphDump.dumpConfiguredTarget(configuredTarget); + } } else if (key.functionName().equals(SkyFunctions.ASPECT)) { AspectValue aspectValue = (AspectValue) skyValue; AspectKey aspectKey = (AspectKey) key; diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java index f15cd79c454fa5..9920a282261a5f 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java @@ -308,10 +308,7 @@ void prepareForExecution( freeDiscoveredInputsAfterExecution = !trackIncrementalState && options.getOptions(CoreOptions.class).actionListeners.isEmpty(); - this.cacheHitSemaphore = - options.getOptions(CoreOptions.class).throttleActionCacheCheck - ? new Semaphore(ResourceUsage.getAvailableProcessors()) - : null; + this.cacheHitSemaphore = new Semaphore(ResourceUsage.getAvailableProcessors()); this.actionExecutionSemaphore = buildRequestOptions.useSemaphoreForJobs ? new Semaphore(buildRequestOptions.jobs) : null; diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java index 2e4ba6b327bf56..b6a5fdbbf12afa 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java @@ -78,17 +78,14 @@ import com.google.devtools.build.lib.analysis.AnalysisOptions; import com.google.devtools.build.lib.analysis.AspectConfiguredEvent; import com.google.devtools.build.lib.analysis.AspectValue; -import com.google.devtools.build.lib.analysis.BaseDependencySpecification; import com.google.devtools.build.lib.analysis.BlazeDirectories; -import com.google.devtools.build.lib.analysis.ConfigurationsCollector; -import com.google.devtools.build.lib.analysis.ConfigurationsResult; import com.google.devtools.build.lib.analysis.ConfiguredAspect; import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.ConfiguredTargetValue; import com.google.devtools.build.lib.analysis.Dependency; import com.google.devtools.build.lib.analysis.DependencyKind; -import com.google.devtools.build.lib.analysis.InvalidVisibilityDependencyException; +import com.google.devtools.build.lib.analysis.InconsistentNullConfigException; import com.google.devtools.build.lib.analysis.PlatformOptions; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; import com.google.devtools.build.lib.analysis.TargetConfiguredEvent; @@ -99,20 +96,14 @@ import com.google.devtools.build.lib.analysis.WorkspaceStatusAction.Factory; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.config.BuildOptions; -import com.google.devtools.build.lib.analysis.config.ConfigurationResolver; import com.google.devtools.build.lib.analysis.config.CoreOptions; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; -import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition; -import com.google.devtools.build.lib.analysis.config.transitions.NullTransition; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; import com.google.devtools.build.lib.analysis.constraints.RuleContextConstraintSemantics; import com.google.devtools.build.lib.analysis.producers.ConfiguredTargetAndDataProducer; import com.google.devtools.build.lib.analysis.producers.DependencyError; import com.google.devtools.build.lib.analysis.producers.DependencyMapProducer; import com.google.devtools.build.lib.analysis.producers.PrerequisiteParameters; -import com.google.devtools.build.lib.analysis.starlark.StarlarkBuildSettingsDetailsValue; -import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition; -import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException; import com.google.devtools.build.lib.bazel.bzlmod.BzlmodRepoRuleValue; import com.google.devtools.build.lib.bazel.repository.RepositoryOptions; import com.google.devtools.build.lib.bugreport.BugReport; @@ -132,7 +123,6 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadCompatible; import com.google.devtools.build.lib.events.ErrorSensingEventHandler; -import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.events.Reporter; @@ -293,7 +283,7 @@ * additional artifacts (workspace status and build info artifacts) into SkyFunctions for use during * the build. */ -public abstract class SkyframeExecutor implements WalkableGraphFactory, ConfigurationsCollector { +public abstract class SkyframeExecutor implements WalkableGraphFactory { private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); protected MemoizingEvaluator memoizingEvaluator; @@ -1722,11 +1712,8 @@ public void deleteActionsIfRemoteOptionsChanged(OptionsProvider options) lastRemoteCacheEnabled != null && lastRemoteCacheEnabled && !remoteCacheEnabled; } lastRemoteCacheEnabled = remoteCacheEnabled; - - RemoteOutputsMode remoteOutputsMode = + lastRemoteOutputsMode = remoteOptions != null ? remoteOptions.remoteOutputsMode : RemoteOutputsMode.ALL; - needsDeletion |= lastRemoteOutputsMode != null && lastRemoteOutputsMode != remoteOutputsMode; - this.lastRemoteOutputsMode = remoteOutputsMode; if (needsDeletion) { memoizingEvaluator.delete(k -> SkyFunctions.ACTION_EXECUTION.equals(k.functionName())); @@ -1809,126 +1796,6 @@ public Map getConfigurations( Functions.identity(), key -> (BuildConfigurationValue) evaluationResult.get(key))); } - /** - * Retrieves the configurations needed for the given deps. Unconditionally includes all fragments. - * - *

Skips targets with loading phase errors. - */ - // TODO(ulfjack): Remove this legacy method after switching to the Skyframe-based implementation. - @Override - public ConfigurationsResult getConfigurations( - ExtendedEventHandler eventHandler, - BuildOptions fromOptions, - Iterable keys) - throws InvalidConfigurationException, InterruptedException { - ConfigurationsResult.Builder builder = ConfigurationsResult.newBuilder(); - - PlatformMappingValue platformMappingValue = getPlatformMappingValue(eventHandler, fromOptions); - - // Now get the configurations. - List configSkyKeys = new ArrayList<>(); - for (BaseDependencySpecification key : keys) { - ConfigurationTransition transition = key.getTransition(); - if (transition == NullTransition.INSTANCE) { - continue; - } - Collection toOptions; - try { - StarlarkBuildSettingsDetailsValue details = - getStarlarkBuildSettingsDetailsValue(eventHandler, transition); - toOptions = - ConfigurationResolver.applyTransitionWithoutSkyframe( - fromOptions, - transition, - details, - eventHandler, - skyframeBuildView.getStarlarkTransitionCache()) - .values(); - } catch (TransitionException e) { - eventHandler.handle(Event.error(e.getMessage())); - builder.setHasError(); - continue; - } - for (BuildOptions toOption : toOptions) { - configSkyKeys.add(toConfigurationKey(platformMappingValue, toOption)); - } - } - - EvaluationResult configsResult = - evaluateSkyKeys(eventHandler, configSkyKeys, /*keepGoing=*/ true); - - for (BaseDependencySpecification key : keys) { - if (key.getTransition() == NullTransition.INSTANCE) { - builder.put(key, null); - continue; - } - Collection toOptions; - try { - StarlarkBuildSettingsDetailsValue details = - getStarlarkBuildSettingsDetailsValue(eventHandler, key.getTransition()); - toOptions = - ConfigurationResolver.applyTransitionWithoutSkyframe( - fromOptions, - key.getTransition(), - details, - eventHandler, - skyframeBuildView.getStarlarkTransitionCache()) - .values(); - } catch (TransitionException e) { - eventHandler.handle(Event.error(e.getMessage())); - builder.setHasError(); - continue; - } - - for (BuildOptions toOption : toOptions) { - BuildConfigurationKey configKey = toConfigurationKey(platformMappingValue, toOption); - BuildConfigurationValue configValue = - (BuildConfigurationValue) configsResult.get(configKey); - if (configValue != null) { - builder.put(key, configValue); - } else if (configsResult.errorMap().containsKey(configKey)) { - ErrorInfo configError = configsResult.getError(configKey); - if (configError.getException() instanceof InvalidConfigurationException) { - // Wrap underlying exception to make it clearer to developers which line of code - // actually threw exception. - InvalidConfigurationException underlying = - (InvalidConfigurationException) configError.getException(); - throw new InvalidConfigurationException(underlying.getDetailedExitCode(), underlying); - } - } - } - } - return builder.build(); - } - - /** Must be in sync with {@link ConfigurationResolver#getStarlarkBuildSettingsDetailsValue}. */ - private StarlarkBuildSettingsDetailsValue getStarlarkBuildSettingsDetailsValue( - ExtendedEventHandler eventHandler, ConfigurationTransition transition) - throws TransitionException { - ImmutableSet

" - + "JavaInfo#source_jar

." - + "At least one of parameters output_jar or output_source_jar is required.", - parameters = { - @Param(name = "actions", named = true, doc = "ctx.actions"), - @Param( - name = "output_jar", - positional = false, - named = true, - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - defaultValue = "None", - doc = - "Deprecated: The output jar of the rule. Used to name the resulting source jar. " - + "The parameter sets output_source_jar parameter to `{output_jar}-src.jar`." - + "Use output_source_jar parameter directly instead.", - disableWithFlag = BuildLanguageOptions.INCOMPATIBLE_JAVA_COMMON_PARAMETERS, - valueWhenDisabled = "None"), - @Param( - name = "output_source_jar", - positional = false, - named = true, - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - defaultValue = "None", - doc = "The output source jar."), - @Param( - name = "sources", - positional = false, - named = true, - allowedTypes = {@ParamType(type = Sequence.class, generic1 = FileApi.class)}, - defaultValue = "[]", - doc = "A list of Java source files to be packed into the source jar."), - @Param( - name = "source_jars", - positional = false, - named = true, - allowedTypes = {@ParamType(type = Sequence.class, generic1 = FileApi.class)}, - defaultValue = "[]", - doc = "A list of source jars to be packed into the source jar."), - @Param( - name = "java_toolchain", - positional = false, - named = true, - doc = "A JavaToolchainInfo to used to find the ijar tool."), - @Param( - name = "host_javabase", - positional = false, - named = true, - doc = - "Deprecated: You can drop this parameter (host_javabase is provided with " - + "java_toolchain)", - defaultValue = "None", - disableWithFlag = BuildLanguageOptions.INCOMPATIBLE_JAVA_COMMON_PARAMETERS, - valueWhenDisabled = "None"), - }, - allowReturnNones = true) - @Nullable - FileApi packSources( - StarlarkActionFactoryT actions, - Object outputJar, - Object outputSourceJar, - Sequence sourceFiles, // expected. - Sequence sourceJars, // expected. - JavaToolchainT javaToolchain, - Object hostJavabase) - throws EvalException; - @StarlarkMethod( name = "default_javac_opts", // This function is experimental for now. @@ -538,15 +370,6 @@ JavaInfoT mergeJavaProviders( }) JavaInfoT makeNonStrict(JavaInfoT javaInfo); - @StarlarkMethod( - name = "JavaPluginInfo", - doc = - "The key used to retrieve the provider that contains information about the Java " - + "plugins. The same value is accessible as JavaPluginInfo.
" - + "Prefer using JavaPluginInfo in new code.", - structField = true) - ProviderApi getJavaPluginProvider(); - @StarlarkMethod( name = "JavaToolchainInfo", doc = @@ -563,47 +386,6 @@ JavaInfoT mergeJavaProviders( structField = true) ProviderApi getJavaRuntimeProvider(); - @StarlarkMethod( - name = "MessageBundleInfo", - doc = "The provider used to supply message bundles for translation", - structField = true, - enableOnlyWithFlag = BuildLanguageOptions.EXPERIMENTAL_GOOGLE_LEGACY_API) - ProviderApi getMessageBundleInfo(); - - @StarlarkMethod( - name = "add_constraints", - doc = "Returns a copy of the given JavaInfo with the given constraints added.", - parameters = { - @Param( - name = "java_info", - positional = true, - named = false, - doc = "The JavaInfo to enhance."), - @Param( - name = "constraints", - allowedTypes = {@ParamType(type = Sequence.class, generic1 = String.class)}, - named = true, - positional = false, - defaultValue = "[]", - doc = "Constraints to add") - }, - enableOnlyWithFlag = BuildLanguageOptions.EXPERIMENTAL_GOOGLE_LEGACY_API) - Info addConstraints(Info javaInfo, Sequence constraints /* expected. */) - throws EvalException, RuleErrorException; - - @StarlarkMethod( - name = "get_constraints", - doc = "Returns a set of constraints added.", - parameters = { - @Param( - name = "java_info", - positional = true, - named = false, - doc = "The JavaInfo to get constraints from."), - }, - enableOnlyWithFlag = BuildLanguageOptions.EXPERIMENTAL_GOOGLE_LEGACY_API) - Sequence getConstraints(Info javaInfo) throws RuleErrorException; - @StarlarkMethod( name = "set_annotation_processing", doc = "Returns a copy of the given JavaInfo with the given annotation_processing info.", @@ -699,19 +481,6 @@ JavaInfoT setAnnotationProcessing( String getTargetKind(Object target, boolean dereferenceAliases, StarlarkThread thread) throws EvalException; - @StarlarkMethod( - name = "to_java_binary_info", - doc = "Returns a copy of the given JavaInfo with minimal info returned by a java_binary", - parameters = { - @Param( - name = "java_info", - positional = true, - named = false, - doc = "The JavaInfo to enhance."), - }, - useStarlarkThread = true) - JavaInfoT toJavaBinaryInfo(JavaInfoT javaInfo, StarlarkThread thread) throws EvalException; - @StarlarkMethod( name = "get_build_info", documented = false, diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaInfoApi.java index 0ceb21f2604687..fa693977e7b46d 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaInfoApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaInfoApi.java @@ -14,9 +14,7 @@ package com.google.devtools.build.lib.starlarkbuildapi.java; -import com.google.devtools.build.docgen.annot.StarlarkConstructor; import com.google.devtools.build.lib.collect.nestedset.Depset; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; import com.google.devtools.build.lib.starlarkbuildapi.FileApi; import com.google.devtools.build.lib.starlarkbuildapi.core.ProviderApi; @@ -24,13 +22,8 @@ import com.google.devtools.build.lib.starlarkbuildapi.cpp.CcInfoApi; import com.google.devtools.build.lib.starlarkbuildapi.java.JavaPluginInfoApi.JavaPluginDataApi; import javax.annotation.Nullable; -import net.starlark.java.annot.Param; -import net.starlark.java.annot.ParamType; import net.starlark.java.annot.StarlarkMethod; -import net.starlark.java.eval.EvalException; -import net.starlark.java.eval.NoneType; import net.starlark.java.eval.Sequence; -import net.starlark.java.eval.StarlarkThread; /** Info object encapsulating all information by java rules. */ public interface JavaInfoApi< @@ -39,6 +32,12 @@ public interface JavaInfoApi< JavaPluginDataT extends JavaPluginDataApi> extends StructApi, JavaPluginInfoApi { + @StarlarkMethod( + name = "_neverlink", + doc = "Whether this library should be used only for compilation and not at runtime.", + structField = true) + boolean isNeverlink(); + @StarlarkMethod( name = "transitive_runtime_jars", doc = "Returns a transitive set of Jars required on the target's runtime classpath.", @@ -178,183 +177,11 @@ public interface JavaInfoApi< @StarlarkMethod(name = "_compile_time_java_dependencies", documented = false, structField = true) Depset getCompileTimeJavaDependencies(); + @StarlarkMethod(name = "_constraints", documented = false, structField = true) + Sequence getJavaConstraintsStarlark(); + /** Provider class for {@link JavaInfoApi} objects. */ interface JavaInfoProviderApi extends ProviderApi { - @StarlarkMethod( - name = "JavaInfo", - doc = "The JavaInfo constructor.", - parameters = { - @Param( - name = "output_jar", - named = true, - doc = - "The jar that was created as a result of a compilation " - + "(e.g. javac, scalac, etc)."), - @Param( - name = "compile_jar", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - doc = - "A jar that is added as the compile-time dependency in lieu of " - + "output_jar. Typically this is the ijar produced by " - + "" - + "run_ijar. " - + "If you cannot use ijar, consider instead using the output of " - + "" - + "stamp_ijar. If you do not wish to use either, " - + "you can simply pass output_jar. " - + "There are a couple of special cases when this parameter may be set to " - + "None, for example adding a jar with resources or when used in" - + " a terminal rule like java_binary."), - @Param( - name = "source_jar", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "The source jar that was used to create the output jar. Use pack_sources" - + " to produce this source jar."), - @Param( - name = "compile_jdeps", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "jdeps information about compile time dependencies to be consumed by" - + " JavaCompileAction. This should be a binary proto encoded using the" - + " deps.proto protobuf included with Bazel. If available this file is" - + " typically produced by a header compiler."), - @Param( - name = "generated_class_jar", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "A jar file containing class files compiled from sources generated during" - + " annotation processing."), - @Param( - name = "generated_source_jar", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = "The source jar that was created as a result of annotation processing."), - @Param( - name = "native_headers_jar", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "A jar containing CC header files supporting native method implementation" - + " (typically output of javac -h)."), - @Param( - name = "manifest_proto", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "Manifest information for the rule output (if available). This should be a" - + " binary proto encoded using the manifest.proto protobuf included with" - + " Bazel. IDEs and other tools can use this information for more efficient" - + " processing."), - @Param( - name = "neverlink", - named = true, - defaultValue = "False", - doc = "If true only use this library for compilation and not at runtime."), - @Param( - name = "deps", - allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)}, - named = true, - defaultValue = "[]", - doc = "Compile time dependencies that were used to create the output jar."), - @Param( - name = "runtime_deps", - allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)}, - named = true, - defaultValue = "[]", - doc = "Runtime dependencies that are needed for this library."), - @Param( - name = "exports", - allowedTypes = {@ParamType(type = Sequence.class, generic1 = JavaInfoApi.class)}, - named = true, - defaultValue = "[]", - doc = - "Libraries to make available for users of this library. See also " - + "java_library.exports."), - @Param( - name = "exported_plugins", - named = true, - allowedTypes = { - @ParamType(type = Sequence.class, generic1 = JavaPluginInfoApi.class) - }, - defaultValue = "[]", - doc = "A list of exported plugins. Optional."), - @Param( - name = "jdeps", - allowedTypes = { - @ParamType(type = FileApi.class), - @ParamType(type = NoneType.class), - }, - named = true, - defaultValue = "None", - doc = - "jdeps information for the rule output (if available). This should be a binary" - + " proto encoded using the deps.proto protobuf included with Bazel. If" - + " available this file is typically produced by a compiler. IDEs and other" - + " tools can use this information for more efficient processing."), - @Param( - name = "native_libraries", - allowedTypes = {@ParamType(type = Sequence.class, generic1 = CcInfoApi.class)}, - named = true, - defaultValue = "[]", - doc = "CC native library dependencies that are needed for this library."), - }, - selfCall = true, - useStarlarkThread = true) - @StarlarkConstructor - JavaInfoApi javaInfo( - FileApi outputJarApi, - Object compileJarApi, - Object sourceJarApi, - Object compileJdepsApi, - Object generatedClassJarApi, - Object generatedSourceJarApi, - Object nativeHeadersJarApi, - Object manifestProtoApi, - Boolean neverlink, - Sequence deps, - Sequence runtimeDeps, - Sequence exports, - Sequence exportedPlugins, - Object jdepsApi, - Sequence nativeLibraries, - StarlarkThread thread) - throws EvalException, RuleErrorException; } } diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java index 11cc3ec2e36766..8c11040504f53c 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaToolchainStarlarkApiProviderApi.java @@ -84,6 +84,12 @@ public interface JavaToolchainStarlarkApiProviderApi extends StructApi { structField = true) Depset getStarlarkJvmOptions(); + @StarlarkMethod( + name = "ijar", + doc = "A FilesToRunProvider representing the ijar executable.", + structField = true) + FilesToRunProviderApi getIjar(); + @StarlarkMethod( name = "jacocorunner", doc = "The jacocorunner used by the toolchain.", diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/MessageBundleInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/MessageBundleInfoApi.java deleted file mode 100644 index ab4c476e9d60a6..00000000000000 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/MessageBundleInfoApi.java +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2018 The Bazel Authors. 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.starlarkbuildapi.java; - -import com.google.devtools.build.lib.starlarkbuildapi.FileApi; -import net.starlark.java.annot.StarlarkMethod; -import net.starlark.java.eval.Sequence; -import net.starlark.java.eval.StarlarkValue; - -/** Info object encapsulating message bundles in java rules. */ -public interface MessageBundleInfoApi extends StarlarkValue { - - @StarlarkMethod(name = "messages", structField = true, doc = "Sequence of message bundles") - Sequence getMessageBundles(); -} diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/test/CoverageCommonApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/test/CoverageCommonApi.java index 30a47151a598ca..bdf1f789386aa3 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/test/CoverageCommonApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/test/CoverageCommonApi.java @@ -99,9 +99,11 @@ public interface CoverageCommonApi< defaultValue = "None"), @Param( name = "metadata_files", + doc = + "Additional files required to generate coverage LCOV files after code execution." + + " e.g. .gcno files for C++.", named = true, positional = false, - documented = false, defaultValue = "[]", allowedTypes = { @ParamType(type = Sequence.class, generic1 = FileApi.class), diff --git a/src/main/java/com/google/devtools/build/lib/vfs/BUILD b/src/main/java/com/google/devtools/build/lib/vfs/BUILD index 22dd4272cafd36..f80997f0305041 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/BUILD +++ b/src/main/java/com/google/devtools/build/lib/vfs/BUILD @@ -66,7 +66,6 @@ java_library( ":pathfragment", "//src/main/java/com/google/devtools/build/lib/clock", "//src/main/java/com/google/devtools/build/lib/concurrent", - "//src/main/java/com/google/devtools/build/lib/jni", "//src/main/java/com/google/devtools/build/lib/io:file_symlink_exception", "//src/main/java/com/google/devtools/build/lib/profiler", "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec", @@ -78,7 +77,6 @@ java_library( "//third_party:guava", "//third_party:jsr305", "//third_party/protobuf:protobuf_java", - "@maven//:com_google_errorprone_error_prone_annotations", ], ) diff --git a/src/main/java/com/google/devtools/build/lib/vfs/bazel/Blake3HashFunction.java b/src/main/java/com/google/devtools/build/lib/vfs/bazel/Blake3HashFunction.java index 28d2b10ccbf438..e0d310757b937d 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/bazel/Blake3HashFunction.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/bazel/Blake3HashFunction.java @@ -7,11 +7,9 @@ import com.google.common.hash.HashCode; import com.google.common.hash.HashFunction; import com.google.common.hash.Hasher; -import com.google.errorprone.annotations.Immutable; import java.nio.ByteBuffer; import java.nio.charset.Charset; -@Immutable public final class Blake3HashFunction implements HashFunction { public int bits() { return 256; diff --git a/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java b/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java index dbb96c833c95f9..35158766aece1d 100644 --- a/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java +++ b/src/main/java/com/google/devtools/build/lib/worker/WorkerOptions.java @@ -94,7 +94,6 @@ public String getTypeDescription() { @Option( name = "worker_max_multiplex_instances", oldName = "experimental_worker_max_multiplex_instances", - oldNameWarning = false, converter = MultiResourceConverter.class, defaultValue = "null", documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY, @@ -151,7 +150,6 @@ public String getTypeDescription() { @Option( name = "worker_multiplex", oldName = "experimental_worker_multiplex", - oldNameWarning = false, defaultValue = "true", documentationCategory = OptionDocumentationCategory.EXECUTION_STRATEGY, effectTags = {OptionEffectTag.EXECUTION, OptionEffectTag.HOST_MACHINE_RESOURCE_OPTIMIZATIONS}, diff --git a/src/main/java/com/google/devtools/build/skyframe/BUILD b/src/main/java/com/google/devtools/build/skyframe/BUILD index 139223edf23e88..d9c920b6d48b6a 100644 --- a/src/main/java/com/google/devtools/build/skyframe/BUILD +++ b/src/main/java/com/google/devtools/build/skyframe/BUILD @@ -17,7 +17,6 @@ SKYFRAME_OBJECT_SRCS = [ "SkyFunctionName.java", "SkyKey.java", "SkyValue.java", - "UsePooledLabelInterningFlag.java", "Version.java", ] diff --git a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java index 2645ae1fe0822f..e1ddd3bacd922f 100644 --- a/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java +++ b/src/main/java/com/google/devtools/build/skyframe/InMemoryGraphImpl.java @@ -80,9 +80,7 @@ private InMemoryGraphImpl(int initialCapacity, boolean usePooledInterning) { this.usePooledInterning = usePooledInterning; if (usePooledInterning) { SkyKeyInterner.setGlobalPool(new SkyKeyPool()); - if (UsePooledLabelInterningFlag.usePooledLabelInterningFlag()) { - LabelInterner.setGlobalPool(new LabelPool()); - } + LabelInterner.setGlobalPool(new LabelPool()); } } @@ -127,9 +125,6 @@ private void weakInternPackageTargetsLabels(@Nullable PackageValue packageValue) return; } LabelInterner interner = Label.getLabelInterner(); - if (interner == null) { - return; - } ImmutableSortedMap targets = packageValue.getPackage().getTargets(); targets.values().forEach(t -> interner.weakIntern(t.getLabel())); @@ -257,9 +252,7 @@ public void cleanupInterningPool() { e -> { weakInternSkyKey(e.getKey()); - if (!UsePooledLabelInterningFlag.usePooledLabelInterningFlag() - || !e.isDone() - || !e.getKey().functionName().equals(SkyFunctions.PACKAGE)) { + if (!e.isDone() || !e.getKey().functionName().equals(SkyFunctions.PACKAGE)) { return; } diff --git a/src/main/java/com/google/devtools/build/skyframe/UsePooledLabelInterningFlag.java b/src/main/java/com/google/devtools/build/skyframe/UsePooledLabelInterningFlag.java deleted file mode 100644 index 124c66c9542a82..00000000000000 --- a/src/main/java/com/google/devtools/build/skyframe/UsePooledLabelInterningFlag.java +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2023 The Bazel Authors. 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.skyframe; - -import com.google.devtools.build.lib.util.TestType; -import java.util.Objects; - -/** - * A startup flag to decide whether some {@link com.google.devtools.build.lib.cmdline.Label}s will - * use {@link com.google.devtools.build.lib.cmdline.LabelInterner} backed by {@link - * com.google.devtools.build.lib.concurrent.PooledInterner} or just the regular bazel weak interner. - * - *

When this flag is true, {@code LabelInterner} will be applied for all {@code Label}s so that - * they are able to switch between interning the instances between the regular bazel weak interner - * and the static global pool. - * - *

Applying {@code LabelInterner} can reduce memory overhead of having duplicate {@code Label} - * instances in both weak interner and {@link InMemoryGraphImpl}. - */ -// TODO(b/250641010): This flag is temporary to facilitate a controlled rollout. So it should be -// removed after the new pooled interning for `Label` instances is fully released and stable. -public final class UsePooledLabelInterningFlag { - - private static final boolean USE_POOLED_LABEL_INTERNER = - Objects.equals(System.getProperty("BAZEL_USE_POOLED_LABEL_INTERNER"), "1") - || TestType.isInTest(); - - public static boolean usePooledLabelInterningFlag() { - return USE_POOLED_LABEL_INTERNER; - } - - private UsePooledLabelInterningFlag() {} -} diff --git a/src/main/native/blake3_jni.cc b/src/main/native/blake3_jni.cc index 555ad53f56050b..600915de62a952 100644 --- a/src/main/native/blake3_jni.cc +++ b/src/main/native/blake3_jni.cc @@ -16,7 +16,7 @@ #include #include -#include "external/blake3/c/blake3.h" +#include "c/blake3.h" namespace blaze_jni { diff --git a/src/main/protobuf/analysis_v2.proto b/src/main/protobuf/analysis_v2.proto index d3ae80b04f19dc..cfe4d76797baca 100644 --- a/src/main/protobuf/analysis_v2.proto +++ b/src/main/protobuf/analysis_v2.proto @@ -116,6 +116,10 @@ message Action { // The contents of the file for the actions.write() action // (guarded by the --include_file_write_contents flag). string file_contents = 17; + + // The target of the symlink created by UnresolvedSymlink actions. + // For regular Symlink actions, the target is represented as an input. + string unresolved_symlink_target = 18; } // Represents a single target (without configuration information) that is diff --git a/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary_deploy_jar.bzl b/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary_deploy_jar.bzl index bed4a2de7a38db..204de369a57a93 100644 --- a/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary_deploy_jar.bzl +++ b/src/main/starlark/builtins_bzl/bazel/java/bazel_java_binary_deploy_jar.bzl @@ -20,7 +20,7 @@ the generating actions, so that the runfiles symlink tree is staged for the depl load(":common/java/java_binary_deploy_jar.bzl", "create_deploy_archives", "make_deploy_jars_rule") load(":common/java/java_binary.bzl", "InternalDeployJarInfo") -load(":common/java/java_common.bzl", "get_build_info") +load(":common/java/java_common_internal_for_builtins.bzl", "get_build_info") def _stamping_enabled(ctx, stamp): if ctx.configuration.is_tool_configuration(): diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_common.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_common.bzl index b2375707d18443..2291c46fffb36e 100644 --- a/src/main/starlark/builtins_bzl/common/cc/cc_common.bzl +++ b/src/main/starlark/builtins_bzl/common/cc/cc_common.bzl @@ -589,13 +589,13 @@ def _register_linkstamp_compile_action( actions, cc_toolchain, feature_configuration, - grep_includes, source_file, output_file, compilation_inputs, inputs_for_validation, label_replacement, - output_replacement): + output_replacement, + grep_includes = None): cc_common_internal.check_private_api(allowlist = _PRIVATE_STARLARKIFICATION_ALLOWLIST) return cc_common_internal.register_linkstamp_compile_action( actions = actions, @@ -786,13 +786,13 @@ def _create_compile_action( actions, cc_toolchain, feature_configuration, - grep_includes, source_file, output_file, variables, action_name, compilation_context, additional_inputs = None, + grep_includes = None, additional_outputs = []): cc_common_internal.check_private_api(allowlist = _CREATE_COMPILE_ACTION_API_ALLOWLISTED_PACKAGES) return cc_common_internal.create_compile_action( diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl index 094eca5acb0e84..cde737f8a9a88c 100644 --- a/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl +++ b/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl @@ -908,16 +908,19 @@ def _expand_single_make_variable(ctx, token, additional_make_variable_substituti def _expand_make_variables_for_copts(ctx, tokenization, unexpanded_tokens, additional_make_variable_substitutions): tokens = [] + targets = [] + for additional_compiler_input in getattr(ctx.attr, "additional_compiler_inputs", []): + targets.append(additional_compiler_input) for token in unexpanded_tokens: if tokenization: - expanded_token = _expand(ctx, token, additional_make_variable_substitutions) + expanded_token = _expand(ctx, token, additional_make_variable_substitutions, targets = targets) _tokenize(tokens, expanded_token) else: exp = _expand_single_make_variable(ctx, token, additional_make_variable_substitutions) if exp != None: _tokenize(tokens, exp) else: - tokens.append(_expand(ctx, token, additional_make_variable_substitutions)) + tokens.append(_expand(ctx, token, additional_make_variable_substitutions, targets = targets)) return tokens def _get_copts(ctx, feature_configuration, additional_make_variable_substitutions): diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_library.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_library.bzl index 581237a257ab14..5e1e2e185cb49c 100755 --- a/src/main/starlark/builtins_bzl/common/cc/cc_library.bzl +++ b/src/main/starlark/builtins_bzl/common/cc/cc_library.bzl @@ -73,6 +73,7 @@ def _cc_library_impl(ctx): textual_hdrs = ctx.files.textual_hdrs, include_prefix = ctx.attr.include_prefix, strip_include_prefix = ctx.attr.strip_include_prefix, + additional_inputs = ctx.files.additional_compiler_inputs, ) precompiled_objects = cc_common.create_compilation_outputs( @@ -592,6 +593,10 @@ attrs = { "win_def_file": attr.label(allow_single_file = [".def"]), # buildifier: disable=attr-license "licenses": attr.license() if hasattr(attr, "license") else attr.string_list(), + "additional_compiler_inputs": attr.label_list( + allow_files = True, + flags = ["ORDER_INDEPENDENT", "DIRECT_COMPILE_TIME_INPUT"], + ), "_stl": semantics.get_stl(), "_grep_includes": attr.label( allow_files = True, diff --git a/src/main/starlark/builtins_bzl/common/java/basic_java_library.bzl b/src/main/starlark/builtins_bzl/common/java/basic_java_library.bzl index d1c6c781a80a45..bb6d9c4c2d8056 100644 --- a/src/main/starlark/builtins_bzl/common/java/basic_java_library.bzl +++ b/src/main/starlark/builtins_bzl/common/java/basic_java_library.bzl @@ -24,7 +24,8 @@ load(":common/java/proguard_validation.bzl", "validate_proguard_specs") load(":common/cc/cc_info.bzl", "CcInfo") load(":common/java/java_info.bzl", "JavaInfo") load(":common/java/java_plugin_info.bzl", "JavaPluginInfo") -load(":common/java/java_common.bzl", "java_common", "target_kind") +load(":common/java/java_common.bzl", "java_common") +load(":common/java/java_common_internal_for_builtins.bzl", "target_kind") coverage_common = _builtins.toplevel.coverage_common diff --git a/src/main/starlark/builtins_bzl/common/java/compile_action.bzl b/src/main/starlark/builtins_bzl/common/java/compile_action.bzl index 0e4e9a36d533b7..fdc29b5f6aa5d8 100644 --- a/src/main/starlark/builtins_bzl/common/java/compile_action.bzl +++ b/src/main/starlark/builtins_bzl/common/java/compile_action.bzl @@ -17,7 +17,7 @@ Java compile action """ load(":common/java/java_semantics.bzl", "semantics") -load(":common/java/java_common.bzl", "java_common") +load(":common/java/java_common_internal_for_builtins.bzl", _compile_private_for_builtins = "compile") def _filter_strict_deps(mode): return "error" if mode in ["strict", "default"] else mode @@ -130,8 +130,10 @@ def compile_action( or resources present, whereas runfiles in this case are empty. """ - java_info = java_common.compile( + java_info = _compile_private_for_builtins( ctx, + output = output_class_jar, + java_toolchain = semantics.find_java_toolchain(ctx), source_files = source_files, source_jars = source_jars, resources = resources, @@ -145,8 +147,6 @@ def compile_action( exported_plugins = exported_plugins, javac_opts = [ctx.expand_location(opt) for opt in javacopts], neverlink = neverlink, - java_toolchain = semantics.find_java_toolchain(ctx), - output = output_class_jar, output_source_jar = output_source_jar, strict_deps = _filter_strict_deps(strict_deps), enable_compile_jar_action = enable_compile_jar_action, diff --git a/src/main/starlark/builtins_bzl/common/java/java_binary.bzl b/src/main/starlark/builtins_bzl/common/java/java_binary.bzl index 8e3e924b293dc0..1d7d4f97a39c67 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_binary.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_binary.bzl @@ -22,14 +22,13 @@ load(":common/cc/semantics.bzl", cc_semantics = "semantics") load(":common/proto/proto_info.bzl", "ProtoInfo") load(":common/cc/cc_info.bzl", "CcInfo") load(":common/paths.bzl", "paths") -load(":common/java/java_info.bzl", "JavaInfo") +load(":common/java/java_info.bzl", "JavaInfo", "to_java_binary_info") load(":common/java/java_plugin_info.bzl", "JavaPluginInfo") +load(":common/java/java_common.bzl", "java_common") load( - ":common/java/java_common.bzl", + ":common/java/java_common_internal_for_builtins.bzl", "collect_native_deps_dirs", "get_runtime_classpath_for_archive", - "java_common", - "to_java_binary_info", ) CcLauncherInfo = _builtins.internal.cc_internal.launcher_provider @@ -341,10 +340,10 @@ def _create_shared_archive(ctx, java_attrs): jsa = ctx.actions.declare_file("%s.jsa" % ctx.label.name) merged = ctx.actions.declare_file(jsa.dirname + "/" + helper.strip_extension(jsa) + "-merged.jar") helper.create_single_jar( - ctx, - merged, - java_attrs.runtime_jars, - java_attrs.runtime_classpath_for_archive, + ctx.actions, + toolchain = semantics.find_java_toolchain(ctx), + output = merged, + sources = depset(transitive = [java_attrs.runtime_jars, java_attrs.runtime_classpath_for_archive]), ) args = ctx.actions.args() @@ -418,9 +417,10 @@ def _create_one_version_check(ctx, inputs): def _create_deploy_sources_jar(ctx, sources): helper.create_single_jar( - ctx, - ctx.outputs.deploysrcjar, - sources, + ctx.actions, + toolchain = semantics.find_java_toolchain(ctx), + output = ctx.outputs.deploysrcjar, + sources = sources, ) def _filter_validation_output_group(ctx, output_group): diff --git a/src/main/starlark/builtins_bzl/common/java/java_common.bzl b/src/main/starlark/builtins_bzl/common/java/java_common.bzl index 6c8ae716aca504..e8d8dc962450bc 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_common.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_common.bzl @@ -14,71 +14,260 @@ """ Utilities for Java compilation support in Starlark. """ +load( + ":common/java/java_info.bzl", + "JavaInfo", + _java_info_add_constraints = "add_constraints", +) +load(":common/java/message_bundle_info.bzl", "MessageBundleInfo") +load(":common/java/java_common_internal_for_builtins.bzl", "compile", "merge", "run_ijar") +load(":common/java/java_plugin_info.bzl", "JavaPluginInfo") +load(":common/java/java_semantics.bzl", "semantics") +load(":common/paths.bzl", "paths") +load(":common/java/java_helper.bzl", "helper") + _java_common_internal = _builtins.internal.java_common_internal_do_not_use -def target_kind(target, dereference_aliases = False): - """ Get the rule class string for a target +def _compile( + ctx, + output, + java_toolchain, + source_jars = [], + source_files = [], + output_source_jar = None, + javac_opts = [], + deps = [], + runtime_deps = [], + exports = [], + plugins = [], + exported_plugins = [], + native_libraries = [], + annotation_processor_additional_inputs = [], + annotation_processor_additional_outputs = [], + strict_deps = "ERROR", + bootclasspath = None, + sourcepath = [], + resources = [], + neverlink = False, + enable_annotation_processing = True, + add_exports = [], + add_opens = []): + return compile( + ctx, + output, + java_toolchain, + source_jars = source_jars, + source_files = source_files, + output_source_jar = output_source_jar, + javac_opts = javac_opts, + deps = deps, + runtime_deps = runtime_deps, + exports = exports, + plugins = plugins, + exported_plugins = exported_plugins, + native_libraries = native_libraries, + annotation_processor_additional_inputs = annotation_processor_additional_inputs, + annotation_processor_additional_outputs = annotation_processor_additional_outputs, + strict_deps = strict_deps, + bootclasspath = bootclasspath, + sourcepath = sourcepath, + resources = resources, + neverlink = neverlink, + enable_annotation_processing = enable_annotation_processing, + add_exports = add_exports, + add_opens = add_opens, + ) + +def _run_ijar(actions, jar, java_toolchain, target_label = None): + return run_ijar( + actions = actions, + jar = jar, + java_toolchain = java_toolchain, + target_label = target_label, + ) + +def _stamp_jar(actions, jar, java_toolchain, target_label): + """Stamps a jar with a target label for add_dep support. + + The return value is typically passed to `JavaInfo.compile_jar`. Prefer to use `run_ijar` when + possible. + + Args: + actions: (actions) ctx.actions + jar: (File) The jar to run stamp_jar on. + java_toolchain: (JavaToolchainInfo) The toolchain to used to find the stamp_jar tool. + target_label: (Label) A target label to stamp the jar with. Used for `add_dep` support. + Typically, you would pass `ctx.label` to stamp the jar with the current rule's label. + + Returns: + (File) The output artifact + + """ + output = actions.declare_file(paths.replace_extension(jar.basename, "-stamped.jar"), sibling = jar) + args = actions.args() + args.add(jar) + args.add(output) + args.add("--nostrip_jar") + args.add("--target_label", target_label) + actions.run( + mnemonic = "JavaIjar", + inputs = [jar], + outputs = [output], + executable = java_toolchain.ijar, # ijar doubles as a stamping tool + arguments = [args], + progress_message = "Stamping target label into jar %{input}", + toolchain = semantics.JAVA_TOOLCHAIN_TYPE, + use_default_shell_env = True, + ) + return output + +def _pack_sources( + actions, + java_toolchain, + output_source_jar, + sources = [], + source_jars = []): + """Packs sources and source jars into a single source jar file. + + The return value is typically passed to `JavaInfo.source_jar`. Args: - target: (Target) - dereference_aliases: (bool) resolve the actual target rule class if an - alias + actions: (actions) ctx.actions + java_toolchain: (JavaToolchainInfo) The toolchain used to find the ijar tool. + output_source_jar: (File) The output source jar. + sources: ([File]) A list of Java source files to be packed into the source jar. + source_jars: ([File]) A list of source jars to be packed into the source jar. Returns: - (str) The rule class string of the target + (File) The output artifact """ - return _java_common_internal.target_kind( - target, - dereference_aliases = dereference_aliases, + return helper.create_single_jar( + actions, + toolchain = java_toolchain, + output = output_source_jar, + sources = depset(source_jars), + resources = depset(sources), + progress_message = "Building source jar %{output}", + mnemonic = "JavaSourceJar", ) -def to_java_binary_info(java_info): - """ Get a copy of the given JavaInfo with minimal info returned by a java_binary +def _default_javac_opts(java_toolchain): + """Experimental! Get default javacopts from a java toolchain + + Args: + java_toolchain: (JavaToolchainInfo) the toolchain from which to get the javac options. + + Returns: + ([str]) A list of javac options + """ + return _java_common_internal.default_javac_opts(java_toolchain = java_toolchain) + +def _merge(providers): + return merge(providers) + +def _make_non_strict(java_info): + """Returns a new JavaInfo instance whose direct-jars part is the union of both the direct and indirect jars of the given Java provider. Args: - java_info: (JavaInfo) A JavaInfo provider instance + java_info: (JavaInfo) The java info to make non-strict. Returns: - (JavaInfo) A JavaInfo instance representing a java_binary target + (JavaInfo) """ - return _java_common_internal.to_java_binary_info(java_info) + return _java_common_internal.make_non_strict(java_info) -def get_build_info(ctx, is_stamping_enabled): - """ Get the artifacts representing the workspace status for this build +def _get_message_bundle_info(): + return None if semantics.IS_BAZEL else MessageBundleInfo + +def _add_constraints(java_info, constraints = []): + """Returns a copy of the given JavaInfo with the given constraints added. Args: - ctx: (RuleContext) The rule context - is_stamping_enabled: (bool) If stamping is enabled + java_info: (JavaInfo) The JavaInfo to enhance + constraints: ([str]) Constraints to add - Returns - ([File]) The build info artifacts + Returns: + (JavaInfo) """ - return _java_common_internal.get_build_info(ctx, is_stamping_enabled) + if semantics.IS_BAZEL: + return java_info -def collect_native_deps_dirs(deps): - """ Collect the set of root-relative paths containing native libraries + return _java_info_add_constraints(java_info, constraints = constraints) + +def _get_constraints(java_info): + """Returns a set of constraints added. Args: - deps: [Target] list of targets + java_info: (JavaInfo) The JavaInfo to get constraints from. Returns: - ([String]) A set of root-relative paths as a list + ([str]) The constraints set on the supplied JavaInfo """ - return _java_common_internal.collect_native_deps_dirs(deps) + return [] if semantics.IS_BAZEL else java_info._constraints -def get_runtime_classpath_for_archive(jars, excluded_jars): - """ Filters a classpath to remove certain entries +def _set_annotation_processing( + java_info, + enabled = False, + processor_classnames = [], + processor_classpath = None, + class_jar = None, + source_jar = None): + """Returns a copy of the given JavaInfo with the given annotation_processing info. - Args - jars: (depset[File]) The classpath to filter - excluded_jars: (depset[File]) The files to remove + Args: + java_info: (JavaInfo) The JavaInfo to enhance. + enabled: (bool) Whether the rule uses annotation processing. + processor_classnames: ([str]) Class names of annotation processors applied. + processor_classpath: (depset[File]) Class names of annotation processors applied. + class_jar: (File) Optional. Jar that is the result of annotation processing. + source_jar: (File) Optional. Source archive resulting from annotation processing. Returns: - (depset[File]) The filtered classpath + (JavaInfo) """ - return _java_common_internal.get_runtime_classpath_for_archive( - jars, - excluded_jars, + return _java_common_internal.set_annotation_processing( + java_info, + enabled = enabled, + processor_classnames = processor_classnames, + processor_classpath = processor_classpath, + class_jar = class_jar, + source_jar = source_jar, ) -java_common = _java_common_internal +def _java_toolchain_label(java_toolchain): + """Returns the toolchain's label. + + Args: + java_toolchain: (JavaToolchainInfo) The toolchain. + Returns: + (Label) + """ + return _java_common_internal.java_toolchain_label(java_toolchain) + +def _make_java_common(): + methods = { + "provider": JavaInfo, + "compile": _compile, + "run_ijar": _run_ijar, + "stamp_jar": _stamp_jar, + "pack_sources": _pack_sources, + "default_javac_opts": _default_javac_opts, + "merge": _merge, + "make_non_strict": _make_non_strict, + "JavaPluginInfo": JavaPluginInfo, + "JavaToolchainInfo": _java_common_internal.JavaToolchainInfo, + "JavaRuntimeInfo": _java_common_internal.JavaRuntimeInfo, + "BootClassPathInfo": _java_common_internal.BootClassPathInfo, + "experimental_java_proto_library_default_has_services": _java_common_internal.experimental_java_proto_library_default_has_services, + } + if _java_common_internal._google_legacy_api_enabled(): + methods.update( + MessageBundleInfo = _get_message_bundle_info(), # struct field that is None in bazel + add_constraints = _add_constraints, + get_constraints = _get_constraints, + set_annotation_processing = _set_annotation_processing, + java_toolchain_label = _java_toolchain_label, + ) + return struct(**methods) + +java_common = _make_java_common() diff --git a/src/main/starlark/builtins_bzl/common/java/java_common_internal_for_builtins.bzl b/src/main/starlark/builtins_bzl/common/java/java_common_internal_for_builtins.bzl new file mode 100644 index 00000000000000..663c103571b35a --- /dev/null +++ b/src/main/starlark/builtins_bzl/common/java/java_common_internal_for_builtins.bzl @@ -0,0 +1,268 @@ +# Copyright 2023 The Bazel Authors. 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. + +""" Private utilities for Java compilation support in Starlark. """ + +load(":common/java/java_semantics.bzl", "semantics") +load(":common/paths.bzl", "paths") + +_java_common_internal = _builtins.internal.java_common_internal_do_not_use + +def compile( + ctx, + output, + java_toolchain, + source_jars = [], + source_files = [], + output_source_jar = None, + javac_opts = [], + deps = [], + runtime_deps = [], + exports = [], + plugins = [], + exported_plugins = [], + native_libraries = [], + annotation_processor_additional_inputs = [], + annotation_processor_additional_outputs = [], + strict_deps = "ERROR", + bootclasspath = None, + sourcepath = [], + resources = [], + add_exports = [], + add_opens = [], + neverlink = False, + enable_annotation_processing = True, + # private to @_builtins: + enable_compile_jar_action = True, + enable_jspecify = True, + include_compilation_info = True, + classpath_resources = [], + resource_jars = [], + injecting_rule_kind = None): + """Compiles Java source files/jars from the implementation of a Starlark rule + + The result is a provider that represents the results of the compilation and can be added to the + set of providers emitted by this rule. + + Args: + ctx: (RuleContext) The rule context + output: (File) The output of compilation + java_toolchain: (JavaToolchainInfo) Toolchain to be used for this compilation. Mandatory. + source_jars: ([File]) A list of the jars to be compiled. At least one of source_jars or + source_files should be specified. + source_files: ([File]) A list of the Java source files to be compiled. At least one of + source_jars or source_files should be specified. + output_source_jar: (File) The output source jar. Optional. Defaults to + `{output_jar}-src.jar` if unset. + javac_opts: ([str]) A list of the desired javac options. Optional. + deps: ([JavaInfo]) A list of dependencies. Optional. + runtime_deps: ([JavaInfo]) A list of runtime dependencies. Optional. + exports: ([JavaInfo]) A list of exports. Optional. + plugins: ([JavaPluginInfo|JavaInfo]) A list of plugins. Optional. + exported_plugins: ([JavaPluginInfo|JavaInfo]) A list of exported plugins. Optional. + native_libraries: ([CcInfo]) CC library dependencies that are needed for this library. + annotation_processor_additional_inputs: ([File]) A list of inputs that the Java compilation + action will take in addition to the Java sources for annotation processing. + annotation_processor_additional_outputs: ([File]) A list of outputs that the Java + compilation action will output in addition to the class jar from annotation processing. + strict_deps: (str) A string that specifies how to handle strict deps. Possible values: + 'OFF', 'ERROR', 'WARN' and 'DEFAULT'. + bootclasspath: (BootClassPathInfo) If present, overrides the bootclasspath associated with + the provided java_toolchain. Optional. + sourcepath: ([File]) + resources: ([File]) + resource_jars: ([File]) + classpath_resources: ([File]) + neverlink: (bool) + enable_annotation_processing: (bool) Disables annotation processing in this compilation, + causing any annotation processors provided in plugins or in exported_plugins of deps to + be ignored. + enable_compile_jar_action: (bool) Enables header compilation or ijar creation. If set to + False, it forces use of the full class jar in the compilation classpaths of any + dependants. Doing so is intended for use by non-library targets such as binaries that + do not have dependants. + enable_jspecify: (bool) + include_compilation_info: (bool) + injecting_rule_kind: (str|None) + add_exports: ([str]) Allow this library to access the given /. Optional. + add_opens: ([str]) Allow this library to reflectively access the given /. + Optional. + + Returns: + (JavaInfo) + """ + return _java_common_internal.compile( + ctx, + output = output, + java_toolchain = java_toolchain, + source_jars = source_jars, + source_files = source_files, + output_source_jar = output_source_jar, + javac_opts = javac_opts, + deps = deps, + runtime_deps = runtime_deps, + exports = exports, + plugins = plugins, + exported_plugins = exported_plugins, + native_libraries = native_libraries, + annotation_processor_additional_inputs = annotation_processor_additional_inputs, + annotation_processor_additional_outputs = annotation_processor_additional_outputs, + strict_deps = strict_deps, + bootclasspath = bootclasspath, + sourcepath = sourcepath, + resources = resources, + neverlink = neverlink, + enable_annotation_processing = enable_annotation_processing, + add_exports = add_exports, + add_opens = add_opens, + enable_compile_jar_action = enable_compile_jar_action, + enable_jspecify = enable_jspecify, + include_compilation_info = include_compilation_info, + classpath_resources = classpath_resources, + resource_jars = resource_jars, + injecting_rule_kind = injecting_rule_kind, + ) + +def run_ijar( + actions, + jar, + java_toolchain, + target_label = None, + # private to @_builtins: + output = None): + """Runs ijar on a jar, stripping it of its method bodies. + + This helps reduce rebuilding of dependent jars during any recompiles consisting only of simple + changes to method implementations. The return value is typically passed to JavaInfo.compile_jar + + Args: + actions: (actions) ctx.actions + jar: (File) The jar to run ijar on. + java_toolchain: (JavaToolchainInfo) The toolchain to used to find the ijar tool. + target_label: (Label|None) A target label to stamp the jar with. Used for `add_dep` support. + Typically, you would pass `ctx.label` to stamp the jar with the current rule's label. + output: (File) Optional. + + Returns: + (File) The output artifact + """ + if not output: + output = actions.declare_file(paths.replace_extension(jar.basename, "-ijar.jar"), sibling = jar) + args = actions.args() + args.add(jar) + args.add(output) + if target_label != None: + args.add("--target_label", target_label) + actions.run( + mnemonic = "JavaIjar", + inputs = [jar], + outputs = [output], + executable = java_toolchain.ijar, + arguments = [args], + progress_message = "Extracting interface for jar %{input}", + toolchain = semantics.JAVA_TOOLCHAIN_TYPE, + use_default_shell_env = True, + ) + return output + +def merge( + providers, + # private to @_builtins: + merge_java_outputs = True, + merge_source_jars = True): + """Merges the given providers into a single JavaInfo. + + Args: + providers: ([JavaInfo]) The list of providers to merge. + merge_java_outputs: (bool) + merge_source_jars: (bool) + + Returns: + (JavaInfo) The merged JavaInfo + """ + return _java_common_internal.merge( + providers, + merge_java_outputs = merge_java_outputs, + merge_source_jars = merge_source_jars, + ) + +def target_kind(target, dereference_aliases = False): + """Get the rule class string for a target + + Args: + target: (Target) + dereference_aliases: (bool) resolve the actual target rule class if an + alias + + Returns: + (str) The rule class string of the target + """ + return _java_common_internal.target_kind( + target, + dereference_aliases = dereference_aliases, + ) + +def get_build_info(ctx, is_stamping_enabled): + """Get the artifacts representing the workspace status for this build + + Args: + ctx: (RuleContext) The rule context + is_stamping_enabled: (bool) If stamping is enabled + + Returns + ([File]) The build info artifacts + """ + return _java_common_internal.get_build_info(ctx, is_stamping_enabled) + +def collect_native_deps_dirs(deps): + """Collect the set of root-relative paths containing native libraries + + Args: + deps: [Target] list of targets + + Returns: + ([String]) A set of root-relative paths as a list + """ + return _java_common_internal.collect_native_deps_dirs(deps) + +def get_runtime_classpath_for_archive(jars, excluded_jars): + """Filters a classpath to remove certain entries + + Args + jars: (depset[File]) The classpath to filter + excluded_jars: (depset[File]) The files to remove + + Returns: + (depset[File]) The filtered classpath + """ + return _java_common_internal.get_runtime_classpath_for_archive( + jars, + excluded_jars, + ) + +def filter_protos_for_generated_extension_registry(runtime_jars, deploy_env): + """Get proto artifacts from runtime_jars excluding those in deploy_env + + Args: + runtime_jars: (depset[File]) the artifacts to scan + deploy_env: (depset[File]) the artifacts to exclude + + Returns + (depset[File], bool) A tuple of the filtered protos and whether all protos are 'lite' + flavored + """ + return _java_common_internal.filter_protos_for_generated_extension_registry( + runtime_jars, + deploy_env, + ) diff --git a/src/main/starlark/builtins_bzl/common/java/java_helper.bzl b/src/main/starlark/builtins_bzl/common/java/java_helper.bzl index eebc50d57dec67..7c751f4e8ff3fd 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_helper.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_helper.bzl @@ -288,19 +288,35 @@ def _test_providers(ctx): return test_providers -def _create_single_jar(ctx, output, *input_depsets): - """Register action for the output jar. +def _resource_mapper(file): + return "%s:%s" % ( + file.path, + semantics.get_default_resource_path(file.short_path, segment_extractor = _java_segments), + ) + +def _create_single_jar( + actions, + toolchain, + output, + sources = depset(), + resources = depset(), + mnemonic = "JavaSingleJar", + progress_message = "Building singlejar jar %{output}"): + """Register singlejar action for the output jar. Args: - ctx: (RuleContext) Used to register the action. - output: (Artifact) Output file of the action. - *input_depsets: (list[depset[Artifact]]) Input files of the action. + actions: (actions) ctx.actions + toolchain: (JavaToolchainInfo) The java toolchain + output: (File) Output file of the action. + sources: (depset[File]) The jar files to merge into the output jar. + resources: (depset[File]) The files to add to the output jar. + mnemonic: (str) The action identifier + progress_message: (str) The action progress message Returns: (File) Output file which was used for registering the action. """ - toolchain = semantics.find_java_toolchain(ctx) - args = ctx.actions.args() + args = actions.args() args.set_param_file_format("shell").use_param_file("@%s", use_always = True) args.add("--output", output) args.add_all( @@ -311,15 +327,15 @@ def _create_single_jar(ctx, output, *input_depsets): "--warn_duplicate_resources", ], ) - all_inputs = depset(transitive = input_depsets) - args.add_all("--sources", all_inputs) - ctx.actions.run( - mnemonic = "JavaSingleJar", - progress_message = "Building singlejar jar %s" % output.short_path, + args.add_all("--sources", sources) + args.add_all("--resources", resources, map_each = _resource_mapper) + actions.run( + mnemonic = mnemonic, + progress_message = progress_message, executable = toolchain.single_jar, toolchain = semantics.JAVA_TOOLCHAIN_TYPE, - inputs = all_inputs, + inputs = depset(transitive = [resources, sources]), tools = [toolchain.single_jar], outputs = [output], arguments = [args], diff --git a/src/main/starlark/builtins_bzl/common/java/java_import.bzl b/src/main/starlark/builtins_bzl/common/java/java_import.bzl index 6aa2e850504fd3..6dce021f97dc39 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_import.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_import.bzl @@ -23,6 +23,7 @@ load(":common/java/import_deps_check.bzl", "import_deps_check") load(":common/cc/cc_info.bzl", "CcInfo") load(":common/java/java_info.bzl", "JavaInfo") load(":common/java/java_common.bzl", "java_common") +load(":common/java/java_common_internal_for_builtins.bzl", _run_ijar_private_for_builtins = "run_ijar") def _filter_provider(provider, *attrs): return [dep[provider] for attr in attrs for dep in attr if provider in dep] @@ -49,7 +50,7 @@ def _process_with_ijars_if_needed(jars, ctx): interface_jar_directory = "_ijar/" + ctx.label.name + "/" + ijar_basename interface_jar = ctx.actions.declare_file(interface_jar_directory) - java_common.run_ijar( + _run_ijar_private_for_builtins( ctx.actions, target_label = ctx.label, jar = jar, diff --git a/src/main/starlark/builtins_bzl/common/java/java_info.bzl b/src/main/starlark/builtins_bzl/common/java/java_info.bzl index d0f5c0b425fc87..39cf7031476596 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_info.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_info.bzl @@ -17,7 +17,7 @@ Definition of JavaInfo provider. """ load(":common/cc/cc_common.bzl", "cc_common") -load(":common/java/java_plugin_info.bzl", "merge_without_outputs") +load(":common/java/java_plugin_info.bzl", "EMPTY_PLUGIN_DATA", "merge_without_outputs") load(":common/cc/cc_info.bzl", "CcInfo") # TODO(hvd): remove this when: @@ -71,6 +71,105 @@ _JavaGenJarsInfo = provider( }, ) +_JavaCompilationInfo = provider( + doc = "Compilation information in Java rules, for perusal of aspects and tools.", + fields = { + "boot_classpath": "Boot classpath for this Java target.", + "javac_options": "Options to the java compiler.", + "compilation_classpath": "Compilation classpath for this Java target.", + "runtime_classpath": "Run-time classpath for this Java target.", + }, +) + +def to_java_binary_info(java_info): + """Get a copy of the given JavaInfo with minimal info returned by a java_binary + + Args: + java_info: (JavaInfo) A JavaInfo provider instance + + Returns: + (JavaInfo) A JavaInfo instance representing a java_binary target + """ + result = { + "transitive_runtime_jars": depset(), + "transitive_runtime_deps": depset(), # deprecated + "transitive_compile_time_jars": depset(), + "transitive_deps": depset(), # deprecated + "compile_jars": depset(), + "full_compile_jars": depset(), + "_transitive_full_compile_time_jars": depset(), + "_compile_time_java_dependencies": depset(), + "runtime_output_jars": [], + "plugins": EMPTY_PLUGIN_DATA, + "api_generating_plugins": EMPTY_PLUGIN_DATA, + "module_flags_info": _ModuleFlagsInfo(add_exports = depset(), add_opens = depset()), + "_neverlink": False, + "_constraints": [], + "annotation_processing": java_info.annotation_processing, + "cc_link_params_info": getattr(java_info, "cc_link_params_info", None), + "transitive_native_libraries": java_info.transitive_native_libraries, + "source_jars": java_info.source_jars, + "transitive_source_jars": java_info.transitive_source_jars, + } + + compilation_info = None + if hasattr(java_info, "compilation_info"): + compilation_info = java_info.compilation_info + elif java_info.transitive_compile_time_jars or java_info.transitive_runtime_jars: + compilation_info = _JavaCompilationInfo( + boot_classpath = None, + javac_options = [], + compilation_classpath = java_info.transitive_compile_time_jars, + runtime_classpath = java_info.transitive_runtime_jars, + ) + result["compilation_info"] = compilation_info + + java_outputs = [ + _JavaOutputInfo( + compile_jar = None, + compile_jdeps = None, + class_jar = output.class_jar, + ijar = output.compile_jar, # deprecated + generated_class_jar = output.generated_class_jar, + generated_source_jar = output.generated_source_jar, + native_headers_jar = output.native_headers_jar, + manifest_proto = output.manifest_proto, + jdeps = output.jdeps, + source_jars = output.source_jars, + source_jar = output.source_jar, # deprecated + ) + for output in java_info.java_outputs + ] + result.update( + java_outputs = java_outputs, + outputs = _JavaRuleOutputJarsInfo(jars = java_outputs, jdeps = None, native_headers = None), + ) + return _new_javainfo(**result) + +def _to_mutable_dict(java_info): + return { + key: getattr(java_info, key) + for key in dir(java_info) + if key not in ["to_json", "to_proto"] + } + +def add_constraints(java_info, constraints = []): + """Returns a copy of the given JavaInfo with the given constraints added. + + Args: + java_info: (JavaInfo) The JavaInfo to enhance + constraints: ([str]) Constraints to add + + Returns: + (JavaInfo) + """ + result = _to_mutable_dict(java_info) + old_constraints = java_info._constraints if java_info._constraints else [] + result.update( + _constraints = depset(constraints + old_constraints).to_list(), + ) + return _new_javainfo(**result) + def _validate_provider_list(provider_list, what, expected_provider_type): _java_common_internal.check_provider_instances(provider_list, what, expected_provider_type) @@ -234,12 +333,12 @@ def _javainfo_init( direct = [output_jar], transitive = [dep._transitive_full_compile_time_jars for dep in exports + deps], ), - "_plugin_info": plugin_info, "_compile_time_java_dependencies": depset( order = "preorder", transitive = [dep._compile_time_java_dependencies for dep in exports] + ([depset([compile_jdeps])] if compile_jdeps else []), ), + "_constraints": [], } if _java_common_internal._google_legacy_api_enabled(): cc_info = cc_common.merge_cc_infos( @@ -309,7 +408,7 @@ JavaInfo, _new_javainfo = provider( "_transitive_full_compile_time_jars": "internal API, do not use", "_compile_time_java_dependencies": "internal API, do not use", "_neverlink": "internal API, do not use", - "_plugin_info": "internal API, do not use", + "_constraints": "internal API, do not use", }, init = _javainfo_init, ) diff --git a/src/main/starlark/builtins_bzl/common/java/java_plugin_info.bzl b/src/main/starlark/builtins_bzl/common/java/java_plugin_info.bzl index 7c0f79fb0cd6be..23502f9e08dabd 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_plugin_info.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_plugin_info.bzl @@ -16,7 +16,7 @@ Definition of JavaPluginInfo provider. """ -load(":common/java/java_common.bzl", "java_common") +load(":common/java/java_common_internal_for_builtins.bzl", _merge_private_for_builtins = "merge") _JavaPluginDataInfo = provider( doc = "Provider encapsulating information about a Java compatible plugin.", @@ -27,7 +27,7 @@ _JavaPluginDataInfo = provider( }, ) -_EMPTY_PLUGIN_DATA = _JavaPluginDataInfo( +EMPTY_PLUGIN_DATA = _JavaPluginDataInfo( processor_classes = depset(), processor_jars = depset(), processor_data = depset(), @@ -58,7 +58,9 @@ def _javaplugininfo_init( Returns: (JavaPluginInfo) """ - java_infos = java_common.merge(runtime_deps) + + # we don't need the private API but java_common needs JavaPluginInfo which would be a cycle + java_infos = _merge_private_for_builtins(runtime_deps) processor_data = data if type(data) == "depset" else depset(data) plugins = _JavaPluginDataInfo( processor_classes = depset([processor_class]) if processor_class else depset(), @@ -67,7 +69,7 @@ def _javaplugininfo_init( ) return { "plugins": plugins, - "api_generating_plugins": plugins if generates_api else _EMPTY_PLUGIN_DATA, + "api_generating_plugins": plugins if generates_api else EMPTY_PLUGIN_DATA, "java_outputs": java_infos.java_outputs, } diff --git a/src/main/starlark/builtins_bzl/common/java/java_semantics.bzl b/src/main/starlark/builtins_bzl/common/java/java_semantics.bzl index a13b1404e6ff10..a369ee6136b804 100644 --- a/src/main/starlark/builtins_bzl/common/java/java_semantics.bzl +++ b/src/main/starlark/builtins_bzl/common/java/java_semantics.bzl @@ -28,6 +28,15 @@ def _find_java_toolchain(ctx): def _find_java_runtime_toolchain(ctx): return ctx.toolchains["@bazel_tools//tools/jdk:runtime_toolchain_type"].java_runtime +def _get_default_resource_path(path, segment_extractor): + # Look for src/.../resources to match Maven repository structure. + segments = path.split("/") + for idx in range(0, len(segments) - 2): + if segments[idx] == "src" and segments[idx + 2] == "resources": + return "/".join(segments[idx + 3:]) + java_segments = segment_extractor(path) + return "/".join(java_segments) if java_segments != None else path + semantics = struct( JAVA_TOOLCHAIN_LABEL = "@bazel_tools//tools/jdk:current_java_toolchain", JAVA_TOOLCHAIN_TYPE = "@bazel_tools//tools/jdk:toolchain_type", @@ -57,4 +66,6 @@ semantics = struct( JAVA_STUB_TEMPLATE_LABEL = "@bazel_tools//tools/jdk:java_stub_template.txt", BUILD_INFO_TRANSLATOR_LABEL = None, JAVA_TEST_RUNNER_LABEL = "@bazel_tools//tools/jdk:TestRunner", + IS_BAZEL = True, + get_default_resource_path = _get_default_resource_path, ) diff --git a/src/main/starlark/builtins_bzl/common/java/message_bundle_info.bzl b/src/main/starlark/builtins_bzl/common/java/message_bundle_info.bzl new file mode 100644 index 00000000000000..49948fa42d57ec --- /dev/null +++ b/src/main/starlark/builtins_bzl/common/java/message_bundle_info.bzl @@ -0,0 +1,24 @@ +# Copyright 2023 The Bazel Authors. 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. + +""" +Definition of MessageBundleInfo provider. +""" + +MessageBundleInfo = provider( + doc = "Marks configured targets that are able to supply message bundles to their dependents.", + fields = { + "messages": "Sequence of message bundles", + }, +) diff --git a/src/main/starlark/builtins_bzl/common/java/proto/java_proto_library.bzl b/src/main/starlark/builtins_bzl/common/java/proto/java_proto_library.bzl index f3b557dd6528de..c4ed89c0e187d1 100644 --- a/src/main/starlark/builtins_bzl/common/java/proto/java_proto_library.bzl +++ b/src/main/starlark/builtins_bzl/common/java/proto/java_proto_library.bzl @@ -18,7 +18,11 @@ load(":common/java/java_semantics.bzl", "semantics") load(":common/proto/proto_common.bzl", "ProtoLangToolchainInfo", proto_common = "proto_common_do_not_use") load(":common/proto/proto_info.bzl", "ProtoInfo") load(":common/java/java_info.bzl", "JavaInfo") -load(":common/java/java_common.bzl", "java_common") +load( + ":common/java/java_common_internal_for_builtins.bzl", + _compile_private_for_builtins = "compile", + _merge_private_for_builtins = "merge", +) # The provider is used to collect source and runtime jars in the `proto_library` dependency graph. JavaProtoAspectInfo = provider("JavaProtoAspectInfo", fields = ["jars"]) @@ -106,23 +110,23 @@ def java_compile_for_protos(ctx, output_jar_suffix, source_jar = None, deps = [] path, sep, filename = ctx.label.name.rpartition("/") output_jar = ctx.actions.declare_file(path + sep + "lib" + filename + output_jar_suffix) java_toolchain = semantics.find_java_toolchain(ctx) - java_info = java_common.compile( + java_info = _compile_private_for_builtins( ctx, + output = output_jar, + java_toolchain = java_toolchain, source_jars = [source_jar], deps = deps, exports = exports, - output = output_jar, output_source_jar = source_jar, injecting_rule_kind = injecting_rule_kind, javac_opts = java_toolchain.compatible_javacopts("proto"), enable_jspecify = False, - java_toolchain = java_toolchain, include_compilation_info = False, ) jars = [source_jar, output_jar] else: # If there are no proto sources just pass along the compilation dependencies. - java_info = java_common.merge(deps + exports, merge_java_outputs = False, merge_source_jars = False) + java_info = _merge_private_for_builtins(deps + exports, merge_java_outputs = False, merge_source_jars = False) jars = [] return java_info, jars @@ -149,7 +153,7 @@ def bazel_java_proto_library_rule(ctx): ([JavaInfo, DefaultInfo, OutputGroupInfo]) """ - java_info = java_common.merge([dep[JavaInfo] for dep in ctx.attr.deps], merge_java_outputs = False) + java_info = _merge_private_for_builtins([dep[JavaInfo] for dep in ctx.attr.deps], merge_java_outputs = False) transitive_src_and_runtime_jars = depset(transitive = [dep[JavaProtoAspectInfo].jars for dep in ctx.attr.deps]) transitive_runtime_jars = depset(transitive = [java_info.transitive_runtime_jars]) diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java index d5a19e8fd2f9c5..e3904628b8542d 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java @@ -11,7 +11,6 @@ // 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.analysis; import static com.google.common.truth.Truth.assertThat; @@ -194,13 +193,13 @@ public void testActionConflictInDependencyImpliesTopLevelTargetFailure() throws } useConfiguration("--cpu=k8"); scratch.file( - "conflict/BUILD", + "conflict_non_top_level/BUILD", "cc_library(name='x', srcs=['foo.cc'])", "cc_binary(name='_objs/x/foo.o', srcs=['bar.cc'])", "cc_binary(name='foo', deps=['x'], data=['_objs/x/foo.o'])"); reporter.removeHandler(failFastHandler); // expect errors - update(defaultFlags().with(Flag.KEEP_GOING), "//conflict:foo"); - assertContainsEvent("file 'conflict/_objs/x/foo.o' " + CONFLICT_MSG); + update(defaultFlags().with(Flag.KEEP_GOING), "//conflict_non_top_level:foo"); + assertContainsEvent("file 'conflict_non_top_level/_objs/x/foo.o' " + CONFLICT_MSG); assertThat(getAnalysisResult().getTargetsToBuild()).isEmpty(); } @@ -489,10 +488,14 @@ public void testDependencyAllCacheHits() throws Exception { update("//java/a:x"); Set oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys(); assertThat(oldAnalyzedTargets.size()).isAtLeast(2); // could be greater due to implicit deps - assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x")).isEqualTo(1); + // x is evaluated once with the top level configuration and once with its rule transitioned + // configuration. + assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x")).isEqualTo(2); assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y")).isEqualTo(1); + update("//java/a:y"); - assertNoTargetsVisited(); + // y is evaluated with the top-level configuration instead of with its rule transition applied. + assertThat(getSkyframeEvaluatedTargetKeys()).hasSize(1); } @Test @@ -508,12 +511,14 @@ public void testSupersetNotAllCacheHits() throws Exception { Set oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys(); assertThat(oldAnalyzedTargets.size()).isAtLeast(3); // could be greater due to implicit deps assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x")).isEqualTo(0); - assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y")).isEqualTo(1); + // y is evaluated once with the top level configuration and once with its rule transitioned + // configuration. + assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y")).isEqualTo(2); update("//java/a:x"); Set newAnalyzedTargets = getSkyframeEvaluatedTargetKeys(); - // Source target and rule target. - assertThat(newAnalyzedTargets).hasSize(2); - assertThat(countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:x")).isEqualTo(1); + // Source target and x twice. + assertThat(newAnalyzedTargets).hasSize(3); + assertThat(countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:x")).isEqualTo(2); assertThat(countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:y")).isEqualTo(0); } @@ -642,7 +647,9 @@ public void testGetSkyframeEvaluatedTargetKeysOmitsCachedTargets() throws Except update("//java/a:x"); Set oldAnalyzedTargets = getSkyframeEvaluatedTargetKeys(); assertThat(oldAnalyzedTargets.size()).isAtLeast(2); // could be greater due to implicit deps - assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x")).isEqualTo(1); + // x is analyzed once with the top-level configuration and once with its rule-transitioned + // configuration. + assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:x")).isEqualTo(2); assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:y")).isEqualTo(0); assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:z")).isEqualTo(1); assertThat(countObjectsPartiallyMatchingRegex(oldAnalyzedTargets, "//java/a:w")).isEqualTo(1); @@ -651,11 +658,12 @@ public void testGetSkyframeEvaluatedTargetKeysOmitsCachedTargets() throws Except // as cached top-level targets. For the two tests above to work correctly, we need to ensure // that getSkyframeEvaluatedTargetKeys() doesn't return these. update("//java/a:x", "//java/a:y", "//java/a:z"); - Set newAnalyzedTargets = getSkyframeEvaluatedTargetKeys(); - assertThat(newAnalyzedTargets).hasSize(2); - assertThat(countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:B.java")) - .isEqualTo(1); - assertThat(countObjectsPartiallyMatchingRegex(newAnalyzedTargets, "//java/a:y")).isEqualTo(1); + assertNumberOfAnalyzedConfigurationsOfTargets( + ImmutableMap.builder() + .put("//java/a:y", 2) // With the top-level and rule transitioned configurations. + .put("//java/a:B.java", 1) + .put("//java/a:z", 1) // With the top-level configuration. + .buildOrThrow()); } /** Test options class for testing diff-based analysis cache resetting. */ @@ -876,9 +884,10 @@ public void cacheClearedWhenRedundantDefinesChange_collapseDuplicateDefinesDisab scratch.file("test/BUILD", "load(':lib.bzl', 'normal_lib')", "normal_lib(name='top')"); useConfiguration("--nocollapse_duplicate_defines", "--define=a=1", "--define=a=2"); update("//test:top"); + assertNumberOfAnalyzedConfigurationsOfTargets(ImmutableMap.of("//test:top", 2)); useConfiguration("--nocollapse_duplicate_defines", "--define=a=2"); update("//test:top"); - assertNumberOfAnalyzedConfigurationsOfTargets(ImmutableMap.of("//test:top", 1)); + assertNumberOfAnalyzedConfigurationsOfTargets(ImmutableMap.of("//test:top", 2)); } @Test diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java index 5ce837d7d1acbb..08696878ef1ef5 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java @@ -17,7 +17,6 @@ import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.truth.Truth.assertThat; import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationIdMessage; -import static com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil.configurationIdMessage; import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; @@ -25,6 +24,7 @@ import com.google.common.eventbus.Subscribe; import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; +import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId; import com.google.devtools.build.lib.causes.AnalysisFailedCause; import com.google.devtools.build.lib.causes.Cause; import com.google.devtools.build.lib.causes.LoadingFailedCause; @@ -38,7 +38,6 @@ import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.Collection; -import java.util.HashMap; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -102,8 +101,7 @@ public void testMissingDependency() throws Exception { .containsExactly( new AnalysisFailedCause( causeLabel, - configurationIdMessage( - getOnlyElement(collector.failedTargets.values()).getConfigurationKey()), + collector.getOnlyConfigurationId(), createPackageLoadingDetailedExitCode( "BUILD file not found in any of the following" + " directories. Add a BUILD file to a directory to mark it as a" @@ -130,8 +128,7 @@ public void testExpanderFailure() throws Exception { .containsExactly( new AnalysisFailedCause( topLevel, - configurationIdMessage( - getOnlyElement(collector.failedTargets.values()).getConfigurationKey()), + collector.getOnlyConfigurationId(), createAnalysisDetailedExitCode( "in cmd attribute of genrule rule //test:bad: variable '$<' : no input file"))); } @@ -164,7 +161,7 @@ public void testSymlinkCycleReportedExactlyOnce() throws Exception { .containsExactly( new AnalysisFailedCause( Label.parseCanonical("//cycles1"), - configurationIdMessage(collector.failedTargets.get(topLevel).getConfigurationKey()), + collector.getOnlyConfigurationId(), createPackageLoadingDetailedExitCode(message, code))); } @@ -181,8 +178,7 @@ public void testVisibilityError() throws Exception { .containsExactly( new AnalysisFailedCause( Label.parseCanonical("//foo"), - configurationIdMessage( - getOnlyElement(collector.failedTargets.values()).getConfigurationKey()), + collector.getOnlyConfigurationId(), createAnalysisDetailedExitCode( "in sh_library rule //foo:foo: target '//bar:bar' is not visible from" + " target '//foo:foo'. Check the visibility declaration of the" @@ -204,8 +200,7 @@ public void testFileVisibilityError() throws Exception { .containsExactly( new AnalysisFailedCause( Label.parseCanonical("//foo"), - configurationIdMessage( - getOnlyElement(collector.failedTargets.values()).getConfigurationKey()), + collector.getOnlyConfigurationId(), DetailedExitCode.of( FailureDetail.newBuilder() .setMessage( @@ -277,14 +272,22 @@ public static DetailedExitCode createAnalysisDetailedExitCode(String message) { /** Class to collect analysis failures. */ public static class AnalysisFailureEventCollector { private final Multimap events = HashMultimap.create(); - private final HashMap failedTargets = new HashMap<>(); @Subscribe public void failureEvent(AnalysisFailureEvent event) { ConfiguredTargetKey failedTarget = event.getFailedTarget(); - Label label = failedTarget.getLabel(); - events.putAll(label, event.getRootCauses().toList()); - failedTargets.put(label, failedTarget); + events.putAll(failedTarget.getLabel(), event.getRootCauses().toList()); + } + + private ConfigurationId getOnlyConfigurationId() { + // Analysis errors after the target's configuration has been determined are reported using a + // possibly transitioned ID which is hard to retrieve from the graph if analysis of that + // target fails. This method simply extracts them from the event ID. + return getOnlyElement(events.entries()) + .getValue() + .getIdProto() + .getConfiguredLabel() + .getConfiguration(); } } } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AutoExecGroupsTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AutoExecGroupsTest.java index 2344f17117ff5d..0b9286a525a942 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/AutoExecGroupsTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/AutoExecGroupsTest.java @@ -26,7 +26,6 @@ import com.google.devtools.build.lib.actions.ActionAnalysisMetadata; import com.google.devtools.build.lib.analysis.actions.LazyWritePathsFileAction; import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction; -import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement; import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; @@ -1498,10 +1497,12 @@ public void javaCommonBuildIjar_automaticExecGroupsEnabled_ijarActionsExecuteOnF "custom_rule(name = 'custom_rule_name')"); useConfiguration("--incompatible_auto_exec_groups"); - ImmutableList actions = getActions("//test:custom_rule_name", SpawnAction.class); + ImmutableList actions = + getActions("//test:custom_rule_name").stream() + .filter(action -> action.getMnemonic().equals("JavaIjar")) + .collect(toImmutableList()); assertThat(actions).hasSize(1); - assertThat(actions.get(0).getMnemonic()).isEqualTo("JavaIjar"); assertThat(actions.get(0).getOwner().getExecutionPlatform().label()) .isEqualTo(Label.parseCanonical("//platforms:platform_1")); } @@ -1530,10 +1531,12 @@ public void javaCommonPackSources_automaticExecGroupsEnabled_sourceActionExecute "custom_rule(name = 'custom_rule_name')"); useConfiguration("--incompatible_auto_exec_groups"); - ImmutableList actions = getActions("//test:custom_rule_name", SpawnAction.class); + ImmutableList actions = + getActions("//test:custom_rule_name").stream() + .filter(action -> action.getMnemonic().equals("JavaSourceJar")) + .collect(toImmutableList()); assertThat(actions).hasSize(1); - assertThat(actions.get(0).getMnemonic()).isEqualTo("JavaSourceJar"); assertThat(actions.get(0).getOwner().getExecutionPlatform().label()) .isEqualTo(Label.parseCanonical("//platforms:platform_1")); } @@ -1568,11 +1571,15 @@ public void javaCommonStampJar_automaticExecGroupsEnabled_actionExecutesOnFirstP "custom_rule(name = 'custom_rule_name')"); useConfiguration("--incompatible_auto_exec_groups"); - ImmutableList actions = getActions("//test:custom_rule_name", SpawnAction.class); + ImmutableList actions = + getActions("//test:custom_rule_name").stream() + .filter(action -> action.getMnemonic().equals("JavaIjar")) + .collect(toImmutableList()); + ; assertThat(actions).hasSize(1); assertThat(actions.get(0).getProgressMessage()) - .isEqualTo("Stamping target label into jar lib_custom_rule_name.jar"); + .matches("Stamping target label into jar .*/lib_custom_rule_name.jar"); assertThat(actions.get(0).getOwner().getExecutionPlatform().label()) .isEqualTo(Label.parseCanonical("//platforms:platform_1")); } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/BUILD b/src/test/java/com/google/devtools/build/lib/analysis/BUILD index aa6e0028a31696..3dbc0dc2e53950 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/BUILD +++ b/src/test/java/com/google/devtools/build/lib/analysis/BUILD @@ -173,6 +173,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/vfs", "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment", "//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs", + "//src/main/java/com/google/devtools/build/skyframe", "//src/main/java/com/google/devtools/build/skyframe:skyframe-objects", "//src/main/java/com/google/devtools/common/options", "//src/main/java/net/starlark/java/annot", diff --git a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java index 28bdc4ffdd443d..049b1ed8f0f162 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java @@ -1406,13 +1406,4 @@ public void testExistingRules() throws Exception { update("//pkg:foo"); assertContainsEvent("DEBUG /workspace/pkg/BUILD:5:6: [\"foo\"]"); } - - /** Runs the same test with the Skyframe-based analysis prep. */ - @RunWith(JUnit4.class) - public static class WithSkyframePrepareAnalysis extends BuildViewTest { - @Override - protected FlagBuilder defaultFlags() { - return super.defaultFlags().with(Flag.SKYFRAME_PREPARE_ANALYSIS); - } - } } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java index 280593f8edbf3d..ef6be77deebae6 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurableAttributesTest.java @@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.build.lib.analysis; -import static com.google.common.testing.GcFinalization.awaitClear; import static com.google.common.truth.Truth.assertThat; import static com.google.devtools.build.lib.packages.Attribute.attr; import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST; @@ -33,12 +32,9 @@ import com.google.devtools.build.lib.packages.RuleClass.ToolchainResolutionMode; import com.google.devtools.build.lib.packages.Type; import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; -import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; -import com.google.devtools.build.lib.skyframe.SkyframeExecutorWrappingWalkableGraph; import com.google.devtools.build.lib.testutil.TestRuleClassProvider; import com.google.devtools.build.lib.util.FileTypeSet; import java.io.IOException; -import java.lang.ref.WeakReference; import java.util.Collection; import java.util.Set; import org.junit.Before; @@ -1931,71 +1927,4 @@ public void selectWithLabelKeysInMacro() throws Exception { /*expected:*/ ImmutableList.of("bin java/foo/libb.jar", "bin java/foo/libb2.jar"), /*not expected:*/ ImmutableList.of("bin java/foo/liba.jar", "bin java/foo/liba2.jar")); } - - @Test - public void proxyKeysAreRetained() throws Exception { - // This test case verifies that when a ProxyConfiguredTargetKey is created, it is retained. - scratch.file( - "conditions/BUILD", - "constraint_setting(name = 'animal')", - "constraint_value(name = 'manatee', constraint_setting = 'animal')", - "constraint_value(name = 'koala', constraint_setting = 'animal')", - "platform(", - " name = 'manatee_platform',", - " constraint_values = [':manatee'],", - ")", - "platform(", - " name = 'koala_platform',", - " constraint_values = [':koala'],", - ")"); - scratch.file( - "check/BUILD", - "filegroup(name = 'adep', srcs = ['afile'])", - "filegroup(name = 'bdep', srcs = ['bfile'])", - "filegroup(name = 'hello',", - " srcs = select({", - " '//conditions:manatee': [':adep'],", - " '//conditions:koala': [':bdep'],", - " }))"); - - useConfiguration("--experimental_platforms=//conditions:manatee_platform"); - ConfiguredTarget hello = getConfiguredTarget("//check:hello"); - - var koalaLabel = Label.parseCanonical("//conditions:koala"); - - // Shakes the interner to try to get any non-strongly reachable keys to fall out. This should - // cause the ProxyConfiguredTargetKey created for "//conditions:koala" to fall out if it's not - // otherwise retained. - // - // Creates and inserts a canary key into the interner that can be used to detect eviction of - // weak keys. - var canaryKey = new WeakReference<>(ConfiguredTargetKey.builder().setLabel(koalaLabel).build()); - awaitClear(canaryKey); - // Once we get here we know that the canaryKey is no longer in the weak interner. Due to the - // collection properties of weak references, that implies the interner now has no weakly - // reachable keys at all. - - // Since //conditions:koala is a ConfigCondition, so it would be requested by //check:hello - // using //check:hello's configuration. - var koalaOwner = - ConfiguredTargetKey.builder() - .setLabel(koalaLabel) - .setConfigurationKey(hello.getConfigurationKey()) - .build(); - // Uses a WalkableGraph lookup to ensure there is an existing //conditions:koala instance that - // was created using koalaOwner. - var walkableGraph = SkyframeExecutorWrappingWalkableGraph.of(skyframeExecutor); - var koala = (ConfiguredTargetValue) walkableGraph.getValue(koalaOwner.toKey()); - assertThat(koala).isNotNull(); - - // constraint_value has a NoConfigTransition rule transition so a corresponding proxy key - // should exist. - ConfiguredTargetKey koalaKey = - ConfiguredTargetKey.builder() - .setLabel(koalaLabel) - .setConfigurationKey(koala.getConfiguredTarget().getConfigurationKey()) - .build(); - assertThat(koalaKey.isProxy()).isTrue(); - assertThat(koalaKey.toKey()).isEqualTo(koalaOwner); - } } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java b/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java index 96ea0753dc4b25..707efb4b1574e5 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/TargetCompleteEventTest.java @@ -24,6 +24,7 @@ import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.EventReportingArtifacts.ReportedArtifacts; import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper.ArtifactsToBuild; +import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; import com.google.devtools.build.lib.analysis.util.AnalysisTestCase; import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.File; import com.google.devtools.build.lib.collect.nestedset.NestedSet; @@ -57,8 +58,11 @@ public void testFileProtoFromArtifactReencodesAsUtf8() throws Exception { AnalysisResult result = update("//sh:globby"); ConfiguredTarget ct = Iterables.getOnlyElement(result.getTargetsToBuild()); TargetAndConfiguration tac = Iterables.getOnlyElement(result.getTopLevelTargetsWithConfigs()); + var configuredTargetConfiguration = + (BuildConfigurationValue) + skyframeExecutor.getEvaluator().getExistingValue(ct.getConfigurationKey()); ConfiguredTargetAndData ctAndData = - new ConfiguredTargetAndData(ct, tac.getTarget(), tac.getConfiguration(), null); + new ConfiguredTargetAndData(ct, tac.getTarget(), configuredTargetConfiguration, null); TopLevelArtifactContext context = new TopLevelArtifactContext(false, false, false, OutputGroupInfo.DEFAULT_GROUPS); ArtifactsToBuild artifactsToBuild = TopLevelArtifactHelper.getAllArtifactsToBuild(ct, context); diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTest.java index 24da5e03ceedf9..b6cd9a53dbe1f2 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/SpawnActionTest.java @@ -135,7 +135,7 @@ public void testExecutionInfo_fromExecutionPlatform() throws Exception { Label.parseCanonicalUnchecked("//target"), new Location("dummy-file", 0, 0), /* targetKind= */ "dummy-kind", - /* mnemonic= */ "dummy-configuration-mnemonic", + /* buildConfigurationMnemonic= */ "dummy-configuration-mnemonic", /* configurationChecksum= */ "dummy-configuration", new BuildConfigurationEvent( BuildEventStreamProtos.BuildEventId.getDefaultInstance(), @@ -231,7 +231,7 @@ public void testBuilderWithJarExecutable() throws Exception { @Test public void testBuilderWithJarExecutableAndParameterFile2() throws Exception { - useConfiguration("--min_param_file_size=0", "--defer_param_files"); + useConfiguration("--min_param_file_size=0"); collectingAnalysisEnvironment = new AnalysisTestUtil.CollectingAnalysisEnvironment(getTestAnalysisEnvironment()); Artifact output = getBinArtifactWithNoOwner("output"); @@ -320,27 +320,6 @@ public void testMultipleCommandLines() throws Exception { assertThat(action.getArguments()).containsExactly("/bin/xxx", "arg1", "arg2").inOrder(); } - @Test - public void testGetArgumentsWithParameterFiles() throws Exception { - useConfiguration("--min_param_file_size=0", "--nodefer_param_files"); - Artifact input = getSourceArtifact("input"); - Artifact output = getBinArtifactWithNoOwner("output"); - SpawnAction action = - builder() - .addInput(input) - .addOutput(output) - .setExecutable(scratch.file("/bin/xxx").asFragment()) - .addCommandLine( - CommandLine.of(ImmutableList.of("arg1")), - ParamFileInfo.builder(ParameterFileType.UNQUOTED).build()) - .addCommandLine( - CommandLine.of(ImmutableList.of("arg2")), - ParamFileInfo.builder(ParameterFileType.UNQUOTED).build()) - .build(nullOwnerWithTargetConfig(), targetConfig); - // getArguments returns all arguments, regardless whether some go in parameter files or not - assertThat(action.getArguments()).containsExactly("/bin/xxx", "arg1", "arg2").inOrder(); - } - @Test public void testExtraActionInfo() throws Exception { SpawnAction action = createCopyFromWelcomeToDestination(ImmutableMap.of()); diff --git a/src/test/java/com/google/devtools/build/lib/analysis/test/TrimTestConfigurationTest.java b/src/test/java/com/google/devtools/build/lib/analysis/test/TrimTestConfigurationTest.java index da71995249209d..f665dd5d7e8c38 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/test/TrimTestConfigurationTest.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/test/TrimTestConfigurationTest.java @@ -22,12 +22,15 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.ImmutableSet; import com.google.devtools.build.lib.actions.ActionLookupKey; +import com.google.devtools.build.lib.actions.ActionLookupKeyOrProxy; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ArtifactOwner; import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.ConfiguredTargetValue; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.analysis.RuleContext; @@ -45,6 +48,7 @@ import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; +import com.google.devtools.build.skyframe.MemoizingEvaluator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; @@ -137,7 +141,7 @@ public void setUp() throws Exception { } private static void assertNumberOfConfigurationsOfTargets( - Set keys, Map targetsWithCounts) { + Set keys, Map targetsWithCounts) { ImmutableMultiset

Unconditionally includes all fragments. - */ - public BuildConfigurationValue getConfigurationForTesting( - Target target, BuildConfigurationValue config, ExtendedEventHandler eventHandler) - throws InvalidConfigurationException, InterruptedException { - List node = - ImmutableList.of(new TargetAndConfiguration(target, config)); - Collection configs = - ConfigurationResolver.getConfigurationsFromExecutor( - node, - AnalysisUtils.targetsToDeps(new LinkedHashSet<>(node), ruleClassProvider), - eventHandler, - skyframeExecutor) - .getTargetsAndConfigs(); - return configs.iterator().next().getConfiguration(); - } - /** * Sets the possible artifact roots in the artifact factory. This allows the factory to resolve * paths with unknown roots to artifacts. @@ -425,7 +402,7 @@ private OrderedSetMultimap getPrerequis eventHandler, new PrerequisiteParameters( ConfiguredTargetKey.fromConfiguredTarget(target), - state.targetAndConfiguration.getTarget().getAssociatedRule(), + state.targetAndConfiguration.getTarget(), /* aspects= */ ImmutableList.of(), skyframeBuildView.getStarlarkTransitionCache(), toolchainContexts, diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java index 4a99b4399886f7..c5866037394013 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java @@ -2006,17 +2006,11 @@ protected BuildConfigurationValue getConfiguration( } private BuildConfigurationValue getConfiguration(String label) { - BuildConfigurationValue config; try { - config = getConfiguration(getConfiguredTarget(label)); - config = view.getConfigurationForTesting(getTarget(label), config, reporter); + return getConfiguration(getConfiguredTarget(label)); } catch (LabelSyntaxException e) { throw new IllegalArgumentException(e); - } catch (Exception e) { - // TODO(b/36585204): Clean this up - throw new RuntimeException(e); } - return config; } protected final BuildConfigurationValue getConfiguration(BuildConfigurationKey configurationKey) { diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultTestCase.java b/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultTestCase.java index 65359679eeb7a1..b50e80e7538040 100644 --- a/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultTestCase.java @@ -202,156 +202,6 @@ public void testFailedTargetWithSaveTemps() throws Exception { assertThat(stderr).contains("See temp at blaze-bin/bad_clib/_objs/bad_clib/badlib.pic.ii\n"); } - @Test - public void testSymlinkOutputAtCwdUnderWorkspace_withFlagOn() throws Exception { - write("my_clib/BUILD", "cc_library(name='my_clib', srcs=['myclib.cc'])\n"); - write("my_clib/myclib.cc", "void f() {}"); - - addOptions( - "--print_workspace_in_output_paths_if_needed", - "--client_cwd=" + getWorkspace().getChild("my_clib").getPathString()); - build(false, "no-error", "//my_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //my_clib:my_clib up-to-date:\n"); - assertThat(stderr) - .contains(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.so") + "\n"); - assertThat(stderr) - .contains(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.a") + "\n"); - } - - @Test - public void testSymlinkOutputAtCwdUnderWorkspace_withFlagOff() throws Exception { - write("my_clib/BUILD", "cc_library(name='my_clib', srcs=['myclib.cc'])\n"); - write("my_clib/myclib.cc", "void f() {}"); - - addOptions( - "--noprint_workspace_in_output_paths_if_needed", - "--client_cwd=" + getWorkspace().getChild("my_clib").getPathString()); - build(false, "no-error", "//my_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //my_clib:my_clib up-to-date:\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.so") + "\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.a") + "\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.so\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.a\n"); - } - - @Test - public void testSymlinkOutputAtCwdEqualWorkspace_withFlagOn() throws Exception { - write("my_clib/BUILD", "cc_library(name='my_clib', srcs=['myclib.cc'])\n"); - write("my_clib/myclib.cc", "void f() {}"); - - addOptions("--print_workspace_in_output_paths_if_needed"); - build(false, "no-error", "//my_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //my_clib:my_clib up-to-date:\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.so") + "\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.a") + "\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.so\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.a\n"); - } - - @Test - public void testSymlinkPrefixAtCwdEqualWorkspace_withFlagOff() throws Exception { - write("my_clib/BUILD", "cc_library(name='my_clib', srcs=['myclib.cc'])\n"); - write("my_clib/myclib.cc", "void f() {}"); - - addOptions("--noprint_workspace_in_output_paths_if_needed"); - build(false, "no-error", "//my_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //my_clib:my_clib up-to-date:\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.so") + "\n"); - assertThat(stderr) - .doesNotContain(getWorkspace().getRelative("blaze-bin/my_clib/libmy_clib.a") + "\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.so\n"); - assertThat(stderr).contains("blaze-bin/my_clib/libmy_clib.a\n"); - } - - @Test - public void testSeeTempAtCwdUnderWorkspace_withFlagOn() throws Exception { - write("bad_clib/BUILD", "cc_library(name='bad_clib', srcs=['badlib.cc'])\n"); - // trigger a warning to make the build fail: - // "control reaches end of non-void function [-Werror,-Wreturn-type]" - write("bad_clib/badlib.cc", "int f() { }"); - - // We need to set --keep_going so that the temps get built even though the compilation fails. - addOptions( - "--save_temps", - "--keep_going", - "--print_workspace_in_output_paths_if_needed", - "--client_cwd=" + getWorkspace().getChild("bad_clib").getPathString()); - build(true, "compilation of rule '//bad_clib:bad_clib' failed", "//bad_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //bad_clib:bad_clib failed to build"); - assertThat(stderr) - .contains( - "See temp at " - + getWorkspace().getRelative("blaze-bin/bad_clib/_objs/bad_clib/badlib.pic.ii") - + "\n"); - } - - @Test - public void testSeeTempAtCwdUnderWorkspace_withFlagOff() throws Exception { - write("bad_clib/BUILD", "cc_library(name='bad_clib', srcs=['badlib.cc'])\n"); - // trigger a warning to make the build fail: - // "control reaches end of non-void function [-Werror,-Wreturn-type]" - write("bad_clib/badlib.cc", "int f() { }"); - - // We need to set --keep_going so that the temps get built even though the compilation fails. - addOptions( - "--save_temps", - "--keep_going", - "--noprint_workspace_in_output_paths_if_needed", - "--client_cwd=" + getWorkspace().getChild("bad_clib").getPathString()); - build(true, "compilation of rule '//bad_clib:bad_clib' failed", "//bad_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //bad_clib:bad_clib failed to build"); - assertThat(stderr).contains("See temp at blaze-bin/bad_clib/_objs/bad_clib/badlib.pic.ii\n"); - } - - @Test - public void testSeeTempAtCwdEqualWorkspace_withFlagOn() throws Exception { - write("bad_clib/BUILD", "cc_library(name='bad_clib', srcs=['badlib.cc'])\n"); - // trigger a warning to make the build fail: - // "control reaches end of non-void function [-Werror,-Wreturn-type]" - write("bad_clib/badlib.cc", "int f() { }"); - - // We need to set --keep_going so that the temps get built even though the compilation fails. - addOptions("--save_temps", "--keep_going", "--print_workspace_in_output_paths_if_needed"); - build(true, "compilation of rule '//bad_clib:bad_clib' failed", "//bad_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //bad_clib:bad_clib failed to build"); - assertThat(stderr).contains("See temp at blaze-bin/bad_clib/_objs/bad_clib/badlib.pic.ii\n"); - } - - @Test - public void testSeeTempAtCwdEqualWorkspace_withFlagOff() throws Exception { - write("bad_clib/BUILD", "cc_library(name='bad_clib', srcs=['badlib.cc'])\n"); - // trigger a warning to make the build fail: - // "control reaches end of non-void function [-Werror,-Wreturn-type]" - write("bad_clib/badlib.cc", "int f() { }"); - - // We need to set --keep_going so that the temps get built even though the compilation fails. - addOptions("--save_temps", "--keep_going", "--noprint_workspace_in_output_paths_if_needed"); - build(true, "compilation of rule '//bad_clib:bad_clib' failed", "//bad_clib"); - - String stderr = recOutErr.errAsLatin1(); - assertThat(stderr).contains("Target //bad_clib:bad_clib failed to build"); - assertThat(stderr).contains("See temp at blaze-bin/bad_clib/_objs/bad_clib/badlib.pic.ii\n"); - } - // Concrete implementations of this abstract test: /** Tests with 1 job. */ diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/BUILD b/src/test/java/com/google/devtools/build/lib/cmdline/BUILD index 94ea4e6b45f90b..4c67386a6584b6 100644 --- a/src/test/java/com/google/devtools/build/lib/cmdline/BUILD +++ b/src/test/java/com/google/devtools/build/lib/cmdline/BUILD @@ -50,7 +50,6 @@ java_test( java_test( name = "LabelInternerIntegrationTest", srcs = ["LabelInternerIntegrationTest.java"], - jvm_flags = ["-DBAZEL_USE_POOLED_LABEL_INTERNER=1"], deps = [ "//src/main/java/com/google/devtools/build/lib/cmdline", "//src/main/java/com/google/devtools/build/lib/concurrent", diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/LabelInternerIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/LabelInternerIntegrationTest.java index 65c588b69ed475..41f0ef54aeaa29 100644 --- a/src/test/java/com/google/devtools/build/lib/cmdline/LabelInternerIntegrationTest.java +++ b/src/test/java/com/google/devtools/build/lib/cmdline/LabelInternerIntegrationTest.java @@ -15,11 +15,13 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.truth.Truth.assertThat; +import static java.util.stream.Collectors.toCollection; import static org.junit.Assume.assumeFalse; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Interner; import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import com.google.devtools.build.lib.analysis.util.AnalysisMock; import com.google.devtools.build.lib.buildtool.util.SkyframeIntegrationTestBase; import com.google.devtools.build.lib.cmdline.Label.LabelInterner; @@ -33,6 +35,7 @@ import com.google.devtools.build.skyframe.QueryableGraph.Reason; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -173,6 +176,47 @@ public void labelInterner_removeDirtyPackageStillWeakInternItsLabels() throws Ex .isSameInstanceAs(l)); } + /** + * This test case addresses b/289354550. + * + *

Label interner can sometimes be disabled when blaze does not use {@link InMemoryGraph}. This + * test case deliberately disables label interner and check identical label are always weak + * interned. + */ + @Test + public void labelInterner_alwaysRespectWeakInternerWhenLabelInternerDisabled() throws Exception { + write("hello/BUILD", "genrule(name = 'foo', outs = ['out'], cmd = '/bin/echo hello > $@')"); + // Deliberately set label interner's global pool to null to disable labelInterner. + LabelInterner.setGlobalPool(null); + assertThat(labelInterner.enabled()).isFalse(); + + // Target label //hello:foo is definitely created when build hello:foo target. So create it + // before target build to ensure it is stored in weak interner. + Label preBuildLabel = Label.parseCanonical("//hello:foo"); + buildTarget("//hello:foo"); + + InMemoryGraph graph = skyframeExecutor().getEvaluator().getInMemoryGraph(); + PackageIdentifier packageKey = PackageIdentifier.createInMainRepo(/* name= */ "hello"); + NodeEntry nodeEntry = graph.get(/* requestor= */ null, Reason.OTHER, packageKey); + assertThat(nodeEntry).isNotNull(); + + Set