web-dev-qa-db-ja.com

プログラムによるMSBuildの実行

プログラムで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"

次に、新しいProcessStartInfo(コマンド)を使用します。問題はFooと2011の間のスペースにあるようです。次の出力が表示されます。

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

プロジェクトファイルをMSBuildに渡すにはどうすればよいですか?

20
foo

Microsoft.Build 名前空間のクラス/インターフェースを経由して公式ルートに進むことを強くお勧めします。マイクロソフトはこれを至る所で使用しているので、これは何かに数えられるべきです...

特にクラス Microsoft.Build.Execution.BuildManager およびシングルトンMicrosoft.Build.Execution.BuildManager.DefaultBuildManagerは、ビルドタスクを実行するために必要なものです...ソースコードの例:

36
Yahia

パラメータを渡すには、ArgumentsProcessStartInfoプロパティを使用する必要があります。

例えば.

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の言及 として使用する必要があります。

7
Wilka

ここでは、単純なロガーを使用した完全な動作例を示します。

ソリューションを構築するには:

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

        string projectFileName = "C:\\Users...\\MySolution.sln";//<--- change here can be another VS type ex: .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 ..

そしてロガークラス(この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;
    }

また、正しいMSBuild Frameworkアセンブリ(つまり、「4.0」バージョンではない)を使用してください( here を参照)。

5
Malick