【问题标题】:MSBuild ItemGroup Include/Exclude pattern issueMSBuild ItemGroup 包含/排除模式问题
【发布时间】:2010-10-08 13:36:32
【问题描述】:

问题:没有根据 exclude 属性中传递的值正确构建 ItemGroups 数组。

如果您运行此脚本,它会创建一些示例文件,然后尝试根据 Include/Exclude 属性创建一个名为 TheFiles 的数组,问题是当 Exclude 不是硬编码或非常简单的属性时,它会出错。

目标 DynamicExcludeList 错误地选择了这些文件:
.\AFolder\test.cs;.\AFolder\test.txt

目标 HardcodedExcludeList 正确选择了这些文件:
.\A文件夹\test.txt

非常感谢任何帮助,这让我发疯了。

(注意它的 msbuild v4)

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">

      <Target Name="Run" >
        <CallTarget Targets="CreateSampleFiles" />
        <CallTarget Targets="DynamicExcludeList" />
        <CallTarget Targets="HardcodedExcludeList" />
      </Target>

      <Target Name="CreateSampleFiles" >
        <MakeDir Directories="AFolder" />
        <WriteLinesToFile Lines="Test" File="AFolder\test.cs" Overwrite="true" />
        <WriteLinesToFile Lines="Test" File="AFolder\test.txt" Overwrite="true" />
      </Target>

      <Target Name="DynamicExcludeList" >

        <PropertyGroup>
          <CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs</CommonFileExclusion>
          <FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
        </PropertyGroup>

        <Message Text="FinalExcludes: $(FinalExcludes)" />
        <ItemGroup>
          <TheFiles 
            Include=".\AFolder\**\*;" 
            Exclude="$(FinalExcludes)"
          />
        </ItemGroup>
        <Message Text="TheFiles: @(TheFiles)" />

      </Target>

      <Target Name="HardcodedExcludeList" >

        <PropertyGroup>
          <FinalExcludes>.\AFolder\**\*.cs</FinalExcludes>
        </PropertyGroup>

        <Message Text="FinalExcludes: $(FinalExcludes)" />
        <ItemGroup>
          <TheFilesWithHardcodedExcludes
            Include=".\AFolder\**\*;"
            Exclude="$(FinalExcludes)"
          />
        </ItemGroup>
        <Message Text="TheFilesWithHardcodedExcludes: @(TheFilesWithHardcodedExcludes)" />

      </Target>  
    </Project>

这是输出,注意'TheFiles'和'TheFilesWithHardcodedExcludes'的区别

PS C:\SVN\TrunkDeployment\TestMsBuild> msbuild .\Test.build.xml Microsoft (R) Build Engine 版本 4.0.30319.1 [Microsoft .NET 框架,版本 4.0.30319.1] 版权所有 (C) Microsoft Corporation 2007。保留所有权利。 构建于 2010 年 8 月 10 日下午 2:30:42 开始。 节点 1 上的项目“C:\SVN\TrunkDeployment\TestMsBuild\Test.build.xml”(默认目标)。 动态排除列表: FinalExcludes: .\AFolder\**\*.cs 文件:.\AFolder\test.cs;.\AFolder\test.txt 硬编码排除列表: FinalExcludes: .\AFolder\**\*.cs TheFilesWithHardcodedExcludes: .\AFolder\test.txt 完成构建项目“C:\SVN\TrunkDeployment\TestMsBuild\Test.build.xml”(默认目标)。 构建成功。 0 个警告 0 错误 经过时间 00:00:00.06

编辑

我已更新上述脚本以使用 CreateItem,但是当要排除的项目列表包含多于 1 个路径时仍然存在问题(即 CommonFileExclusion 的值已更改):

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Run">

      <Target Name="Run" >
        <CallTarget Targets="CreateSampleFiles" />
        <CallTarget Targets="DynamicExcludeList" />
        <CallTarget Targets="HardcodedExcludeList" />
      </Target>

      <Target Name="CreateSampleFiles" >
        <MakeDir Directories="AFolder" />
        <WriteLinesToFile Lines="Test" File="AFolder\test.cs" Overwrite="true" />
        <WriteLinesToFile Lines="Test" File="AFolder\test.txt" Overwrite="true" />
        <WriteLinesToFile Lines="Test" File="AFolder\test.vb" Overwrite="true" />
      </Target>

      <Target Name="DynamicExcludeList" >

        <PropertyGroup>
          <CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs;.\DIRECTORY_NAME_TOKEN\**\*.vb;</CommonFileExclusion>
          <FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
        </PropertyGroup>

        <Message Text="FinalExcludes: $(FinalExcludes)" />
        <CreateItem Include=".\AFolder\**\*;"
                     Exclude="$(FinalExcludes)">
          <Output TaskParameter="Include" ItemName="TheFiles"/>
        </CreateItem>
        <Message Text="TheFiles: @(TheFiles)" />

      </Target>

      <Target Name="HardcodedExcludeList" >

        <PropertyGroup>
          <FinalExcludes>.\AFolder\**\*.cs;.\AFolder\**\*.vb</FinalExcludes>
        </PropertyGroup>

        <Message Text="FinalExcludes: $(FinalExcludes)" />
        <CreateItem Include=".\AFolder\**\*;"
                     Exclude="$(FinalExcludes)">
          <Output TaskParameter="Include" ItemName="TheFilesWithHardcodedExcludes"/>
        </CreateItem>
        <Message Text="TheFilesWithHardcodedExcludes: @(TheFilesWithHardcodedExcludes)" />

      </Target>
    </Project>

【问题讨论】:

    标签: msbuild itemgroup


    【解决方案1】:

    好的,我尝试了一点,我认为问题在于您使用的属性代表多个值的 SCALAR 值。我建议进行批处理和转换(参见http://scottlaw.knot.org/blog/?p=402http://msdn.microsoft.com/en-us/library/ms171476.aspx)。例如以下代码正在运行:

    <Target Name="DynamicExcludeList" >
      <ItemGroup>
        <ExtensionsExcluded Include="cs;vb" />
      </ItemGroup>
    
      <CreateItem Include=".\AFolder\**\*"
              Exclude="@(ExtensionsExcluded->'.\AFolder\**\*.%(identity)')">
        <Output TaskParameter="Include" ItemName="TheFiles"/>
      </CreateItem>
      <Message Text="TheFiles: @(TheFiles)" />
    </Target>
    

    【讨论】:

    • 感谢您的修复,它只是 MSBuild (IMO) 中令人讨厌的事情之一,因为您想要添加的排除越多,它就越复杂(例如,某些目录中的某些文件,但不是其他等),可能会寻找另一种解决方案。
    【解决方案2】:

    在目标DynamicExcludeList 中使用CreateItem 任务而不是ItemGroup 来动态生成您的项目:

    <Target Name="DynamicExcludeList" >
    
      <PropertyGroup>
        <CommonFileExclusion>.\DIRECTORY_NAME_TOKEN\**\*.cs</CommonFileExclusion>
        <FinalExcludes>$(CommonFileExclusion.Replace('DIRECTORY_NAME_TOKEN', 'AFolder'))</FinalExcludes>
      </PropertyGroup>
    
      <Message Text="FinalExcludes: $(FinalExcludes)" />
    
      <CreateItem Include=".\AFolder\**\*;"
                  Exclude="$(FinalExcludes)">
        <Output TaskParameter="Include" ItemName="TheFiles"/>
      </CreateItem>
    
      <Message Text="TheFiles: @(TheFiles)" />
    </Target>
    

    理论上ItemGroupCreateItem 是等价的,但是当必须使用CreateItem 时,我见过这样的情况(动态情况)。

    【讨论】:

    • 事实上,在解析脚本时,在运行每个目标之前,都会评估属性和项目组。这就是为什么您的项目组没有填充您的想法,而是使用您的 msbuild 脚本执行之前的内容。您可以在此处阅读更多相关信息:blogs.msdn.com/b/msbuild/archive/2006/01/03/508629.aspxsedodream.com/…。避免此问题的一个好方法是在目标之外使用 ItemGroup(对于静态项目)并在内部使用 createitem(对于动态项目)
    • 感谢您的解释。但是,如果您查看有关 CreateItem (msdn.microsoft.com/en-us/library/s2y3e43x.aspx) 的文档,您会发现此任务已被弃用,因此您可能认为目标内的 ItemGroup 将像 CreateItem 一样动态评估。
    • 感谢您的反馈,我仍然遇到问题(稍后发布),据此:stackoverflow.com/questions/937681/createitem-vs-itemgroup,CreateItem 在 3.5 中已过时
    • CreateItem 自 .NET 3.5 起已弃用,但您仍然可以使用它。它解决了你的问题
    • 它在我的初始示例中解决了这个问题,为了简单起见,我开始实施你的修复,但是一旦我添加更多路径到 CommonFileExclusion 的值时遇到了同样的问题,如果你仍然有任何想法都会很棒(我用上面的问题更新了我的帖子)。感谢您的帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 2011-11-27
    • 2010-09-09
    • 1970-01-01
    相关资源
    最近更新 更多