@VisibleForTesting protected final LoadingResult runLoadingPhase( final BuildRequest request, final TargetValidator validator) throws LoadingFailedException, TargetParsingException, InterruptedException, AbruptExitException { Profiler.instance().markPhase(ProfilePhase.LOAD); runtime.throwPendingException(); initializeOutputFilter(request); final boolean keepGoing = request.getViewOptions().keepGoing; Callback callback = new Callback() { @Override public void notifyTargets(Collection<Target> targets) throws LoadingFailedException { if (validator != null) { validator.validateTargets(targets, keepGoing); } } @Override public void notifyVisitedPackages(Set<PackageIdentifier> visitedPackages) { runtime.getSkyframeExecutor().updateLoadedPackageSet(visitedPackages); } }; LoadingResult result = runtime .getLoadingPhaseRunner() .execute( getReporter(), getEventBus(), request.getTargets(), request.getLoadingOptions(), runtime.createBuildOptions(request).getAllLabels(), keepGoing, request.shouldRunTests(), callback); runtime.throwPendingException(); return result; }
/** * 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"); } }