public void RemoveToolset()
        {
            ProjectCollection collection = new ProjectCollection();

            Toolset toolset1 = new Toolset("x", "c:\\y", collection, null);
            Toolset toolset2 = new Toolset("y", "c:\\z", collection, null);

            int initial = Helpers.MakeList<Toolset>(collection.Toolsets).Count;

            collection.AddToolset(toolset1);
            collection.AddToolset(toolset2);

            Assert.Equal(true, collection.RemoveToolset("x"));
            Assert.Equal(false, collection.ContainsToolset("x"));

            Assert.Equal(1, Helpers.MakeList<Toolset>(collection.Toolsets).Count - initial);
        }
Exemple #2
0
        internal static bool BuildProject
        (
            string projectFile,
            string[] targets,
            string toolsVersion,
            Dictionary<string, string> globalProperties,
            ILogger[] loggers,
            LoggerVerbosity verbosity,
            DistributedLoggerRecord[] distributedLoggerRecords,
            bool needToValidateProject,
            string schemaFile,
            int cpuCount,
            bool enableNodeReuse,
            TextWriter preprocessWriter,
            bool debugger,
            bool detailedSummary
        )
        {
            if (String.Equals(Path.GetExtension(projectFile), ".vcproj", StringComparison.OrdinalIgnoreCase) ||
                String.Equals(Path.GetExtension(projectFile), ".dsp", StringComparison.OrdinalIgnoreCase))
            {
                InitializationException.Throw(ResourceUtilities.FormatResourceString("ProjectUpgradeNeededToVcxProj", projectFile), null);
            }

            bool success = false;

            ProjectCollection projectCollection = null;
            bool onlyLogCriticalEvents = false;

            try
            {
                List<ForwardingLoggerRecord> remoteLoggerRecords = new List<ForwardingLoggerRecord>();
                foreach (DistributedLoggerRecord distRecord in distributedLoggerRecords)
                {
                    remoteLoggerRecords.Add(new ForwardingLoggerRecord(distRecord.CentralLogger, distRecord.ForwardingLoggerDescription));
                }

                // Targeted perf optimization for the case where we only have our own parallel console logger, and verbosity is quiet. In such a case
                // we know we won't emit any messages except for errors and warnings, so the engine should not bother even logging them.
                // If we're using the original serial console logger we can't do this, as it shows project started/finished context
                // around errors and warnings.
                // Telling the engine to not bother logging non-critical messages means that typically it can avoid loading any resources in the successful
                // build case.
                if (loggers.Length == 1 &&
                    remoteLoggerRecords.Count == 0 &&
                    verbosity == LoggerVerbosity.Quiet &&
                    loggers[0].Parameters != null &&
                    loggers[0].Parameters.IndexOf("ENABLEMPLOGGING", StringComparison.OrdinalIgnoreCase) != -1 &&
                    loggers[0].Parameters.IndexOf("DISABLEMPLOGGING", StringComparison.OrdinalIgnoreCase) == -1 &&
                    loggers[0].Parameters.IndexOf("V=", StringComparison.OrdinalIgnoreCase) == -1 &&                // Console logger could have had a verbosity
                    loggers[0].Parameters.IndexOf("VERBOSITY=", StringComparison.OrdinalIgnoreCase) == -1)          // override with the /clp switch
                {
                    // Must be exactly the console logger, not a derived type like the file logger.
                    Type t1 = loggers[0].GetType();
                    Type t2 = typeof(ConsoleLogger);
                    if (t1 == t2)
                    {
                        onlyLogCriticalEvents = true;
                    }
                }

                // HACK HACK: this enables task parameter logging.
                // This is a hack for now to make sure the perf hit only happens
                // on diagnostic. This should be changed to pipe it through properly,
                // perhaps as part of a fuller tracing feature.
                bool logTaskInputs = verbosity == LoggerVerbosity.Diagnostic;

                if (!logTaskInputs)
                {
                    foreach (var logger in loggers)
                    {
                        if (logger.Parameters != null &&
                            (logger.Parameters.IndexOf("V=DIAG", StringComparison.OrdinalIgnoreCase) != -1 ||
                             logger.Parameters.IndexOf("VERBOSITY=DIAG", StringComparison.OrdinalIgnoreCase) != -1)
                           )
                        {
                            logTaskInputs = true;
                            break;
                        }
                    }
                }

                if (!logTaskInputs)
                {
                    foreach (var logger in distributedLoggerRecords)
                    {
                        if (logger.CentralLogger != null)
                        {
                            if (logger.CentralLogger.Parameters != null &&
                                (logger.CentralLogger.Parameters.IndexOf("V=DIAG", StringComparison.OrdinalIgnoreCase) != -1 ||
                                 logger.CentralLogger.Parameters.IndexOf("VERBOSITY=DIAG", StringComparison.OrdinalIgnoreCase) != -1)
                               )
                            {
                                logTaskInputs = true;
                                break;
                            }
                        }
                    }
                }

                projectCollection = new ProjectCollection
                        (
                        globalProperties,
                        loggers,
                        null,
                        Microsoft.Build.Evaluation.ToolsetDefinitionLocations.ConfigurationFile | Microsoft.Build.Evaluation.ToolsetDefinitionLocations.Registry,
                        cpuCount,
                        onlyLogCriticalEvents
                        );

                if (debugger)
                {
                    // Debugging is not currently fully supported so we don't want to open
                    // public API for it. Also, we want to have a way to make it work when running inside VS.
                    // So use an environment variable. The undocumented /debug switch is just an easy way to set it.
                    Environment.SetEnvironmentVariable("MSBUILDDEBUGGING", "1");
                }

                if (toolsVersion != null && !projectCollection.ContainsToolset(toolsVersion))
                {
                    ThrowInvalidToolsVersionInitializationException(projectCollection.Toolsets, toolsVersion);
                }

                // If the user has requested that the schema be validated, do that here. 
                if (needToValidateProject && !FileUtilities.IsSolutionFilename(projectFile))
                {
                    Microsoft.Build.Evaluation.Project project = projectCollection.LoadProject(projectFile, globalProperties, toolsVersion);
                    Microsoft.Build.Evaluation.Toolset toolset = projectCollection.GetToolset((toolsVersion == null) ? project.ToolsVersion : toolsVersion);

                    if (toolset == null)
                    {
                        ThrowInvalidToolsVersionInitializationException(projectCollection.Toolsets, project.ToolsVersion);
                    }

                    ProjectSchemaValidationHandler.VerifyProjectSchema(projectFile, schemaFile, toolset.ToolsPath);

                    // If there are schema validation errors, an InitializationException is thrown, so if we get here,
                    // we can safely assume that the project successfully validated. 
                    projectCollection.UnloadProject(project);
                }

                if (preprocessWriter != null && !FileUtilities.IsSolutionFilename(projectFile))
                {
                    Project project = projectCollection.LoadProject(projectFile, globalProperties, toolsVersion);

                    project.SaveLogicalProject(preprocessWriter);

                    projectCollection.UnloadProject(project);
                    success = true;
                }
                else
                {
                    BuildRequestData request = new BuildRequestData(projectFile, globalProperties, toolsVersion, targets, null);

                    BuildParameters parameters = new BuildParameters(projectCollection);

                    // By default we log synchronously to the console for compatibility with previous versions,
                    // but it is slightly slower
                    if (!String.Equals(Environment.GetEnvironmentVariable("MSBUILDLOGASYNC"), "1", StringComparison.Ordinal))
                    {
                        parameters.UseSynchronousLogging = true;
                    }

                    parameters.EnableNodeReuse = enableNodeReuse;
                    parameters.NodeExeLocation = Assembly.GetExecutingAssembly().Location;
                    parameters.MaxNodeCount = cpuCount;
                    parameters.Loggers = projectCollection.Loggers;
                    parameters.ForwardingLoggers = remoteLoggerRecords;
                    parameters.ToolsetDefinitionLocations = Microsoft.Build.Evaluation.ToolsetDefinitionLocations.ConfigurationFile | Microsoft.Build.Evaluation.ToolsetDefinitionLocations.Registry;
                    parameters.DetailedSummary = detailedSummary;
                    parameters.LogTaskInputs = logTaskInputs;

                    if (!String.IsNullOrEmpty(toolsVersion))
                    {
                        parameters.DefaultToolsVersion = toolsVersion;
                    }

                    string memoryUseLimit = Environment.GetEnvironmentVariable("MSBUILDMEMORYUSELIMIT");
                    if (!String.IsNullOrEmpty(memoryUseLimit))
                    {
                        parameters.MemoryUseLimit = Convert.ToInt32(memoryUseLimit, CultureInfo.InvariantCulture);

                        // The following ensures that when we divide the use by node count to get the per-limit amount, we always end up with a 
                        // positive value - otherwise setting it too low will result in a zero, which will enable only the default cache behavior
                        // which is not what is intended by using this environment variable.
                        if (parameters.MemoryUseLimit < parameters.MaxNodeCount)
                        {
                            parameters.MemoryUseLimit = parameters.MaxNodeCount;
                        }
                    }

                    BuildManager buildManager = BuildManager.DefaultBuildManager;

#if MSBUILDENABLEVSPROFILING 
                    DataCollection.CommentMarkProfile(8800, "Pending Build Request from MSBuild.exe");
#endif
                    BuildResult results = null;
                    buildManager.BeginBuild(parameters);
                    Exception exception = null;
                    try
                    {
                        try
                        {
                            lock (s_buildLock)
                            {
                                s_activeBuild = buildManager.PendBuildRequest(request);

                                // Even if Ctrl-C was already hit, we still pend the build request and then cancel.
                                // That's so the build does not appear to have completed successfully.
                                if (s_receivedCancel == 1)
                                {
                                    buildManager.CancelAllSubmissions();
                                }
                            }

                            results = s_activeBuild.Execute();
                        }
                        finally
                        {
                            buildManager.EndBuild();
                        }
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                        success = false;
                    }

                    if (results != null && exception == null)
                    {
                        success = results.OverallResult == BuildResultCode.Success;
                        exception = results.Exception;
                    }

                    if (exception != null)
                    {
                        success = false;

                        // InvalidProjectFileExceptions have already been logged.
                        if (exception.GetType() != typeof(InvalidProjectFileException))
                        {
                            if
                                (
                                exception.GetType() == typeof(LoggerException) ||
                                exception.GetType() == typeof(InternalLoggerException)
                                )
                            {
                                // We will rethrow this so the outer exception handler can catch it, but we don't
                                // want to log the outer exception stack here.
                                throw exception;
                            }

                            if (exception.GetType() == typeof(BuildAbortedException))
                            {
                                // this is not a bug and should not dump stack. It will already have been logged
                                // appropriately, there is no need to take any further action with it.
                            }
                            else
                            {
                                // After throwing again below the stack will be reset. Make certain we log everything we 
                                // can now
                                Console.WriteLine(AssemblyResources.GetString("FatalError"));
#if DEBUG
                                Console.WriteLine("This is an unhandled exception in MSBuild -- PLEASE OPEN A BUG AGAINST THE MSBUILD TEAM.");
#endif
                                Console.WriteLine(exception.ToString());
                                Console.WriteLine();

                                throw exception;
                            }
                        }
                    }
                }
            }
            // handle project file errors
            catch (InvalidProjectFileException ex)
            {
                // just eat the exception because it has already been logged
                ErrorUtilities.VerifyThrow(ex.HasBeenLogged, "Should have been logged");
                success = false;
            }
            finally
            {
                FileUtilities.ClearCacheDirectory();
                if (projectCollection != null)
                {
                    projectCollection.Dispose();
                }

                BuildManager.DefaultBuildManager.Dispose();
            }

            return success;
        }
        public void AddToolset()
        {
            ProjectCollection collection = new ProjectCollection();
            collection.RemoveAllToolsets();

            Toolset toolset = new Toolset("x", "c:\\y", collection, null);
            collection.AddToolset(toolset);

            Assert.Equal(toolset, collection.GetToolset("x"));
            Assert.Equal(true, collection.ContainsToolset("x"));

            List<Toolset> toolsets = Helpers.MakeList(collection.Toolsets);
            Assert.Equal(1, toolsets.Count);
            Assert.Equal(toolset, toolsets[0]);
        }