use of com.google.devtools.build.lib.analysis.config.BuildConfiguration in project bazel by bazelbuild.
the class DependencyResolver method visitRule.
private void visitRule(TargetAndConfiguration node, BuildConfiguration hostConfig, Iterable<Aspect> aspects, ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Label> rootCauses, OrderedSetMultimap<Attribute, Dependency> outgoingEdges) throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException, InterruptedException {
Preconditions.checkArgument(node.getTarget() instanceof Rule);
BuildConfiguration ruleConfig = Preconditions.checkNotNull(node.getConfiguration());
Rule rule = (Rule) node.getTarget();
ConfiguredAttributeMapper attributeMap = ConfiguredAttributeMapper.of(rule, configConditions);
attributeMap.validateAttributes();
RuleResolver depResolver = new RuleResolver(rule, ruleConfig, aspects, attributeMap, rootCauses, outgoingEdges);
visitTargetVisibility(node, rootCauses, outgoingEdges.get(null));
resolveEarlyBoundAttributes(depResolver);
resolveLateBoundAttributes(depResolver, ruleConfig, hostConfig);
}
use of com.google.devtools.build.lib.analysis.config.BuildConfiguration in project bazel by bazelbuild.
the class DependencyResolver method resolveLateBoundAttribute.
/**
* Returns the label dependencies for the given late-bound attribute in this rule.
*
* @param rule the rule being evaluated
* @param attribute the attribute to evaluate
* @param config the configuration to evaluate the attribute in
* @param attributeMap mapper to attribute values
*/
private Iterable<Label> resolveLateBoundAttribute(Rule rule, Attribute attribute, BuildConfiguration config, AttributeMap attributeMap) throws EvalException, InterruptedException {
Preconditions.checkArgument(attribute.isLateBound());
@SuppressWarnings("unchecked") LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault();
// TODO(bazel-team): This might be too expensive - can we cache this somehow?
if (!lateBoundDefault.getRequiredConfigurationFragments().isEmpty()) {
if (!config.hasAllFragments(lateBoundDefault.getRequiredConfigurationFragments())) {
return ImmutableList.<Label>of();
}
}
// TODO(bazel-team): We should check if the implementation tries to access an undeclared
// fragment.
Object actualValue = lateBoundDefault.resolve(rule, attributeMap, config);
if (EvalUtils.isNullOrNone(actualValue)) {
return ImmutableList.<Label>of();
}
try {
ImmutableList.Builder<Label> deps = ImmutableList.builder();
if (attribute.getType() == BuildType.LABEL) {
deps.add(rule.getLabel().resolveRepositoryRelative(BuildType.LABEL.cast(actualValue)));
} else if (attribute.getType() == BuildType.LABEL_LIST) {
for (Label label : BuildType.LABEL_LIST.cast(actualValue)) {
deps.add(rule.getLabel().resolveRepositoryRelative(label));
}
} else {
throw new IllegalStateException(String.format("Late bound attribute '%s' is not a label or a label list", attribute.getName()));
}
return deps.build();
} catch (ClassCastException e) {
// From either of the cast calls above.
throw new EvalException(rule.getLocation(), String.format("When computing the default value of %s, expected '%s', got '%s'", attribute.getName(), attribute.getType(), EvalUtils.getDataTypeName(actualValue, true)));
}
}
use of com.google.devtools.build.lib.analysis.config.BuildConfiguration in project bazel by bazelbuild.
the class DependencyResolver method resolveLateBoundAttributes.
/**
* Resolves the dependencies for all late-bound attributes in this rule.
*
* <p>Late-bound attributes need special handling because they require configuration
* transitions to determine their values.
*
* <p>In other words, the normal process of dependency resolution is:
* <ol>
* <li>Find every label value in the rule's attributes</li>
* <li>Apply configuration transitions over each value to get its dep configuration
* <li>Return each value with its dep configuration</li>
* </ol>
*
* This doesn't work for late-bound attributes because you can't get their values without
* knowing the configuration first. And that configuration may not be the owning rule's
* configuration. Specifically, {@link LateBoundDefault#useHostConfiguration()} switches to the
* host config and late-bound split attributes branch into multiple split configs.
*
* <p>This method implements that logic and makes sure the normal configuration
* transition logic mixes with it cleanly.
*
* @param depResolver the resolver for this rule's deps
* @param ruleConfig the rule's configuration
* @param hostConfig the equivalent host configuration
*/
private void resolveLateBoundAttributes(RuleResolver depResolver, BuildConfiguration ruleConfig, BuildConfiguration hostConfig) throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException, InterruptedException {
ConfiguredAttributeMapper attributeMap = depResolver.attributeMap;
for (AttributeAndOwner attributeAndOwner : depResolver.attributes) {
Attribute attribute = attributeAndOwner.attribute;
if (!attribute.isLateBound() || !attribute.getCondition().apply(attributeMap)) {
continue;
}
@SuppressWarnings("unchecked") LateBoundDefault<BuildConfiguration> lateBoundDefault = (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault();
Collection<BuildOptions> splitOptions = getSplitOptions(depResolver.rule, attribute, ruleConfig);
if (!splitOptions.isEmpty()) {
// Late-bound attribute with a split transition:
// Since we want to get the same results as BuildConfiguration.evaluateTransition (but
// skip it since we've already applied the split), we want to make sure this logic
// doesn't do anything differently. evaluateTransition has additional logic
// for host configs and attributes with configurators. So we check here that neither of
// of those apply, in the name of keeping the fork as simple as possible.
Verify.verify(attribute.getConfigurator() == null);
Verify.verify(!lateBoundDefault.useHostConfiguration());
Iterable<BuildConfiguration> splitConfigs;
if (!ruleConfig.useDynamicConfigurations()) {
splitConfigs = ruleConfig.getSplitConfigurations(attribute.getSplitTransition(depResolver.rule));
} else {
splitConfigs = getConfigurations(ruleConfig.fragmentClasses(), splitOptions);
if (splitConfigs == null) {
// Need Skyframe deps.
continue;
}
}
for (BuildConfiguration splitConfig : splitConfigs) {
for (Label dep : resolveLateBoundAttribute(depResolver.rule, attribute, splitConfig, attributeMap)) {
// Skip the normal config transition pipeline and directly feed the split config. This
// is because the split already had to be applied to determine the attribute's value.
// This makes the split logic in the normal pipeline redundant and potentially
// incorrect.
depResolver.resolveDep(attributeAndOwner, dep, splitConfig);
}
}
} else {
// Late-bound attribute without a split transition:
for (Label dep : resolveLateBoundAttribute(depResolver.rule, attribute, lateBoundDefault.useHostConfiguration() ? hostConfig : ruleConfig, attributeMap)) {
// Process this dep like a normal attribute.
depResolver.resolveDep(attributeAndOwner, dep);
}
}
}
}
use of com.google.devtools.build.lib.analysis.config.BuildConfiguration in project bazel by bazelbuild.
the class RunCommand method exec.
@Override
public ExitCode exec(CommandEnvironment env, OptionsProvider options) {
RunOptions runOptions = options.getOptions(RunOptions.class);
// This list should look like: ["//executable:target", "arg1", "arg2"]
List<String> targetAndArgs = options.getResidue();
// The user must at the least specify an executable target.
if (targetAndArgs.isEmpty()) {
env.getReporter().handle(Event.error("Must specify a target to run"));
return ExitCode.COMMAND_LINE_ERROR;
}
String targetString = targetAndArgs.get(0);
List<String> runTargetArgs = targetAndArgs.subList(1, targetAndArgs.size());
RunUnder runUnder = options.getOptions(BuildConfiguration.Options.class).runUnder;
OutErr outErr = env.getReporter().getOutErr();
List<String> targets = (runUnder != null) && (runUnder.getLabel() != null) ? ImmutableList.of(targetString, runUnder.getLabel().toString()) : ImmutableList.of(targetString);
BuildRequest request = BuildRequest.create(this.getClass().getAnnotation(Command.class).name(), options, env.getRuntime().getStartupOptionsProvider(), targets, outErr, env.getCommandId(), env.getCommandStartTime());
currentRunUnder = runUnder;
BuildResult result;
try {
result = processRequest(env, request);
} finally {
currentRunUnder = null;
}
if (!result.getSuccess()) {
env.getReporter().handle(Event.error("Build failed. Not running target"));
return result.getExitCondition();
}
// Make sure that we have exactly 1 built target (excluding --run_under),
// and that it is executable.
// These checks should only fail if keepGoing is true, because we already did
// validation before the build began. See {@link #validateTargets()}.
Collection<ConfiguredTarget> targetsBuilt = result.getSuccessfulTargets();
ConfiguredTarget targetToRun = null;
ConfiguredTarget runUnderTarget = null;
if (targetsBuilt != null) {
int maxTargets = runUnder != null && runUnder.getLabel() != null ? 2 : 1;
if (targetsBuilt.size() > maxTargets) {
env.getReporter().handle(Event.error(SINGLE_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
for (ConfiguredTarget target : targetsBuilt) {
ExitCode targetValidation = fullyValidateTarget(env, target);
if (!targetValidation.equals(ExitCode.SUCCESS)) {
return targetValidation;
}
if (runUnder != null && target.getLabel().equals(runUnder.getLabel())) {
if (runUnderTarget != null) {
env.getReporter().handle(Event.error(null, "Can't identify the run_under target from multiple options?"));
return ExitCode.COMMAND_LINE_ERROR;
}
runUnderTarget = target;
} else if (targetToRun == null) {
targetToRun = target;
} else {
env.getReporter().handle(Event.error(SINGLE_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
}
}
// Handle target & run_under referring to the same target.
if ((targetToRun == null) && (runUnderTarget != null)) {
targetToRun = runUnderTarget;
}
if (targetToRun == null) {
env.getReporter().handle(Event.error(NO_TARGET_MESSAGE));
return ExitCode.COMMAND_LINE_ERROR;
}
Path executablePath = Preconditions.checkNotNull(targetToRun.getProvider(FilesToRunProvider.class).getExecutable().getPath());
BuildConfiguration configuration = targetToRun.getConfiguration();
if (configuration == null) {
// The target may be an input file, which doesn't have a configuration. In that case, we
// choose any target configuration.
configuration = result.getBuildConfigurationCollection().getTargetConfigurations().get(0);
}
Path workingDir;
try {
workingDir = ensureRunfilesBuilt(env, targetToRun);
} catch (CommandException e) {
env.getReporter().handle(Event.error("Error creating runfiles: " + e.getMessage()));
return ExitCode.LOCAL_ENVIRONMENTAL_ERROR;
}
List<String> args = runTargetArgs;
FilesToRunProvider provider = targetToRun.getProvider(FilesToRunProvider.class);
RunfilesSupport runfilesSupport = provider == null ? null : provider.getRunfilesSupport();
if (runfilesSupport != null && runfilesSupport.getArgs() != null) {
List<String> targetArgs = runfilesSupport.getArgs();
if (!targetArgs.isEmpty()) {
args = Lists.newArrayListWithCapacity(targetArgs.size() + runTargetArgs.size());
args.addAll(targetArgs);
args.addAll(runTargetArgs);
}
}
String productName = env.getRuntime().getProductName();
//
// We now have a unique executable ready to be run.
//
// We build up two different versions of the command to run: one with an absolute path, which
// we'll actually run, and a prettier one with the long absolute path to the executable
// replaced with a shorter relative path that uses the symlinks in the workspace.
PathFragment prettyExecutablePath = OutputDirectoryLinksUtils.getPrettyPath(executablePath, env.getWorkspaceName(), env.getWorkspace(), options.getOptions(BuildRequestOptions.class).getSymlinkPrefix(productName), productName);
List<String> cmdLine = new ArrayList<>();
if (runOptions.scriptPath == null) {
PathFragment processWrapperPath = env.getBlazeWorkspace().getBinTools().getExecPath(PROCESS_WRAPPER);
Preconditions.checkNotNull(processWrapperPath, PROCESS_WRAPPER + " not found in embedded tools");
cmdLine.add(env.getExecRoot().getRelative(processWrapperPath).getPathString());
cmdLine.add("-1");
cmdLine.add("15");
cmdLine.add("-");
cmdLine.add("-");
}
List<String> prettyCmdLine = new ArrayList<>();
// at the start of the command line.
if (runUnder != null) {
String runUnderValue = runUnder.getValue();
if (runUnderTarget != null) {
// --run_under specifies a target. Get the corresponding executable.
// This must be an absolute path, because the run_under target is only
// in the runfiles of test targets.
runUnderValue = runUnderTarget.getProvider(FilesToRunProvider.class).getExecutable().getPath().getPathString();
// If the run_under command contains any options, make sure to add them
// to the command line as well.
List<String> opts = runUnder.getOptions();
if (!opts.isEmpty()) {
runUnderValue += " " + ShellEscaper.escapeJoinAll(opts);
}
}
cmdLine.add(configuration.getShellExecutable().getPathString());
cmdLine.add("-c");
cmdLine.add(runUnderValue + " " + executablePath.getPathString() + " " + ShellEscaper.escapeJoinAll(args));
prettyCmdLine.add(configuration.getShellExecutable().getPathString());
prettyCmdLine.add("-c");
prettyCmdLine.add(runUnderValue + " " + prettyExecutablePath.getPathString() + " " + ShellEscaper.escapeJoinAll(args));
} else {
cmdLine.add(executablePath.getPathString());
cmdLine.addAll(args);
prettyCmdLine.add(prettyExecutablePath.getPathString());
prettyCmdLine.addAll(args);
}
// Add a newline between the blaze output and the binary's output.
outErr.printErrLn("");
if (runOptions.scriptPath != null) {
String unisolatedCommand = CommandFailureUtils.describeCommand(CommandDescriptionForm.COMPLETE_UNISOLATED, cmdLine, null, workingDir.getPathString());
if (writeScript(env, runOptions.scriptPath, unisolatedCommand)) {
return ExitCode.SUCCESS;
} else {
return ExitCode.RUN_FAILURE;
}
}
env.getReporter().handle(Event.info(null, "Running command line: " + ShellEscaper.escapeJoinAll(prettyCmdLine)));
com.google.devtools.build.lib.shell.Command command = new CommandBuilder().addArgs(cmdLine).setEnv(env.getClientEnv()).setWorkingDir(workingDir).build();
try {
// Restore a raw EventHandler if it is registered. This allows for blaze run to produce the
// actual output of the command being run even if --color=no is specified.
env.getReporter().switchToAnsiAllowingHandler();
// The command API is a little strange in that the following statement
// will return normally only if the program exits with exit code 0.
// If it ends with any other code, we have to catch BadExitStatusException.
command.execute(com.google.devtools.build.lib.shell.Command.NO_INPUT, com.google.devtools.build.lib.shell.Command.NO_OBSERVER, outErr.getOutputStream(), outErr.getErrorStream(), true).getTerminationStatus().getExitCode();
return ExitCode.SUCCESS;
} catch (BadExitStatusException e) {
String message = "Non-zero return code '" + e.getResult().getTerminationStatus().getExitCode() + "' from command: " + e.getMessage();
env.getReporter().handle(Event.error(message));
return ExitCode.RUN_FAILURE;
} catch (AbnormalTerminationException e) {
// The process was likely terminated by a signal in this case.
return ExitCode.INTERRUPTED;
} catch (CommandException e) {
env.getReporter().handle(Event.error("Error running program: " + e.getMessage()));
return ExitCode.RUN_FAILURE;
}
}
use of com.google.devtools.build.lib.analysis.config.BuildConfiguration in project bazel by bazelbuild.
the class ConfiguredTargetFunction method createConfiguredTarget.
@Nullable
private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view, Environment env, Target target, BuildConfiguration configuration, OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap, ImmutableMap<Label, ConfigMatchingProvider> configConditions, NestedSetBuilder<Package> transitivePackages) throws ConfiguredTargetFunctionException, InterruptedException {
StoredEventHandler events = new StoredEventHandler();
BuildConfiguration ownerConfig = (configuration == null) ? null : configuration.getArtifactOwnerConfiguration();
CachingAnalysisEnvironment analysisEnvironment = view.createAnalysisEnvironment(new ConfiguredTargetKey(target.getLabel(), ownerConfig), false, events, env, configuration);
if (env.valuesMissing()) {
return null;
}
Preconditions.checkNotNull(depValueMap);
ConfiguredTarget configuredTarget = view.createConfiguredTarget(target, configuration, analysisEnvironment, depValueMap, configConditions);
events.replayOn(env.getListener());
if (events.hasErrors()) {
analysisEnvironment.disable(target);
throw new ConfiguredTargetFunctionException(new ConfiguredValueCreationException("Analysis of target '" + target.getLabel() + "' failed; build aborted", target.getLabel()));
}
Preconditions.checkState(!analysisEnvironment.hasErrors(), "Analysis environment hasError() but no errors reported");
if (env.valuesMissing()) {
return null;
}
analysisEnvironment.disable(target);
Preconditions.checkNotNull(configuredTarget, target);
ImmutableMap<Artifact, ActionAnalysisMetadata> generatingActions;
// rule implementation).
try {
generatingActions = Actions.filterSharedActionsAndThrowActionConflict(analysisEnvironment.getRegisteredActions());
} catch (ActionConflictException e) {
throw new ConfiguredTargetFunctionException(e);
}
return new ConfiguredTargetValue(configuredTarget, generatingActions, transitivePackages.build());
}
Aggregations