Ejemplo n.º 1
0
 private final BuildConfigurationCollection getConfigurations(
     BuildOptions buildOptions, Set<String> multiCpu, boolean keepGoing)
     throws InvalidConfigurationException, InterruptedException {
   SkyframeExecutor executor = runtime.getSkyframeExecutor();
   // TODO(bazel-team): consider a possibility of moving ConfigurationFactory construction into
   // skyframe.
   return executor.createConfigurations(
       runtime.getConfigurationFactory(),
       buildOptions,
       runtime.getDirectories(),
       multiCpu,
       keepGoing);
 }
Ejemplo n.º 2
0
  /**
   * 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, LocalEnvironmentException, InterruptedException,
          ViewCreationFailedException, TargetParsingException, LoadingFailedException,
          ExecutorInitException, AbruptExitException, InvalidConfigurationException,
          TestExecException {
    validateOptions(request);
    BuildOptions buildOptions = runtime.createBuildOptions(request);
    // Sync the package manager before sending the BuildStartingEvent in runLoadingPhase()
    runtime.setupPackageCache(
        request.getPackageCacheOptions(), DefaultsPackage.getDefaultsPackageContent(buildOptions));

    ExecutionTool executionTool = null;
    LoadingResult loadingResult = null;
    BuildConfigurationCollection configurations = null;
    try {
      getEventBus().post(new BuildStartingEvent(runtime.getOutputFileSystem(), request));
      LOG.info("Build identifier: " + request.getId());
      executionTool = new ExecutionTool(runtime, 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();
      }

      // Loading phase.
      loadingResult = runLoadingPhase(request, validator);

      // Create the build configurations.
      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!");
        }
      }
      configurations =
          getConfigurations(
              buildOptions, request.getMultiCpus(), request.getViewOptions().keepGoing);

      getEventBus().post(new ConfigurationsCreatedEvent(configurations));
      runtime.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]
        getEventBus()
            .post(
                new MakeEnvironmentEvent(
                    configurations.getTargetConfigurations().get(0).getMakeEnvironment()));
      }
      LOG.info("Configurations created");

      // Analysis phase.
      AnalysisResult analysisResult = runAnalysisPhase(request, loadingResult, configurations);
      result.setActualTargets(analysisResult.getTargetsToBuild());
      result.setTestTargets(analysisResult.getTargetsToTest());

      checkTargetEnvironmentRestrictions(
          analysisResult.getTargetsToBuild(), runtime.getPackageManager());
      reportTargets(analysisResult);

      // Execution phase.
      if (needsExecutionPhase(request.getBuildOptions())) {
        runtime.getSkyframeExecutor().injectTopLevelContext(request.getTopLevelArtifactContext());
        executionTool.executeBuild(
            request.getId(),
            analysisResult,
            result,
            runtime.getSkyframeExecutor(),
            configurations,
            transformPackageRoots(loadingResult.getPackageRoots()));
      }

      String delayedErrorMsg = analysisResult.getError();
      if (delayedErrorMsg != null) {
        throw new BuildFailedException(delayedErrorMsg);
      }
    } 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());
      throw e;
    } finally {
      // Delete dirty nodes to ensure that they do not accumulate indefinitely.
      long versionWindow = request.getViewOptions().versionWindowForDirtyNodeGc;
      if (versionWindow != -1) {
        runtime.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).
      getEventBus()
          .post(
              new BuildInfoEvent(
                  runtime.getworkspaceStatusActionFactory().createDummyWorkspaceStatus()));
    }

    if (loadingResult != null && loadingResult.hasTargetPatternError()) {
      throw new BuildFailedException(
          "execution phase successful, but there were errors " + "parsing the target pattern");
    }
  }