以编程方式运行 MSBuild

发布于 2024-12-02 18:35:27 字数 698 浏览 2 评论 0原文

我试图以编程方式执行 MSBuild,但无法执行以下命令:

string command = string.Format(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe  ""{0}\{1}.csproj""", _args.ProjectPath, _args.ProjectName);

字符串呈现为:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe  "C:\...\TestResults\Foo 2011-08-31 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj"

然后我使用 new ProcessStartInfo(command)。问题似乎是 Foo 和 2011 之间的空格。我得到以下输出:

MSBUILD : error MSB1008: Only one project can be specified.
Switch: 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj

How do I pass in the project file to MSBuild?

I am trying to execute MSBuild programmatically and can't execute the following command:

string command = string.Format(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe  ""{0}\{1}.csproj""", _args.ProjectPath, _args.ProjectName);

The string gets rendered as:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe  "C:\...\TestResults\Foo 2011-08-31 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj"

I then use new ProcessStartInfo(command). The problem seems to be the space between Foo and 2011. I get the following output:

MSBUILD : error MSB1008: Only one project can be specified.
Switch: 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj

How do I pass in the project file to MSBuild?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱殇璃 2024-12-09 18:35:27

我建议 stronlgy 通过 Microsoft 中的类/接口走官方路线.Build命名空间。微软到处都使用这个,所以这应该很重要......

特别是。类 Microsoft.Build.Execution.BuildManager 和 Singleton Microsoft.Build.Execution.BuildManager.DefaultBuildManager 是您运行构建任务所需的...源代码示例:

I would recommend stronlgy to go the official route via classes/interfaces in Microsoft.Build namespace. Microsoft uses this all over the place, so this should count for something...

Esp. the class Microsoft.Build.Execution.BuildManager and the Singleton Microsoft.Build.Execution.BuildManager.DefaultBuildManager is what you are after to run a build task... source code examples:

情话墙 2024-12-09 18:35:27

这是一个带有简单记录器的完整工作示例。

构建解决方案:

using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;

string projectFileName = "C:\\Users...\\MySolution.sln"; // <--- Change here can be another
                                                         //      Visual Studio type.
                                                         //      Example: .vcxproj

BasicLogger Logger = new BasicLogger();
var projectCollection = new ProjectCollection();
var buildParamters = new BuildParameters(projectCollection);
buildParamters.Loggers = new List<Microsoft.Build.Framework.ILogger>() { Logger };
var globalProperty = new Dictionary<String, String>();
globalProperty.Add("Configuration", "Debug"); //<--- change here
globalProperty.Add("Platform", "x64");//<--- change here
BuildManager.DefaultBuildManager.ResetCaches();
var buildRequest = new BuildRequestData(projectFileName, globalProperty, null, new String[] { "Build" }, null);
var buildResult = BuildManager.DefaultBuildManager.Build(buildParamters, buildRequest);
if (buildResult.OverallResult == BuildResultCode.Failure)
{
    // Catch result ...
}
MessageBox.Show(Logger.GetLogString());    // Display output ..

以及 logger 类(强烈源自此 MSDN 记录器):

public class BasicLogger : Logger
{
    MemoryStream streamMem = new MemoryStream();


    /// <summary>
    /// Initialize is guaranteed to be called by MSBuild at the start of the build
    /// before any events are raised.
    /// </summary>
    public override void Initialize(IEventSource eventSource)
    {
        try
        {
            // Open the file
            this.streamWriter = new StreamWriter(streamMem);
            //this.streamWriter = new StreamWriter(logFile);
        }
        catch (Exception ex)
        {
            if
            (
                ex is UnauthorizedAccessException
                || ex is ArgumentNullException
                || ex is PathTooLongException
                || ex is DirectoryNotFoundException
                || ex is NotSupportedException
                || ex is ArgumentException
                || ex is SecurityException
                || ex is IOException
            )
            {
                throw new LoggerException("Failed to create log file: " + ex.Message);
            }
            else
            {
                // Unexpected failure
                throw;
            }
        }

        // For brevity, we'll only register for certain event types. Loggers can also
        // register to handle TargetStarted/Finished and other events.
        eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
        eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
        eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
        eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
        eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
        eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
    }


    void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
    {
        // BuildErrorEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
        string line = String.Format(": ERROR {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
        WriteLineWithSenderAndMessage(line, e);
    }


    void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
    {
        // BuildWarningEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
        string line = String.Format(": Warning {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
        WriteLineWithSenderAndMessage(line, e);
    }


    void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
    {
        // BuildMessageEventArgs adds Importance to BuildEventArgs
        // Let's take account of the verbosity setting we've been passed in deciding whether to log the message
        if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
            || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
            || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
        )
        {
            WriteLineWithSenderAndMessage(String.Empty, e);
        }
    }


    void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
    {
        // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
        // To keep this log clean, this logger will ignore these events.
    }


    void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
    {
        // ProjectStartedEventArgs adds ProjectFile, TargetNames
        // Just the regular message string is good enough here, so just display that.
        WriteLine(String.Empty, e);
        indent++;
    }


    void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
    {
        // The regular message string is good enough here too.
        indent--;
        WriteLine(String.Empty, e);
    }


    /// <summary>
    /// Write a line to the log, adding the SenderName and Message
    /// (these parameters are on all MSBuild event argument objects)
    /// </summary>
    private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
    {
        if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
        {
            // Well, if the sender name is MSBuild, let's leave it out for prettiness
            WriteLine(line, e);
        }
        else
        {
            WriteLine(e.SenderName + ": " + line, e);
        }
    }


    /// <summary>
    /// Just write a line to the log
    /// </summary>
    private void WriteLine(string line, BuildEventArgs e)
    {
        for (int i = indent; i > 0; i--)
        {
            streamWriter.Write("\t");
        }
        streamWriter.WriteLine(line + e.Message);
    }


    public string GetLogString()
    {
        var sr = new StreamReader(streamMem);
        var myStr = sr.ReadToEnd();
        return myStr;
    }


    /// <summary>
    /// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all
    /// events have been raised.
    /// </summary>
    ///
    ///
    public override void Shutdown()
    {
        streamWriter.Flush();
        streamMem.Position = 0;
    }

    private StreamWriter streamWriter;
    private int indent;

}

还要确保使用正确的 MSBuild Framework 程序集(即不是“4.0”版本)(请参阅此处

Here a full working example with a simple logger.

To build a solution:

using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;

string projectFileName = "C:\\Users...\\MySolution.sln"; // <--- Change here can be another
                                                         //      Visual Studio type.
                                                         //      Example: .vcxproj

BasicLogger Logger = new BasicLogger();
var projectCollection = new ProjectCollection();
var buildParamters = new BuildParameters(projectCollection);
buildParamters.Loggers = new List<Microsoft.Build.Framework.ILogger>() { Logger };
var globalProperty = new Dictionary<String, String>();
globalProperty.Add("Configuration", "Debug"); //<--- change here
globalProperty.Add("Platform", "x64");//<--- change here
BuildManager.DefaultBuildManager.ResetCaches();
var buildRequest = new BuildRequestData(projectFileName, globalProperty, null, new String[] { "Build" }, null);
var buildResult = BuildManager.DefaultBuildManager.Build(buildParamters, buildRequest);
if (buildResult.OverallResult == BuildResultCode.Failure)
{
    // Catch result ...
}
MessageBox.Show(Logger.GetLogString());    // Display output ..

And the logger class (strongly derived of this MSDN logger):

public class BasicLogger : Logger
{
    MemoryStream streamMem = new MemoryStream();


    /// <summary>
    /// Initialize is guaranteed to be called by MSBuild at the start of the build
    /// before any events are raised.
    /// </summary>
    public override void Initialize(IEventSource eventSource)
    {
        try
        {
            // Open the file
            this.streamWriter = new StreamWriter(streamMem);
            //this.streamWriter = new StreamWriter(logFile);
        }
        catch (Exception ex)
        {
            if
            (
                ex is UnauthorizedAccessException
                || ex is ArgumentNullException
                || ex is PathTooLongException
                || ex is DirectoryNotFoundException
                || ex is NotSupportedException
                || ex is ArgumentException
                || ex is SecurityException
                || ex is IOException
            )
            {
                throw new LoggerException("Failed to create log file: " + ex.Message);
            }
            else
            {
                // Unexpected failure
                throw;
            }
        }

        // For brevity, we'll only register for certain event types. Loggers can also
        // register to handle TargetStarted/Finished and other events.
        eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted);
        eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted);
        eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised);
        eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
        eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
        eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished);
    }


    void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
    {
        // BuildErrorEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
        string line = String.Format(": ERROR {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
        WriteLineWithSenderAndMessage(line, e);
    }


    void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
    {
        // BuildWarningEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
        string line = String.Format(": Warning {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
        WriteLineWithSenderAndMessage(line, e);
    }


    void eventSource_MessageRaised(object sender, BuildMessageEventArgs e)
    {
        // BuildMessageEventArgs adds Importance to BuildEventArgs
        // Let's take account of the verbosity setting we've been passed in deciding whether to log the message
        if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal))
            || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal))
            || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed))
        )
        {
            WriteLineWithSenderAndMessage(String.Empty, e);
        }
    }


    void eventSource_TaskStarted(object sender, TaskStartedEventArgs e)
    {
        // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName
        // To keep this log clean, this logger will ignore these events.
    }


    void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e)
    {
        // ProjectStartedEventArgs adds ProjectFile, TargetNames
        // Just the regular message string is good enough here, so just display that.
        WriteLine(String.Empty, e);
        indent++;
    }


    void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e)
    {
        // The regular message string is good enough here too.
        indent--;
        WriteLine(String.Empty, e);
    }


    /// <summary>
    /// Write a line to the log, adding the SenderName and Message
    /// (these parameters are on all MSBuild event argument objects)
    /// </summary>
    private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
    {
        if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/))
        {
            // Well, if the sender name is MSBuild, let's leave it out for prettiness
            WriteLine(line, e);
        }
        else
        {
            WriteLine(e.SenderName + ": " + line, e);
        }
    }


    /// <summary>
    /// Just write a line to the log
    /// </summary>
    private void WriteLine(string line, BuildEventArgs e)
    {
        for (int i = indent; i > 0; i--)
        {
            streamWriter.Write("\t");
        }
        streamWriter.WriteLine(line + e.Message);
    }


    public string GetLogString()
    {
        var sr = new StreamReader(streamMem);
        var myStr = sr.ReadToEnd();
        return myStr;
    }


    /// <summary>
    /// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all
    /// events have been raised.
    /// </summary>
    ///
    ///
    public override void Shutdown()
    {
        streamWriter.Flush();
        streamMem.Position = 0;
    }

    private StreamWriter streamWriter;
    private int indent;

}

Also be sure to use the correct MSBuild Framework Assemblies (i.e not the "4.0" version) ( see here )

本宫微胖 2024-12-09 18:35:27

您需要使用ProcessStartInfoArguments 属性来传递参数。

例如

var p = new Process();
p.StartInfo = new ProcessStartInfo(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe")      
p.StartInfo.Arguments = string.Format(@"{0}\{1}.csproj", _args.ProjectPath, _args.ProjectName)

p.Start();

,但是,对于 MSBuild,您应该使用 Yahia 提到的 的官方方法。

You need to use the Arguments property of the ProcessStartInfo to pass parameters.

e.g.

var p = new Process();
p.StartInfo = new ProcessStartInfo(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe")      
p.StartInfo.Arguments = string.Format(@"{0}\{1}.csproj", _args.ProjectPath, _args.ProjectName)

p.Start();

However, for MSBuild specifically you should use the official method as Yahia mentions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文