Search in sources :

Example 1 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class BuildTool method buildTargets.

/**
   * The crux of the build system. Builds the targets specified in the request using the specified
   * Executor.
   *
   * <p>Performs loading, analysis and execution for the specified set of targets, honoring the
   * configuration options in the BuildRequest. Returns normally iff successful, throws an exception
   * otherwise.
   *
   * <p>Callers must ensure that {@link #stopRequest} is called after this method, even if it
   * throws.
   *
   * <p>The caller is responsible for setting up and syncing the package cache.
   *
   * <p>During this function's execution, the actualTargets and successfulTargets
   * fields of the request object are set.
   *
   * @param request the build request that this build tool is servicing, which specifies various
   *        options; during this method's execution, the actualTargets and successfulTargets fields
   *        of the request object are populated
   * @param result the build result that is the mutable result of this build
   * @param validator target validator
   */
public void buildTargets(BuildRequest request, BuildResult result, TargetValidator validator) throws BuildFailedException, InterruptedException, ViewCreationFailedException, TargetParsingException, LoadingFailedException, AbruptExitException, InvalidConfigurationException, TestExecException {
    validateOptions(request);
    BuildOptions buildOptions = runtime.createBuildOptions(request);
    // Sync the package manager before sending the BuildStartingEvent in runLoadingPhase()
    env.setupPackageCache(request, DefaultsPackage.getDefaultsPackageContent(buildOptions));
    ExecutionTool executionTool = null;
    boolean catastrophe = false;
    try {
        env.getEventBus().post(new BuildStartingEvent(env, request));
        LOG.info("Build identifier: " + request.getId());
        executionTool = new ExecutionTool(env, request);
        if (needsExecutionPhase(request.getBuildOptions())) {
            // Initialize the execution tool early if we need it. This hides the latency of setting up
            // the execution backends.
            executionTool.init();
        }
        // Error out early if multi_cpus is set, but we're not in build or test command.
        if (!request.getMultiCpus().isEmpty()) {
            getReporter().handle(Event.warn("The --experimental_multi_cpu option is _very_ experimental and only intended for " + "internal testing at this time. If you do not work on the build tool, then you " + "should stop now!"));
            if (!"build".equals(request.getCommandName()) && !"test".equals(request.getCommandName())) {
                throw new InvalidConfigurationException("The experimental setting to select multiple CPUs is only supported for 'build' and " + "'test' right now!");
            }
        }
        // Exit if there are any pending exceptions from modules.
        env.throwPendingException();
        // Target pattern evaluation.
        LoadingResult loadingResult = evaluateTargetPatterns(request, validator);
        // Exit if there are any pending exceptions from modules.
        env.throwPendingException();
        // Configuration creation.
        BuildConfigurationCollection configurations = env.getSkyframeExecutor().createConfigurations(env.getReporter(), runtime.getConfigurationFactory(), buildOptions, request.getMultiCpus(), request.getViewOptions().keepGoing);
        env.throwPendingException();
        if (configurations.getTargetConfigurations().size() == 1) {
            // TODO(bazel-team): This is not optimal - we retain backwards compatibility in the case
            // where there's only a single configuration, but we don't send an event in the multi-config
            // case. Can we do better? [multi-config]
            env.getEventBus().post(new MakeEnvironmentEvent(configurations.getTargetConfigurations().get(0).getMakeEnvironment()));
        }
        LOG.info("Configurations created");
        if (request.getBuildOptions().performAnalysisPhase) {
            AnalysisResult analysisResult = runAnalysisPhase(request, loadingResult, configurations);
            result.setBuildConfigurationCollection(configurations);
            result.setActualTargets(analysisResult.getTargetsToBuild());
            result.setTestTargets(analysisResult.getTargetsToTest());
            LoadedPackageProvider bridge = new LoadedPackageProvider(env.getPackageManager(), env.getReporter());
            checkTargetEnvironmentRestrictions(analysisResult.getTargetsToBuild(), bridge);
            reportTargets(analysisResult);
            // Execution phase.
            if (needsExecutionPhase(request.getBuildOptions())) {
                executionTool.executeBuild(request.getId(), analysisResult, result, configurations, analysisResult.getPackageRoots(), request.getTopLevelArtifactContext());
            }
            String delayedErrorMsg = analysisResult.getError();
            if (delayedErrorMsg != null) {
                throw new BuildFailedException(delayedErrorMsg);
            }
        } else {
            getReporter().handle(Event.progress("Loading complete."));
            LOG.info("No analysis requested, so finished");
            String errorMessage = BuildView.createErrorMessage(loadingResult, null);
            if (errorMessage != null) {
                throw new BuildFailedException(errorMessage);
            }
        // Return.
        }
    } catch (RuntimeException e) {
        // Print an error message for unchecked runtime exceptions. This does not concern Error
        // subclasses such as OutOfMemoryError.
        request.getOutErr().printErrLn("Unhandled exception thrown during build; message: " + e.getMessage());
        catastrophe = true;
        throw e;
    } catch (Error e) {
        catastrophe = true;
        throw e;
    } catch (InvalidConfigurationException e) {
        // TODO(gregce): With "global configurations" we cannot tie a configuration creation failure
        // to a single target and have to halt the entire build. Once configurations are genuinely
        // created as part of the analysis phase they should report their error on the level of the
        // target(s) that triggered them.
        catastrophe = true;
        throw e;
    } finally {
        if (!catastrophe) {
            // Delete dirty nodes to ensure that they do not accumulate indefinitely.
            long versionWindow = request.getViewOptions().versionWindowForDirtyNodeGc;
            if (versionWindow != -1) {
                env.getSkyframeExecutor().deleteOldNodes(versionWindow);
            }
            if (executionTool != null) {
                executionTool.shutdown();
            }
            // The workspace status actions will not run with certain flags, or if an error
            // occurs early in the build. Tell a lie so that the event is not missing.
            // If multiple build_info events are sent, only the first is kept, so this does not harm
            // successful runs (which use the workspace status action).
            env.getEventBus().post(new BuildInfoEvent(env.getBlazeWorkspace().getWorkspaceStatusActionFactory().createDummyWorkspaceStatus()));
        }
    }
}
Also used : BuildStartingEvent(com.google.devtools.build.lib.buildtool.buildevent.BuildStartingEvent) MakeEnvironmentEvent(com.google.devtools.build.lib.analysis.MakeEnvironmentEvent) LoadedPackageProvider(com.google.devtools.build.lib.pkgcache.LoadedPackageProvider) AnalysisResult(com.google.devtools.build.lib.analysis.BuildView.AnalysisResult) InvalidConfigurationException(com.google.devtools.build.lib.analysis.config.InvalidConfigurationException) LoadingResult(com.google.devtools.build.lib.pkgcache.LoadingResult) BuildFailedException(com.google.devtools.build.lib.actions.BuildFailedException) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) BuildInfoEvent(com.google.devtools.build.lib.analysis.BuildInfoEvent) BuildConfigurationCollection(com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection)

Example 2 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class CrosstoolConfigurationIdentifier method fromOptions.

/**
   * Creates a new crosstool configuration from the given crosstool release and
   * configuration options.
   */
public static CrosstoolConfigurationIdentifier fromOptions(BuildOptions buildOptions) {
    Options options = buildOptions.get(BuildConfiguration.Options.class);
    CppOptions cppOptions = buildOptions.get(CppOptions.class);
    return new CrosstoolConfigurationIdentifier(options.cpu, cppOptions.cppCompiler, cppOptions.glibc);
}
Also used : BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) Options(com.google.devtools.build.lib.analysis.config.BuildConfiguration.Options)

Example 3 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions 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);
            }
        }
    }
}
Also used : BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) Attribute(com.google.devtools.build.lib.packages.Attribute) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) Label(com.google.devtools.build.lib.cmdline.Label) LateBoundDefault(com.google.devtools.build.lib.packages.Attribute.LateBoundDefault)

Example 4 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class ConfiguredTargetFunction method getDynamicTransitionOptions.

/**
   * Applies a dynamic configuration transition over a set of build options.
   *
   * @return the build options for the transitioned configuration. If trimResults is true,
   *     only options needed by the required fragments are included. Else the same options as the
   *     original input are included (with different possible values, of course).
   */
static List<BuildOptions> getDynamicTransitionOptions(BuildOptions fromOptions, Attribute.Transition transition, Iterable<Class<? extends BuildConfiguration.Fragment>> requiredFragments, RuleClassProvider ruleClassProvider, boolean trimResults) {
    List<BuildOptions> result;
    if (transition == Attribute.ConfigurationTransition.NONE) {
        result = ImmutableList.<BuildOptions>of(fromOptions);
    } else if (transition instanceof PatchTransition) {
        // TODO(bazel-team): safety-check that this never mutates fromOptions.
        result = ImmutableList.<BuildOptions>of(((PatchTransition) transition).apply(fromOptions));
    } else if (transition instanceof Attribute.SplitTransition) {
        // Attribute.java doesn't have the BuildOptions symbol.
        @SuppressWarnings("unchecked") List<BuildOptions> toOptions = ((Attribute.SplitTransition<BuildOptions>) transition).split(fromOptions);
        if (toOptions.isEmpty()) {
            // When the split returns an empty list, it's signaling it doesn't apply to this instance.
            // Check that it's safe to skip the transition and return the original options.
            Verify.verify(transition.defaultsToSelf());
            result = ImmutableList.<BuildOptions>of(fromOptions);
        } else {
            result = toOptions;
        }
    } else {
        throw new IllegalStateException(String.format("unsupported dynamic transition type: %s", transition.getClass().getName()));
    }
    if (!trimResults) {
        return result;
    } else {
        ImmutableList.Builder<BuildOptions> trimmedOptions = ImmutableList.builder();
        for (BuildOptions toOptions : result) {
            trimmedOptions.add(toOptions.trim(BuildConfiguration.getOptionsClasses(requiredFragments, ruleClassProvider)));
        }
        return trimmedOptions.build();
    }
}
Also used : BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) ImmutableList(com.google.common.collect.ImmutableList) PatchTransition(com.google.devtools.build.lib.analysis.config.PatchTransition)

Example 5 with BuildOptions

use of com.google.devtools.build.lib.analysis.config.BuildOptions in project bazel by bazelbuild.

the class ConfigurationCollectionFunction method getHostConfiguration.

/** Returns the host configuration, or null on missing Skyframe deps. */
private BuildConfiguration getHostConfiguration(Environment env, BuildConfiguration targetConfiguration) throws InvalidConfigurationException, InterruptedException {
    if (targetConfiguration.useDynamicConfigurations()) {
        BuildOptions targetOptions = targetConfiguration.getOptions();
        BuildOptions hostOptions = targetOptions.get(BuildConfiguration.Options.class).useDistinctHostConfiguration ? HostTransition.INSTANCE.apply(targetConfiguration.getOptions()) : targetOptions;
        SkyKey hostConfigKey = BuildConfigurationValue.key(targetConfiguration.trimConfigurations() ? targetConfiguration.fragmentClasses() : ((ConfiguredRuleClassProvider) ruleClassProvider).getAllFragments(), hostOptions);
        BuildConfigurationValue skyValHost = (BuildConfigurationValue) env.getValueOrThrow(hostConfigKey, InvalidConfigurationException.class);
        // Also preload the target configuration so the configured target functions for
        // top-level targets don't have to waste cycles from a missing Skyframe dep.
        SkyKey targetConfigKey = BuildConfigurationValue.key(targetConfiguration.fragmentClasses(), targetOptions);
        BuildConfigurationValue skyValTarget = (BuildConfigurationValue) env.getValueOrThrow(targetConfigKey, InvalidConfigurationException.class);
        if (skyValHost == null || skyValTarget == null) {
            return null;
        }
        return skyValHost.getConfiguration();
    } else {
        return targetConfiguration.getConfiguration(Attribute.ConfigurationTransition.HOST);
    }
}
Also used : BuildConfiguration(com.google.devtools.build.lib.analysis.config.BuildConfiguration) SkyKey(com.google.devtools.build.skyframe.SkyKey) BuildOptions(com.google.devtools.build.lib.analysis.config.BuildOptions) ConfiguredRuleClassProvider(com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider) InvalidConfigurationException(com.google.devtools.build.lib.analysis.config.InvalidConfigurationException)

Aggregations

BuildOptions (com.google.devtools.build.lib.analysis.config.BuildOptions)23 BuildConfiguration (com.google.devtools.build.lib.analysis.config.BuildConfiguration)12 ImmutableList (com.google.common.collect.ImmutableList)6 InvalidConfigurationException (com.google.devtools.build.lib.analysis.config.InvalidConfigurationException)4 SkyKey (com.google.devtools.build.skyframe.SkyKey)4 ArrayList (java.util.ArrayList)4 Dependency (com.google.devtools.build.lib.analysis.Dependency)3 Label (com.google.devtools.build.lib.cmdline.Label)3 Attribute (com.google.devtools.build.lib.packages.Attribute)3 HashSet (java.util.HashSet)3 ImmutableMap (com.google.common.collect.ImmutableMap)2 ImmutableSet (com.google.common.collect.ImmutableSet)2 Options (com.google.devtools.build.lib.analysis.config.BuildConfiguration.Options)2 BuildConfigurationCollection (com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection)2 PatchTransition (com.google.devtools.build.lib.analysis.config.PatchTransition)2 InvocationPolicyEnforcer (com.google.devtools.build.lib.flags.InvocationPolicyEnforcer)2 SplitTransition (com.google.devtools.build.lib.packages.Attribute.SplitTransition)2 LoadingResult (com.google.devtools.build.lib.pkgcache.LoadingResult)2 PackageCacheOptions (com.google.devtools.build.lib.pkgcache.PackageCacheOptions)2 ValueOrException (com.google.devtools.build.skyframe.ValueOrException)2