예제 #1
0
파일: Target.cs 프로젝트: nikson/msbuild
        /// <summary>
        /// Builds this target if it has not already been built as part of its parent project. Before we actually execute the
        /// tasks for this target, though, we first call on all the dependent targets to build themselves.
        /// This function may throw InvalidProjectFileException
        /// </summary>
        internal void Build
        (
            ProjectBuildState buildContext
        )
        {
            // Depending on the build state, we may do different things.
            switch (buildState)
            {
                case BuildState.InProgress:
                    // In single proc mode if the build state was already "in progress" 
                    // and somebody just told us to build ourselves, it means that there is 
                    // a loop (circular dependency) in the target dependency graph. In multi
                    // proc mode we need to analyze the dependency graph before we can
                    // tell if there a circular dependency or if two independent chains
                    // of targets happen to need the result of this target.
                    if (parentEngine.Router.SingleThreadedMode || buildContext.ContainsCycle(this.Name))
                    {
                        ProjectErrorUtilities.VerifyThrowInvalidProject(false, TargetElement, "CircularDependency", targetName);
                    }
                    else
                    {
                        buildContext.CurrentBuildContextState = ProjectBuildState.BuildContextState.WaitingForTarget;
                        this.executionState.AddWaitingBuildContext(buildContext);
                    }
                    break;

                case BuildState.CompletedSuccessfully:
                case BuildState.CompletedUnsuccessfully:
                    // If this target has already been built as part of this project,
                    // we're not going to build it again.  Just return the result
                    // from when it was built previously.  Note:  This condition
                    // could really only ever hold true if the user specifically
                    // requested us to build multiple targets and there existed
                    // a direct or indirect dependency relationship between two or
                    // more of those top-level targets.
                    // Note: we aren't really entering the target in question here, so don't use the target
                    // event context. Using the target ID for skipped messages would force us to
                    // cache the individual target IDs for unloaded projects and it's not really worth the trouble.
                    // Just use the parent event context.
                    parentEngine.LoggingServices.LogComment(buildContext.ProjectBuildEventContext,
                        ((buildState == BuildState.CompletedSuccessfully) ? "TargetAlreadyCompleteSuccess" : "TargetAlreadyCompleteFailure"),
                        this.targetName);

                    // Only contexts which are generated from an MSBuild task could need 
                    // the outputs of this target, such contexts have a non-null evaluation
                    // request
                    if ((buildState == BuildState.CompletedSuccessfully) && 
                        (buildContext.BuildRequest.OutputsByTarget != null &&
                         buildContext.NameOfBlockingTarget == null))
                    {
                        error.VerifyThrow(
                            String.Compare(EscapingUtilities.UnescapeAll(buildContext.NameOfTargetInProgress), this.Name, StringComparison.OrdinalIgnoreCase) == 0,
                            "The name of the target in progress is inconsistent with the target being built");

                        error.VerifyThrow(targetOutputItems != null,
                            "If the target built successfully, we must have its outputs.");

                        buildContext.BuildRequest.OutputsByTarget[Name] = targetOutputItems.ToArray();
                    }

                    if (buildContext.NameOfBlockingTarget == null)
                    {
                        buildContext.BuildRequest.ResultByTarget[Name] = buildState;
                    }
                    break;

                case BuildState.NotStarted:
                case BuildState.Skipped:
                    {
                        // Always have to create a new context in build as other projects or targets may try and build this target
                        BuildEventContext targetBuildEventContext = new BuildEventContext
                                                        (
                                                            buildContext.ProjectBuildEventContext.NodeId,
                                                            this.id,
                                                            buildContext.ProjectBuildEventContext.ProjectContextId,
                                                            buildContext.ProjectBuildEventContext.TaskId
                                                        );

                        Expander expander = new Expander(this.parentProject.evaluatedProperties, this.parentProject.evaluatedItemsByName);

                        // We first make sure no batching was attempted with the target's condition.
                        if (!conditionCheckedForInvalidMetadataReferences)
                        {
                            if (ExpressionShredder.ContainsMetadataExpressionOutsideTransform(this.Condition))
                            {
                                ProjectErrorUtilities.ThrowInvalidProject(this.conditionAttribute, "TargetConditionHasInvalidMetadataReference", targetName, this.Condition);
                            }
                            conditionCheckedForInvalidMetadataReferences = true;
                        }

                        // If condition is false (based on propertyBag), set this target's state to
                        // "Skipped" since we won't actually build it.
                        if (!Utilities.EvaluateCondition(this.Condition, this.conditionAttribute,
                                expander, null, ParserOptions.AllowProperties | ParserOptions.AllowItemLists,
                                parentEngine.LoggingServices, targetBuildEventContext))
                        {
                            buildState = BuildState.Skipped;

                            if (buildContext.NameOfBlockingTarget == null)
                            {
                                buildContext.BuildRequest.ResultByTarget[Name] = buildState;
                            }

                            if (!parentEngine.LoggingServices.OnlyLogCriticalEvents)
                            {
                                // Expand the expression for the Log.
                                string expanded = expander.ExpandAllIntoString(this.Condition, this.conditionAttribute);
                                // By design: Not building dependencies. This is what NAnt does too.
                                parentEngine.LoggingServices.LogComment(targetBuildEventContext, "TargetSkippedFalseCondition",
                                                        this.targetName, this.Condition, expanded);
                            }
                        }
                        else
                        {
                            // This target has not been built yet.  So build it!
                            // Change our state to "in progress". TargetParameters will need to be re-calculated if Inputs and Outputs attribute has changed.
                            buildState = BuildState.InProgress;
                            List<string> batchableTargetParameters = GetBatchableTargetParameters();
                            executionState = new TargetExecutionWrapper(this, taskElementList, batchableTargetParameters, targetElement, expander, targetBuildEventContext);
                            ContinueBuild(buildContext, null);
                        }
                    }
                    break;
                default:
                    error.VerifyThrow(false, "Build state {0} not handled in Target.Build method", buildState);
                    break;
            }
        }
예제 #2
0
파일: Target.cs 프로젝트: nikson/msbuild
        /// <summary>
        /// Update the target data structures since the target has completed
        /// </summary>
        internal void UpdateTargetStateOnBuildCompletion
        (
            BuildState stateOfBuild, 
            List<BuildItem> targetOutputItemList
        )
        {
            this.buildState = stateOfBuild;
            this.targetOutputItems = targetOutputItemList;

            // Clear the execution state since the build is completed
            executionState = null;
        }