MSBuild BuildInParallel,自定义任务生成进程无法运行。

3
我正在使用MSBuild任务的BuildInParallel属性来同时运行构建项目。根项目正在构建四个子项目。子项目正在使用自定义的MSBuild任务,该任务使用System.Diagnostics.Process启动一个新进程。由于UseShellExecute为false时,生成的进程无法正确运行,但我不知道原因是什么,也无法找出错误在哪里——只有Process.ExitCode为1,没有异常。
以下是自定义的MSBuild任务:
using System;
using Microsoft.Build.Utilities;
using System.Diagnostics;

public class MSBuildProcessTask : Task
{
    public string Executable { get; set; }
    public string Arguments { get; set; }

    public override bool Execute()
    {
        using (var p = new Process())
        {
            try
            {
                p.StartInfo = new ProcessStartInfo(Executable, Arguments)
                                {
                                    UseShellExecute = false,
                                    //RedirectStandardOutput = true
                                };
                //p.OutputDataReceived += (o, e) =>
                //{
                //    if (e.Data != null)
                //    {
                //        Log.LogMessage(MessageImportance.Normal, e.Data);
                //    }
                //};
                p.Start();
                //p.BeginOutputReadLine();
                p.WaitForExit();
            }
            catch (Exception e)
            {
                throw; // for setting breakpoint
            }
            finally
            {
                if (p.ExitCode != 0)
                {
                    Log.LogError("Error.  Exit code: " + p.ExitCode);
                }
                p.Close();
            }
        }
        return true;
    }
}

这是根 MSBuild 项目文件(实际上我只在这里构建了两个子项目,但仍然出现错误..):

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="MSBuildProcessTask" AssemblyFile="C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\bin\Debug\MSBuildProcessTask.dll" />
    <Target Name="Default">
        <ItemGroup>
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.1.proj" />
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.2.proj" />
            <!--<ProjectFiles Include="$(MSBuildProjectDirectory)\Test.3.proj" />
            <ProjectFiles Include="$(MSBuildProjectDirectory)\Test.4.proj" />-->
        </ItemGroup>
            <MSBuild BuildInParallel="true" Projects="@(ProjectFiles)" />
    </Target>
</Project>

以下是子项目文件(Test.1.proj)的示例:
<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="MSBuildProcessTask" AssemblyFile="C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\bin\Debug\MSBuildProcessTask.dll" />
    <Target Name="Default">
        <Message Text="Hello" />
        <MSBuildProcessTask Executable="sqlcmd" Arguments="-S .\SQLEXPRESS -Q &quot;SELECT @@VERSION&quot;" />
    </Target>
</Project>

我的命令行是:C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /m /nr:false C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj

以下是示例输出:

C:\Users\Tom>C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe /m /nr:false C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildPr
ocessTask\Test.proj
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.235]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 16/08/2011 22:22:06.
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" on node 1 (default targets).
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (1) is building "C:\Users\Tom\Sandbox\reposito
       ry_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.1.proj" (2) on node 1 (default targets).
     2>Default:
         Hello
     1>Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (1) is building "C:\Users\Tom\Sandbox\reposito
       ry_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (3) on node 2 (default targets).



------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------

Microsoft SQL Server 2008 (SP1) - 10.0.2531.0 (X64)
        Mar 29 2009 10:11:52
        Copyright (c) 1988-2008 Microsoft Corporation
        Express Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)


(1 rows affected)
     3>Default:
         Hello
     2>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.1.proj" (default targets).
     3>C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj(6,3): error : Error.  Exit code: 1
     3>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (default targets).
     1>Done Building Project "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (default targets).

Build succeeded.

       "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.proj" (default target) (1) ->
       "C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj" (default target) (3) ->
       (Default target) ->
         C:\Users\Tom\Sandbox\repository_trunk\MSBuildProcessTask\MSBuildProcessTask\Test.2.proj(6,3): error : Error.  Exit code: 1

    0 Warning(s)
    1 Error(s)

Time Elapsed 00:00:00.23

C:\Users\Tom>

正如您所看到的,我们只从一个SQLCMD命令中获取输出。


任何事件日志中都没有任何内容。 - Tom Hunter
(1) 在句子 UseShellExecute = false, 的末尾有一个悬挂的逗号,对吧? (2) 当 UseShellExecute 被设置为 false 时,你可以尝试将 RedirectStandardOutput 设置为 true 吗? - Arun
2个回答

0

你尝试过给每个目标一个唯一的名称(不是“Default”)吗?

我认为当你包含一个项目时,msbuild会将所包含的项目的目标扩展到当前项目中。当你添加另一个与现有目标同名的目标时,现有目标将被覆盖。

你可以使用/preprocess开关查看扩展后的项目,如此处所述。


1
感谢您的建议,@Alex。不幸的是,使用不同的目标名称没有任何区别——问题仍然存在。请注意,我没有使用Import元素;我正在使用MSBuild任务来构建子项目。我不认为MSBuild任务具有您描述的行为。 - Tom Hunter

0

没有机会准确地说出问题的原因,你必须自己调查或至少提供更多关于错误的细节。

尝试运行MSBuild并指定诊断详细程度,它将在运行时输出非常详细的信息:

MsBuild.exe /v:diag

1
谢谢您的帮助,sllev。我已经花了大约两天的时间自己调查,但是我完全被卡住了。问题在于新进程似乎并不总是运行,并且没有产生任何错误消息(只有ExitCode 1)。/v:diag输出更多信息,但是我恐怕仍然没有错误消息或线索。 - Tom Hunter
@Tom:你尝试过调试吗?如果你能在MSBuildProcessTask的构造函数处设置断点,那就太好了。设置断点后,在VS菜单中选择“调试”->“异常”->“启用所有异常”,然后继续执行<kbd>F5</kbd>,这样如果有任何异常,你就会看到它。 - sll
我已经尝试过调试,但没有抛出任何异常。该进程仅以ExitCode 1结束(SQLCMD没有输出),有没有办法在调用Process.Start()时调试“引擎盖下”的情况? - Tom Hunter
那么它在 p.Start(); 这一行崩溃了? - sll
尝试使用Procmon工具,查看在执行此代码时是否有一些奇怪的文件系统或注册表等活动,它还会显示调试输出,也许那里记录了一些东西。 - sll
嗨@sllev,我尝试了Process Monitor跟踪。我可以看到创建了两个SQLCMD进程实例,但对于为什么一个生成的进程无法运行提供的查询,除了失败的进程捕获的事件较少之外,我没有发现任何明显的原因。您能否重现这个问题? - Tom Hunter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接