プログラムで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に渡すにはどうすればよいですか?
Microsoft.Build
名前空間のクラス/インターフェースを経由して公式ルートに進むことを強くお勧めします。マイクロソフトはこれを至る所で使用しているので、これは何かに数えられるべきです...
特にクラス Microsoft.Build.Execution.BuildManager
およびシングルトンMicrosoft.Build.Execution.BuildManager.DefaultBuildManager
は、ビルドタスクを実行するために必要なものです...ソースコードの例:
パラメータを渡すには、Arguments
のProcessStartInfo
プロパティを使用する必要があります。
例えば.
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の言及 として使用する必要があります。
ここでは、単純なロガーを使用した完全な動作例を示します。
ソリューションを構築するには:
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 を参照)。